MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
lbbndcnd.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 "lbbndcnd.h"
8
9#include <algorithm>
10#include <set>
11#include "COMM/mpioverride.h"
13#include "IO/context.h"
14#include "IO/infoout.h"
15#include "lbconstants.h"
16#include "lbgridboundarycell.h"
17#include "lblatticedescriptor.h"
18#include "lbsolver.h"
19#include "property.h"
20
21using namespace std;
22using namespace lbconstants;
23
24template <MInt nDim>
26 : m_noInternalCells(solver->grid().noInternalCells()),
27 m_solverId(solver->m_solverId),
28 PV(solver->PV),
29 m_noDistributions(solver->m_noDistributions),
30 m_methodId(solver->m_methodId),
31 m_Ma(solver->m_Ma),
32 m_referenceLength(solver->m_referenceLength),
33 m_domainLength(solver->m_domainLength),
34 m_densityFluctuations(solver->m_densityFluctuations),
35 m_pulsatileFrequency(solver->m_pulsatileFrequency) {
36 TRACE();
37
38 NEW_TIMER_GROUP(tgrp_BC, "Boundary Condition LB (solverId=" + std::to_string(m_solverId) + ")");
39 NEW_TIMER(t_BCAll, "complete BC setup", tgrp_BC);
40 m_t_BCAll = t_BCAll;
41 RECORD_TIMER_START(t_BCAll);
42
43 m_solver = solver;
44
45 m_log << endl;
46 m_log << "#########################################################################################################"
47 "#############"
48 << endl;
49 m_log << "## Boundary Conditions "
50 " ##"
51 << endl;
52 m_log << "#########################################################################################################"
53 "#############"
54 << endl
55 << endl;
56
57 // external forcing terms
58 m_Fext = solver->m_Fext;
59
60 m_gridCutTest = "SAT";
61 m_gridCutTest = Context::getSolverProperty<MString>("gridCutTest", m_solverId, AT_, &m_gridCutTest);
62
76 m_interpolationDistMethod = "perpOp";
77 m_interpolationDistMethod =
78 Context::getSolverProperty<MString>("interpolationDistMethod", m_solverId, AT_, &m_interpolationDistMethod);
79
87 m_outputWallDistanceField =
88 Context::getSolverProperty<MBool>("outputWallDistanceField", m_solverId, AT_, &m_outputWallDistanceField);
89
105 m_multiBCTreatment = "I-W-P";
106 m_multiBCTreatment = Context::getSolverProperty<MString>("multiBCTreatment", m_solverId, AT_, &m_multiBCTreatment);
107
118 m_lbNoMovingWalls = 0;
119 m_lbNoMovingWalls = Context::getSolverProperty<MInt>("lbNoMovingWalls", m_solverId, AT_, &m_lbNoMovingWalls);
120
121 if(m_lbNoMovingWalls > 0) {
122 mAlloc(m_segIdMovingWalls, m_lbNoMovingWalls, "m_segIdMovingWalls", 0, AT_);
123
134 for(MInt i = 0; i < m_lbNoMovingWalls; i++) {
135 m_segIdMovingWalls[i] = Context::getSolverProperty<MInt>("segIdMovingWalls", m_solverId, AT_, i);
136 }
137
138 mAlloc(m_lbWallVelocity, m_lbNoMovingWalls * nDim, "m_lbWallVelocity", F0, AT_);
139
150 for(MInt i = 0; i < m_lbNoMovingWalls; i++) {
151 for(MInt d = 0; d < nDim; d++) {
152 m_lbWallVelocity[i * nDim + d] =
153 Context::getSolverProperty<MFloat>("lbWallVelocity", m_solverId, AT_, (i * nDim + d));
154 m_lbWallVelocity[i * nDim + d] *= m_Ma * LBCS;
155 }
156 }
157 }
158
170 m_calcWallForces = false;
171 m_calcWallForces = Context::getSolverProperty<MBool>("calculateWallForces", m_solverId, AT_, &m_calcWallForces);
172
173 if(m_calcWallForces) {
184 m_calcWallForcesInterval = 1;
185 m_calcWallForcesInterval =
186 Context::getSolverProperty<MInt>("calculateWallForcesInterval", m_solverId, AT_, &m_calcWallForcesInterval);
187
198 m_forceFile = "forces.log";
199 m_forceFile = Context::getSolverProperty<MString>("forceFileName", m_solverId, AT_, &m_forceFile);
200 }
201
213 m_calcBcResidual = false;
214 m_calcBcResidual = Context::getSolverProperty<MBool>("calcBcResidual", m_solverId, AT_, &m_calcBcResidual);
215
226 m_lbNoHeatedWalls = 0;
227 m_lbNoHeatedWalls = Context::getSolverProperty<MInt>("lbNoHeatedWalls", m_solverId, AT_, &m_lbNoHeatedWalls);
228
229 if(m_lbNoHeatedWalls > 0) {
230 mAlloc(m_segIdHeatedWalls, m_lbNoHeatedWalls, "m_segIdHeatedWalls", 0, AT_);
231
242 for(MInt i = 0; i < m_lbNoHeatedWalls; i++) {
243 m_segIdHeatedWalls[i] = Context::getSolverProperty<MInt>("segIdHeatedWalls", m_solverId, AT_, i);
244 }
245
246 mAlloc(m_lbWallTemperature, m_lbNoHeatedWalls, "m_lbWallTemperature", F0, AT_);
247
258 for(MInt i = 0; i < m_lbNoHeatedWalls; i++) {
259 m_lbWallTemperature[i] = Context::getSolverProperty<MFloat>("lbWallTemperature", m_solverId, AT_, i);
260 }
261 }
262
263 // the number of segments that carry periodic conditions
264 m_noPeriodicSegments = 0;
265 m_periodicSegmentsIds = nullptr;
266 if(m_solver->m_geometry->geometryContext().propertyExists("periodicSegmentsIds", 0)) {
267 m_noPeriodicSegments = m_solver->m_geometry->geometryContext().getProperty("periodicSegmentsIds", 0)->count();
268 // the segment ids that carry periodic conditions
269 mAlloc(m_periodicSegmentsIds, m_noPeriodicSegments, "m_periodicSegmentsIds", 0, AT_);
270 // m_periodicSegmentsIds = new MInt[m_noPeriodicSegments];
271 for(MInt i = 0; i < m_noPeriodicSegments; i++)
272 m_periodicSegmentsIds[i] =
273 *m_solver->m_geometry->geometryContext().getProperty("periodicSegmentsIds", 0)->asInt(i);
274 }
275
276
277 if(m_solver->grid().isActive()) {
278 // This initializes the initial velocity vectors and the normal vectors for each boundary segment
279 initMembers();
280
281 createBoundaryCells();
282 sortBoundaryCells();
283
284 calculateVectors();
285 processAngles();
286 printBndVelInfo();
287 }
288
289 // for certain BCs it is important to have a neighbor communicator
290 if(m_solver->grid().isActive()) {
291 setBCNeighborCommunicator();
292 setBCWallNeighborCommunicator();
293 }
294
306 m_latentHeat = false;
307 m_latentHeat = Context::getSolverProperty<MBool>("latentHeat", m_solverId, AT_, &m_latentHeat);
308
309 if(m_latentHeat) {
324 m_calcSublayerDist = false;
325 m_calcSublayerDist = Context::getSolverProperty<MBool>("calcSublayerDist", m_solverId, AT_, &m_calcSublayerDist);
326 }
327
328 if(m_solver->isActive()) {
329 setBndCndHandler();
330 }
331
332 RECORD_TIMER_STOP(t_BCAll);
333
334 if(m_solver->m_geometry->m_debugParGeom) {
335 DISPLAY_ALL_GROUP_TIMERS(tgrp_BC);
336 m_log << endl;
337 }
338
339 m_log << endl;
340}
341
342
344
346template <MInt nDim>
348 TRACE();
349
350 if(m_numberOfCommBCs > 0) {
351 mDeallocate(m_allDomainsHaveBC);
352 mDeallocate(m_noBCNeighbors);
353 mDeallocate(m_totalNoBcCells);
354 mDeallocate(tmp_group);
355 mDeallocate(BCGroup);
356 mDeallocate(m_BCComm);
357 if(m_calcBcResidual) mDeallocate(m_BCResidualStream);
358 mDeallocate(m_BCOutputFileName);
359 if((MInt)(m_bndCndIds.size()) > 0) mDeallocate(m_mapBndCndIdSegId);
360 }
361
362 mDeallocate(m_inOutSegmentsIds);
363 mDeallocate(m_bndNormals);
364 mDeallocate(m_initialVelocityVecs);
365 mDeallocate(m_bndNormalDirection);
366 mDeallocate(m_exDirs);
367 mDeallocate(m_exWeights);
368 mDeallocate(m_phi);
369 mDeallocate(m_theta);
370
371 // Delete boundary condition handlers
372 bndCndHandlerVariables.clear();
373 bndCndHandlerRHS.clear();
374 bndCndInitiator.clear();
375
376 // Delete boundary cells
377 m_bndCells.clear();
378 m_boundaryCellsMb.clear();
379}
380
381template <MInt nDim>
383 TRACE();
384
385 NEW_SUB_TIMER(t_processAngles, "process angles", m_t_BCAll);
386 RECORD_TIMER_START(t_processAngles);
387
388
389 m_log << " + Processing angles..." << endl;
390
391 // -------------------------------------------------------------------------------
392 // Determine data for arbitrary outlet directions
393 // (polar angles & directions are derived from the normal vector of the outlet)
394 // -------------------------------------------------------------------------------
395
396 MFloat projection, angle1, angle2;
397 MFloat length;
398
399 MIntScratchSpace axesDirs(nDim, AT_, "axesDirs");
400 MFloat projections[3];
401
402 for(MInt id = 0; id < m_noInOutSegments; id++) {
403 MInt seg_id = -1;
404 for(MInt o = 0; o < (MInt)m_bndCndSegIds.size(); o++)
405 if(m_inOutSegmentsIds[id] == m_bndCndSegIds[o]) {
406 seg_id = o;
407 break;
408 }
409
410 if(seg_id < 0) continue;
411
412 if(m_bndNormals[id][0] > 0) {
413 m_phi[id] = atan(m_bndNormals[id][1] / m_bndNormals[id][0]);
414
415 axesDirs[0] = 0;
416
417 if(m_bndNormals[id][1] > 0)
418 axesDirs[1] = 2;
419 else
420 axesDirs[1] = 3;
421 } else {
422 axesDirs[0] = 1;
423
424 if(m_bndNormals[id][1] > 0) {
425 if(approx(m_bndNormals[id][0], 0.0, MFloatEps)) {
426 m_phi[id] = PI / 2;
427 } else {
428 m_phi[id] = PI + atan(m_bndNormals[id][1] / m_bndNormals[id][0]);
429 }
430
431 axesDirs[1] = 2;
432
433 } else {
434 if(approx(m_bndNormals[id][0], 0.0, MFloatEps)) {
435 m_phi[id] = -PI / 2;
436 } else {
437 m_phi[id] = -PI + atan(m_bndNormals[id][1] / m_bndNormals[id][0]);
438 }
439 axesDirs[1] = 3;
440 }
441 }
442
443 IF_CONSTEXPR(nDim == 3) {
444 m_theta[id] = asin(m_bndNormals[id][2]);
445
446 if(m_bndNormals[id][2] > 0)
447 axesDirs[2] = 4;
448 else
449 axesDirs[2] = 5;
450 }
451 else m_theta[id] = 0;
452
453 for(MInt i = 0; i < nDim; i++) {
454 projections[i] = 0.0;
455 for(MInt j = 0; j < nDim; j++)
456 projections[i] += (LbLatticeDescriptorBase<3>::idFld(axesDirs[i], j) - 1.0)
457 * m_bndNormals[id][j]; // TODO labels:LB dxqy: 3 replaceable by nDim ?
458 }
459
460 IF_CONSTEXPR(nDim == 3) {
461 m_log << " - InOutSegment " << id << ":" << endl;
462 m_log << " * segment id: " << m_bndCndSegIds[seg_id] << endl;
463 m_log << " * distributions along axes which point into the fluid: " << axesDirs[0] << " " << axesDirs[1]
464 << " " << axesDirs[0] << endl;
465 m_log << " * scalar product with bndNormal: " << projections[0] << " "
466 << projections[1] << " " << projections[2] << endl;
467 }
468 else {
469 m_log << " - InOutSegment " << id << ":" << endl;
470 m_log << " * angle phi: " << 180 * m_phi[id] / PI << endl;
471 m_log << " * distributions along axes which point into the fluid: " << axesDirs[0] << " " << axesDirs[1]
472 << endl;
473 m_log << " * scalar product with bndNormal: " << projections[0] << " "
474 << projections[1] << endl;
475 }
476
477
478 // -----------------------------------------------------------------------------------------------------------
479 // Determine directions and weights for extrapolation, i.e. go through all
480 // directions and take those two which have the highest projection on the inverse normal vector.
481 // The weights are calculated from the ratio of enclosed angles.
482 // -----------------------------------------------------------------------------------------------------------
483
484 angle1 = 0;
485 angle2 = 0;
486 m_exDirs[id][0] = -1;
487 m_exDirs[id][1] = -1;
488
489 // number of neighbors was raised to maximum to improve extrapolation
490 for(MInt i = 0; i < pow(3.0, nDim) - 1; i++) {
491 // for (MInt i=0; i < m_noDistributions - 1; i++){
492 projection = 0.0;
493 length = 0.0;
494 for(MInt j = 0; j < nDim; j++) {
495 projection += -1.0 * (LbLatticeDescriptorBase<3>::idFld(i, j) - 1.0)
496 * m_bndNormals[id][j]; // TODO labels:LB dxqy: 3 replaceable by nDim ?
497 length += (LbLatticeDescriptorBase<3>::idFld(i, j) - 1.0)
498 * (LbLatticeDescriptorBase<3>::idFld(i, j) - 1.0); // TODO labels:LB dxqy: 3 replaceable by nDim ?
499 }
500 length = sqrt(length);
501 projection = projection / length;
502
503 if(projection > angle1) {
504 if(angle1 > angle2) {
505 angle2 = angle1;
506 m_exDirs[id][1] = m_exDirs[id][0];
507 }
508 m_exDirs[id][0] = i;
509 angle1 = projection;
510 } else {
511 if(projection > angle2) {
512 m_exDirs[id][1] = i;
513 angle2 = projection;
514 }
515 }
516 }
517
518 angle1 = abs(acos(angle1));
519 angle2 = abs(acos(angle2));
520
521 m_exWeights[id][0] = angle2 / (angle1 + angle2);
522 m_exWeights[id][1] = angle1 / (angle1 + angle2);
523
524 m_log << " * extrapolation directions: " << m_exDirs[id][0] << " "
525 << m_exDirs[id][1] << endl;
526 m_log << " * angle enclosed with bndNormal: " << 180 * angle1 / PI << " "
527 << 180 * angle2 / PI << endl;
528 m_log << " * extrapolation weights: " << m_exWeights[id][0] << " "
529 << m_exWeights[id][1] << endl;
530
531 // Oha, there seems to be something wrong, no extrapolation neighbors found
532 if(m_exDirs[id][0] == -1 && m_exDirs[id][1] == -1) {
533 stringstream errorMsg;
534 errorMsg << "ERROR: no neighbors found for extrapolation for segment id " << m_inOutSegmentsIds[id] << endl;
535 m_log << errorMsg.str();
536 TERMM(1, errorMsg.str());
537 }
538 }
539
540 m_log << endl;
541
542 RECORD_TIMER_STOP(t_processAngles);
543}
544
550template <MInt nDim>
552 TRACE();
553
554 NEW_SUB_TIMER(t_printBndVelInfo, "print boundary velcoity info", m_t_BCAll);
555 RECORD_TIMER_START(t_printBndVelInfo);
556
557
558 m_log << " + We have the following inflow / outflow boundary information: " << endl;
559
560 for(MInt i = 0; i < (MInt)(m_bndCndIds.size()); i++) {
561 MInt mapId = m_mapSegIdsInOutCnd[i];
562 if(mapId != -1) {
563 m_log << " - information for segment " << m_bndCndSegIds[i] << endl;
564 m_log << " * BC: " << m_bndCndIds[i] << endl;
565 m_log << " * no cells: " << m_noBndCellsPerSegment[m_bndCndSegIds[i]] << endl;
566 m_log << " * normal id: " << m_mapSegIdsInOutCnd[i] << endl;
567 m_log << " * normal dir: " << m_bndNormalDirection[mapId] << " ("
568 << (m_bndNormalDirection[mapId] == -1 ? "outside" : "inside") << ")" << endl;
569 m_log << " * normal: ";
570 for(MInt j = 0; j < nDim; j++)
571 m_log << m_bndNormals[mapId][j] << " ";
572 m_log << endl;
573 m_log << " * init vel: ";
574 for(MInt j = 0; j < nDim; j++)
575 m_log << m_initialVelocityVecs[mapId][j] << " ";
576 m_log << endl;
577 m_log << " * ext dirs: " << m_exDirs[mapId][0] << " " << m_exDirs[mapId][1] << endl;
578 m_log << " * ext wght: " << m_exWeights[mapId][0] << " " << m_exWeights[mapId][1] << endl;
579 }
580 }
581
582 m_log << endl;
583
584 RECORD_TIMER_STOP(t_printBndVelInfo);
585}
586
593template <MInt nDim>
595 TRACE();
596
597 NEW_SUB_TIMER(t_initMembers, "init members", m_t_BCAll);
598 RECORD_TIMER_START(t_initMembers);
599
600 m_log << " + Initializing some members..." << endl;
601
602 // the number of all segments
603 m_noSegments = m_solver->m_geometry->geometryContext().getNoSegments();
604
605 if(m_solver->m_geometry->geometryContext().propertyExists("inOutSegmentsIds", 0)) {
606 // the number of segments that carry in-/outflow conditions
607 m_noInOutSegments = m_solver->m_geometry->geometryContext().getProperty("inOutSegmentsIds", 0)->count();
608
609 // the segment ids that carry in-/outflow conditions
610 mAlloc(m_inOutSegmentsIds, m_noInOutSegments, "m_inOutSegmentsIds", 0, AT_);
611 } else
612 m_noInOutSegments = 0;
613
614 // init the velocity vectors and the segment normals, the direction array and the array holding the ids of the
615 // in-/outflow conditions
616 if(m_noInOutSegments > 0) {
617 mAlloc(m_bndNormals, m_noInOutSegments, nDim, "m_bndNormals", F0, AT_);
618 mAlloc(m_initialVelocityVecs, m_noInOutSegments, nDim, "m_initialVelocityVecs", F0, AT_);
619 mAlloc(m_bndNormalDirection, m_noInOutSegments, "m_bndNormalDirection", -1, AT_);
620
621 mAlloc(m_exDirs, m_noInOutSegments, 2, "m_exDirs", 0, AT_);
622 mAlloc(m_exWeights, m_noInOutSegments, 2, "m_exWeights", F0, AT_);
623 mAlloc(m_phi, m_noInOutSegments, "m_phi", F0, AT_);
624 mAlloc(m_theta, m_noInOutSegments, "m_theta", F0, AT_);
625 }
626 for(MInt i = 0; i < m_noInOutSegments; i++) {
627 m_inOutSegmentsIds[i] = *m_solver->m_geometry->geometryContext().getProperty("inOutSegmentsIds", 0)->asInt(i);
628 }
629
642 m_bndNormalMethod = "calcNormal";
643 m_bndNormalMethod = Context::getSolverProperty<MString>("bndNormalMethod", m_solverId, AT_, &m_bndNormalMethod);
644
658 m_initVelocityMethod = "calcNormal";
659 m_initVelocityMethod =
660 Context::getSolverProperty<MString>("initVelocityMethod", m_solverId, AT_, &m_initVelocityMethod);
661
674 m_fastParallelGeomNormals = 0;
675 m_fastParallelGeomNormals =
676 Context::getSolverProperty<MInt>("fastParallelGeomNormals", m_solverId, AT_, &m_fastParallelGeomNormals);
677
678 m_log << endl;
679
680 RECORD_TIMER_STOP(t_initMembers);
681}
682
689template <MInt nDim>
691 TRACE();
692
693 // Vector calculation is only performed for in/out segments.
694 if(m_noInOutSegments < 1) return;
695
696 NEW_SUB_TIMER(t_calcVecs, "calculate vectors", m_t_BCAll);
697 g_tc_geometry.push_back(pair<MString, MInt>("calculate vectors", t_calcVecs));
698 RECORD_TIMER_START(t_calcVecs);
699
700 m_log << " + Calculating vectors..." << endl;
701
702 // read from file
703 if(m_bndNormalMethod == "read") {
704 m_log << " - reading normals in 3D (bndNormalMethod is set to '" << m_bndNormalMethod << "')" << endl;
705 for(MInt i = 0, k = 0; i < m_noInOutSegments; i++) {
706 MBool own = false;
707 for(MInt o = 0; o < (MInt)m_bndCndSegIds.size(); o++) {
708 if(m_inOutSegmentsIds[i] == m_bndCndSegIds[o]) { // m_inOutSegmentsIds is from geometry-file
709 own = true;
710 break;
711 }
712 }
713
714 for(MInt j = 0; j < nDim; j++) {
721 m_bndNormals[i][j] = Context::getSolverProperty<MFloat>("bndNormalVectors", m_solverId, AT_, k);
722
723 // normal vector points out of the body
724 m_bndNormalDirection[i] = -1;
725
726 k++;
727 }
728
729 if(own) {
730 m_log << " * segment " << m_inOutSegmentsIds[i] << " has normal: (" << m_bndNormals[i][0] << " "
731 << m_bndNormals[i][1];
732 IF_CONSTEXPR(nDim > 2)
733 m_log << " " << m_bndNormals[i][2] << ")" << endl;
734 else m_log << ")" << endl;
735 }
736 }
737 }
738 // Get the normals from the STL
739 else {
740 if(m_bndNormalMethod == "calcNormal")
742 else if(m_bndNormalMethod == "fromSTL")
743 retrieveNormal = &LbBndCnd::getNormalFromSTL;
744
745 calculateBndNormals();
746 }
747
748 // fill initial velocity vectors
749 for(MInt i = 0, k = 0; i < m_noInOutSegments; i++) {
750 for(MInt j = 0; j < nDim; j++) {
751 // read from file
752 if(m_initVelocityMethod == "read")
759 m_initialVelocityVecs[i][j] = Context::getSolverProperty<MFloat>("initialVelocityVectors", m_solverId, AT_, k);
760
761 // just use the segment normals
762 else if(m_initVelocityMethod == "calcNormal")
763 m_initialVelocityVecs[i][j] = m_bndNormals[i][j];
764
765 // use inverted segment normals
766 else if(m_initVelocityMethod == "fromSTL")
767 m_initialVelocityVecs[i][j] = -1 * m_bndNormals[i][j];
768
769 k++;
770 }
771
772 // Normalize velocity vectors
773 MFloat normalLength = 0.0;
774 for(MInt j = 0; j < nDim; j++) {
775 normalLength += m_initialVelocityVecs[i][j] * m_initialVelocityVecs[i][j];
776 }
777 normalLength = sqrt(normalLength);
778 for(MInt j = 0; j < nDim; j++) {
779 m_initialVelocityVecs[i][j] = m_initialVelocityVecs[i][j] / normalLength;
780 }
781 }
782
783 m_log << endl;
784
785 RECORD_TIMER_STOP(t_calcVecs);
786}
787
802template <MInt nDim>
804 TRACE();
805
806 std::array<MFloat, nDim> edge1;
807 std::array<MFloat, nDim> edge2;
808
809 // the edges
810 for(MInt d = 0; d < nDim; d++) {
811 edge1[d] = ge.m_vertices[1][d] - ge.m_vertices[0][d];
812 edge2[d] = ge.m_vertices[2][d] - ge.m_vertices[0][d];
813 }
814
815 MFloat normal_len = 0.0;
816 for(MInt d = 0; d < nDim; d++) {
817 MInt next = (d + 1) % nDim;
818 MInt nnext = (d + 2) % nDim;
819 normal[d] = edge1[next] * edge2[nnext] - edge1[nnext] * edge2[next];
820 normal_len += normal[d] * normal[d];
821 }
822
823 normal_len = sqrt(normal_len);
824
825 for(MInt d = 0; d < nDim; d++)
826 normal[d] /= normal_len;
827
828 if(approx(normal_len, 0.0, MFloatEps)) {
829 return false;
830 } else {
831 return true;
832 }
833}
834
850template <MInt nDim>
852 TRACE();
853
854 MFloat normal_len = 0.0;
855 for(MInt d = 0; d < nDim; d++) {
856 normal[d] = ge.m_normal[d];
857 normal_len += normal[d] * normal[d];
858 }
859
860 normal_len = sqrt(normal_len);
861
862 for(MInt d = 0; d < nDim; d++)
863 normal[d] /= normal_len;
864 if(approx(normal_len, 0.0, MFloatEps))
865 return false;
866 else
867 return true;
868}
869
881template <MInt nDim>
882void LbBndCnd<nDim>::calculateAveragedNormalAndCenter(MInt segmentId, MFloat* const normal, MFloat* const center) {
883 TRACE();
884
885 for(MInt d = 0; d < nDim; d++) {
886 normal[d] = 0.0;
887 center[d] = 0.0;
888 }
889
890 MInt offStart = 0;
891 MInt offEnd = 0;
892
893 if(m_solver->m_geometry->m_parallelGeometry) {
894 offStart = m_solver->m_geometry->m_segmentOffsets[segmentId];
895 offEnd = m_solver->m_geometry->m_segmentOffsets[segmentId + 1];
896 } else {
897 offStart = m_solver->m_geometry->m_segmentOffsetsWithoutMB[segmentId];
898 offEnd = m_solver->m_geometry->m_segmentOffsetsWithoutMB[segmentId + 1];
899 }
900 MInt count = 0;
901
902 for(MInt e = offStart; e < offEnd; e++) {
903 GeometryElement<nDim> triangle = m_solver->m_geometry->elements[e];
904 std::array<MFloat, nDim> normal_t;
905
906 // this retrieves the normal either from the STL or recalculates it from the triangle
907 MBool is_valid = (this->*retrieveNormal)(triangle, normal_t.data());
908
909 // make sure that this is a valid triangle, otherwise, skip
910 if(is_valid) {
911 std::array<MFloat, nDim> tmp;
912 for(MInt d = 0; d < nDim; d++)
913 tmp[d] = normal[d] + normal_t[d];
914
915 // this is the dangerous case in which we might go back directly onto the surface again
916 MBool flip = true;
917 for(MInt d = 0; d < nDim; d++)
918 flip = flip && approx(tmp[d], 0.0, MFloatEps);
919
920 if(flip)
921 for(MInt d = 0; d < nDim; d++)
922 normal_t[d] *= -1;
923
924 for(MInt d = 0; d < nDim; d++) {
925 normal[d] += normal_t[d];
926 for(MInt v = 0; v < nDim; v++)
927 center[d] += triangle.m_vertices[v][d];
928 }
929 count++;
930 }
931 }
932
933 // Oha, there seems to be something wrong with the geometry, no normal found!
934 if(count == 0) {
935 stringstream errorMsg;
936 errorMsg << "ERROR: no normal found for segment id " << segmentId << endl;
937 m_log << errorMsg.str();
938 TERMM(1, errorMsg.str());
939 }
940
941 // normalize
942 MFloat avg_normal_len = sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]);
943
944 for(MInt d = 0; d < nDim; d++) {
945 normal[d] /= avg_normal_len;
946 center[d] /= nDim * count;
947 }
948}
949
962template <MInt nDim>
963void LbBndCnd<nDim>::fastParallelGeomNormals3D(vector<pair<MInt, MInt>> own_segments) {
964 TRACE();
965
966 MIntScratchSpace numAllOwners(m_solver->noDomains(), AT_, "numAllOwners");
967 for(MInt d = 0; d < m_solver->noDomains(); d++)
968 numAllOwners[d] = 0;
969 numAllOwners[m_solver->domainId()] = own_segments.size();
970
971 MPI_Allreduce(MPI_IN_PLACE, numAllOwners.getPointer(), m_solver->noDomains(), MPI_INT, MPI_SUM, m_solver->mpiComm(),
972 AT_, "MPI_IN_PLACE", "numAllOwners.getPointer()");
973
974 MInt sumOwners = 0;
975 MInt myOffsetStart = 0;
976 for(MInt d = 0; d < m_solver->noDomains(); d++) {
977 if(d == m_solver->domainId()) myOffsetStart = sumOwners;
978 sumOwners += numAllOwners[d];
979 }
980
981 // calculate my local normal and the test point (used later) and print to log
982 MFloatScratchSpace test_pts(sumOwners * nDim, AT_, "test_pts");
983 MIntScratchSpace io(sumOwners * nDim, AT_, "io");
984 for(MInt i = 0; i < sumOwners * nDim; i++) {
985 test_pts[i] = 0.0;
986 io[i] = 0;
987 }
988
989 for(MInt s = 0; s < (MInt)own_segments.size(); s++) {
990 MInt pos = own_segments[s].first;
991 MInt segId = own_segments[s].second;
992 MInt posInTestPts = (myOffsetStart + s) * nDim;
993
994 std::array<MFloat, nDim> normal;
995 std::array<MFloat, nDim> center;
996 calculateAveragedNormalAndCenter(segId, normal.data(), center.data());
997
998 MFloat max_diag = (m_solver->c_cellLengthAtLevel(m_solver->grid().maxUniformRefinementLevel())) * SQRT3;
999
1000 for(MInt d = 0; d < nDim; d++) {
1001 test_pts[posInTestPts + d] = center[d] + normal[d] * max_diag;
1002 m_bndNormals[pos][d] = normal[d];
1003 }
1004
1005 m_log << " * local values for segment " << segId << endl;
1006 m_log << " = local normal: (" << normal[0] << " " << normal[1];
1007 if constexpr(nDim == 3) m_log << " " << normal[2];
1008 m_log << ")" << endl;
1009 m_log << " = local center: (" << center[0] << " " << center[1];
1010 if constexpr(nDim == 3) m_log << " " << center[2];
1011 m_log << ")" << endl;
1012 m_log << " = local test point: (" << test_pts[posInTestPts] << " " << test_pts[posInTestPts + 1] << " "
1013 << test_pts[posInTestPts + 2] << endl;
1014 }
1015
1016 MPI_Allreduce(MPI_IN_PLACE, test_pts.getPointer(), sumOwners * nDim, MPI_DOUBLE, MPI_SUM, m_solver->mpiComm(), AT_,
1017 "MPI_IN_PLACE", "test_pts.getPointer()");
1018
1019 // this runs bascially over all test points and checks for each domain if there exist intersections with the geometry
1020 for(MInt i = 0; i < sumOwners; i++) {
1021 MInt pos = i * nDim;
1022 vector<vector<MInt>> int_nodes;
1023 m_solver->m_geometry->determineRayIntersectedElements(&test_pts[pos], &int_nodes);
1024
1025 // now for each direction we need to know if the original ids are unique
1026 for(MInt d = 0; d < nDim; d++) {
1027 // this will contain the number of intersections per domain
1028 MIntScratchSpace doms_with_ints(m_solver->noDomains(), AT_, "doms_with_ints");
1029 for(MInt dom = 0; dom < m_solver->noDomains(); dom++)
1030 doms_with_ints[dom] = 0;
1031
1032 doms_with_ints[m_solver->domainId()] = int_nodes[d].size();
1033
1034 // after the following doms_with_ints contains for each process the number of intersection for direcetion d
1035 MPI_Allreduce(MPI_IN_PLACE, doms_with_ints.getPointer(), m_solver->noDomains(), MPI_INT, MPI_SUM,
1036 m_solver->mpiComm(), AT_, "MPI_IN_PLACE", "doms_with_ints.getPointer()");
1037
1038 MInt no_allCuts = 0;
1039 MInt myOff = 0;
1040 for(MInt dom = 0; dom < m_solver->noDomains(); dom++)
1041 no_allCuts += doms_with_ints[dom];
1042
1043 for(MInt dom = 0; dom < m_solver->domainId(); dom++)
1044 myOff += doms_with_ints[dom];
1045
1046 MIntScratchSpace origCmps(no_allCuts, AT_, "origCmps");
1047 for(MInt l = 0; l < no_allCuts; l++)
1048 origCmps[l] = 0;
1049
1050 for(MInt l = 0; l < (MInt)int_nodes[d].size(); l++)
1051 origCmps[myOff + l] = m_solver->m_geometry->elements[int_nodes[d][l]].m_originalId;
1052
1053 MPI_Allreduce(MPI_IN_PLACE, origCmps.getPointer(), no_allCuts, MPI_INT, MPI_SUM, m_solver->mpiComm(), AT_,
1054 "MPI_IN_PLACE", "origCmps.getPointer()");
1055
1056 set<MInt> uniques;
1057 for(MInt l = 0; l < no_allCuts; l++)
1058 uniques.insert(origCmps[l]);
1059
1060 io[i * nDim + d] = uniques.size();
1061 }
1062 }
1063
1064 // summarize the number of cuts to dermine the global inside/outside
1065 MPI_Allreduce(MPI_IN_PLACE, io.getPointer(), sumOwners * nDim, MPI_INT, MPI_SUM, m_solver->mpiComm(), AT_,
1066 "MPI_IN_PLACE", "io.getPointer()");
1067
1068 for(MInt s = 0; s < (MInt)own_segments.size(); s++) {
1069 MInt p = own_segments[s].first;
1070 MInt posInTestPts = (myOffsetStart + s) * nDim;
1071 MInt sum = 0;
1072
1073 for(MInt d = 0; d < nDim; d++)
1074 sum += io[posInTestPts + d];
1075
1076 MBool is_inside = sum % 2;
1077
1078 updateBndNormals(p, is_inside, m_bndNormals[p]);
1079 m_log << " * segment " << m_inOutSegmentsIds[p] << endl;
1080 m_log << " = normal: (" << m_bndNormals[p][0] << " " << m_bndNormals[p][1] << " " << m_bndNormals[p][2]
1081 << ")" << endl;
1082 }
1083}
1084
1096template <MInt nDim>
1097void LbBndCnd<nDim>::normalParallelGeomNormals3D(vector<pair<MInt, MInt>> own_segments) {
1098 TRACE();
1099
1100 MIntScratchSpace allDoOwn(m_noInOutSegments, AT_, "allDoOwn");
1101 MIntScratchSpace IDoOwn(m_noInOutSegments, AT_, "IDoOwn");
1102 MFloatScratchSpace test_pts(m_noInOutSegments, nDim, AT_, "test_pts");
1103
1104 for(MInt i = 0; i < m_noInOutSegments; i++)
1105 for(MInt d = 0; d < nDim; d++)
1106 test_pts(i, d) = 0.0;
1107
1108 for(MInt i = 0; i < m_noInOutSegments; i++)
1109 IDoOwn[i] = 0;
1110
1111 for(MInt s = 0; s < (MInt)own_segments.size(); s++)
1112 IDoOwn[own_segments[s].first] = 1;
1113
1114
1115 MPI_Allreduce(IDoOwn.getPointer(), allDoOwn.getPointer(), m_noInOutSegments, MPI_INT, MPI_SUM, m_solver->mpiComm(),
1116 AT_, "IDoOwn.getPointer()", "allDoOwn.getPointer()");
1117
1118 // calculate my local normal and the test point (used later) and print to log
1119 for(MInt s = 0; s < (MInt)own_segments.size(); s++) {
1120 MInt pos = own_segments[s].first;
1121 MInt segId = own_segments[s].second;
1122
1123 std::array<MFloat, nDim> normal;
1124 std::array<MFloat, nDim> center;
1125 calculateAveragedNormalAndCenter(segId, normal.data(), center.data());
1126
1127 MFloat max_diag = (m_solver->c_cellLengthAtLevel(m_solver->grid().maxUniformRefinementLevel())) * SQRT3;
1128
1129 for(MInt d = 0; d < nDim; d++) {
1130 test_pts(pos, d) = center[d] + normal[d] * max_diag;
1131 m_bndNormals[pos][d] = normal[d];
1132 }
1133
1134 m_log << " * local values for segment " << segId << endl;
1135 m_log << " = local normal: (" << normal[0] << " " << normal[1];
1136 if constexpr(nDim == 3) m_log << " " << normal[2];
1137 m_log << ")" << endl;
1138 m_log << " = local center: (" << center[0] << " " << center[1];
1139 if constexpr(nDim == 3) m_log << " " << center[2];
1140 m_log << ")" << endl;
1141 m_log << " = local test point: (" << test_pts(pos, 0) << " " << test_pts(pos, 1) << " " << test_pts(pos, 2)
1142 << endl;
1143 }
1144
1145 // this is now for all the others
1146
1147 // count the number of non-single entries in allDoOwn
1148 // also store the roots of segment ids for domains that own the segment completely
1149 MIntScratchSpace owner_roots(m_solver->noDomains(), AT_, "owner_roots");
1150 MInt numComm = 0;
1151 vector<MInt> posToComm;
1152 for(MInt i = 0; i < m_noInOutSegments; i++) {
1153 if(allDoOwn[i] == 1 && IDoOwn[i] == 1)
1154 owner_roots[m_solver->domainId()] = i;
1155 else
1156 owner_roots[m_solver->domainId()] = -1;
1157
1158 if(allDoOwn[i] > 1) {
1159 posToComm.push_back(i);
1160 numComm++;
1161 }
1162 }
1163
1164 // create the communicators
1165 vector<MPI_Comm> comms;
1166 for(MInt i = 0; i < numComm; i++) {
1167 MInt pos = posToComm[i];
1168
1169 // place holders for all owners
1170 MInt sumowners = 0;
1171 MInt firstOwner = -1;
1172 MIntScratchSpace owners(m_solver->noDomains(), AT_, "owners");
1173 MPI_Comm tmpComm;
1174
1175 // first determine all owners
1176 m_solver->m_geometry->determineSegmentOwnership(m_inOutSegmentsIds[pos], &IDoOwn[pos], &sumowners, &firstOwner,
1177 owners.getPointer());
1178
1179 if(m_solver->domainId() == firstOwner) owner_roots[m_solver->domainId()] = pos;
1180 m_log << " * creating MPI communicators for segment " << m_inOutSegmentsIds[pos] << endl;
1181 m_log << " = sum of owners: " << sumowners << endl;
1182 m_log << " = root of communication: " << firstOwner << endl;
1183 m_log << " = owners: ";
1184 for(MInt d = 0; d < m_solver->noDomains(); d++)
1185 if(owners[d] > 0) m_log << d << " ";
1186 m_log << endl;
1187
1188 // build communicator for the subgroup
1189 m_solver->createMPIComm(owners.getPointer(), sumowners, &tmpComm);
1190 comms.push_back(tmpComm);
1191 }
1192 MPI_Allreduce(MPI_IN_PLACE, owner_roots.getPointer(), m_solver->noDomains(), MPI_INT, MPI_SUM, m_solver->mpiComm(),
1193 AT_, "MPI_IN_PLACE", "owner_roots.getPointer()");
1194
1195 // do the exchange
1196 for(MInt i = 0; i < numComm; i++) {
1197 MInt p = posToComm[i];
1198 // I am an owner, I need to participate in the communication
1199 if(IDoOwn[p]) {
1200 // sum the normals and test points and average
1201 MFloatScratchSpace testenv(2 * nDim, AT_, "testenv");
1202 MInt j = 0;
1203 for(MInt d = 0; d < nDim; d++, j++)
1204 testenv[j] = m_bndNormals[p][d];
1205 for(MInt d = 0; d < nDim; d++, j++)
1206 testenv[j] = test_pts(p, d);
1207
1208 MPI_Allreduce(MPI_IN_PLACE, testenv.getPointer(), 2 * nDim, MPI_DOUBLE, MPI_SUM, comms[i], AT_, "MPI_IN_PLACE",
1209 "testenv.getPointer()");
1210
1211 MInt size;
1212 MPI_Comm_size(comms[i], &size);
1213
1214 // average over the number of domains
1215 for(MInt d = 0; d < 2 * nDim; d++)
1216 testenv[d] /= size;
1217
1218 // now testenv contains the averaged normal and the averaged test point
1219 // copy back to original position
1220 j = 0;
1221 for(MInt d = 0; d < nDim; d++, j++)
1222 m_bndNormals[i][d] = testenv[j];
1223 for(MInt d = 0; d < nDim; d++, j++)
1224 test_pts(p, d) = testenv[j];
1225 }
1226 }
1227
1228 // at this position all domains owning (a piece) of a segment have their normal and test point available
1229
1230 // now test all the test points
1231 // allocate space on all domains for the testing points
1232 MFloatScratchSpace rec_test_pts(nDim * m_noInOutSegments, AT_, "rec_test_pts");
1233 for(MInt i = 0; i < nDim * m_noInOutSegments; i++)
1234 rec_test_pts[i] = 0.0;
1235
1236 for(MInt d = 0; d < m_solver->noDomains(); d++) {
1237 MInt segInOut = owner_roots[m_solver->domainId()];
1238 if(segInOut >= 0) {
1239 MInt p = segInOut * nDim;
1240 for(MInt k = 0; k < nDim; k++)
1241 rec_test_pts[p + k] = test_pts(segInOut, k);
1242 }
1243 }
1244
1245 MPI_Allreduce(MPI_IN_PLACE, rec_test_pts.getPointer(), nDim * m_noInOutSegments, MPI_DOUBLE, MPI_SUM,
1246 m_solver->mpiComm(), AT_, "MPI_IN_PLACE", "rec_test_pts.getPointer()");
1247
1248 // now perform inside/outside determination
1249 MIntScratchSpace num_cuts(m_noInOutSegments * nDim, AT_, "num_cuts");
1250
1251 for(MInt i = 0; i < m_noInOutSegments; i++) {
1252 MInt pos = i * nDim;
1253 m_solver->m_geometry->pointIsInside2(&rec_test_pts[pos], &num_cuts[pos]);
1254 }
1255
1256 // summarize the number of cuts to dermine the global inside/outside
1257 MPI_Allreduce(MPI_IN_PLACE, num_cuts.getPointer(), nDim * m_noInOutSegments, MPI_INT, MPI_SUM, m_solver->mpiComm(),
1258 AT_, "MPI_IN_PLACE", "num_cuts.getPointer()");
1259
1260 for(MInt s = 0; s < (MInt)own_segments.size(); s++) {
1261 MInt p = own_segments[s].first;
1262 MInt pos = p * nDim;
1263 MInt sum = 0;
1264
1265 for(MInt d = 0; d < nDim; d++)
1266 sum += num_cuts[pos + d];
1267
1268 MBool is_inside = sum % 2;
1269
1270 updateBndNormals(p, is_inside, m_bndNormals[p]);
1271 m_log << " * segment " << m_inOutSegmentsIds[p] << endl;
1272 m_log << " = normal: (" << m_bndNormals[p][0] << " " << m_bndNormals[p][1] << " " << m_bndNormals[p][2]
1273 << ")" << endl;
1274 }
1275}
1276
1277
1278template <MInt nDim>
1280 TRACE();
1281 // TODO labels:LB dxqy: enable also for 2D
1282 std::stringstream ss;
1283 ss << "Calculate boundary normal not implemented for " << nDim << "D, yet !";
1284 TERMM(1, ss.str());
1285}
1286
1304template <>
1306 constexpr MInt nDim = 3;
1307 TRACE();
1308
1309 m_log << " - calculating normals in 3D (bndNormalMethod is set to " << m_bndNormalMethod << ")" << endl;
1310
1311 // 1. find out what segments we own and print to log
1312 vector<pair<MInt, MInt>> own_segments;
1313 for(MInt i = 0; i < m_noInOutSegments; i++) {
1314 for(MInt o = 0; o < (MInt)m_bndCndSegIds.size(); o++)
1315 if(m_inOutSegmentsIds[i] == m_bndCndSegIds[o]) {
1316 own_segments.push_back(pair<MInt, MInt>(i, m_inOutSegmentsIds[i]));
1317 break;
1318 }
1319
1320 // initialize all by (0,0,0)
1321 for(MInt d = 0; d < nDim; d++)
1322 m_bndNormals[i][d] = 0.0;
1323 }
1324
1325 if(m_solver->m_geometry->m_parallelGeometry) {
1326 if(m_fastParallelGeomNormals)
1327 fastParallelGeomNormals3D(own_segments);
1328 else
1329 normalParallelGeomNormals3D(own_segments);
1330 } else {
1331 for(MInt s = 0; s < (MInt)own_segments.size(); s++) {
1332 MInt pos = own_segments[s].first;
1333 MInt segId = own_segments[s].second;
1334 std::array<MFloat, nDim> normal;
1335 std::array<MFloat, nDim> center;
1336 calculateAveragedNormalAndCenter(segId, normal.data(), center.data());
1337
1338 MFloat max_diag = (m_solver->c_cellLengthAtLevel(m_solver->grid().maxUniformRefinementLevel())) * SQRT3;
1339 std::array<MFloat, nDim> test_pt;
1340
1341 for(MInt d = 0; d < nDim; d++)
1342 test_pt[d] = center[d] + normal[d] * max_diag;
1343
1344 updateBndNormals(pos, !m_solver->m_geometry->pointIsInside2(test_pt.data()), normal.data());
1345 m_log << " * segment " << segId << endl;
1346 m_log << " = normal: (" << m_bndNormals[pos][0] << " " << m_bndNormals[pos][1] << " "
1347 << m_bndNormals[pos][2] << ")" << endl;
1348 m_log << " = center: (" << center[0] << " " << center[1] << " " << center[2] << ")" << endl;
1349 }
1350 }
1351}
1352
1363template <MInt nDim>
1364void LbBndCnd<nDim>::updateBndNormals(MInt segId, MBool is_inside, MFloat* avg_normal) {
1365 // init the right direction, they should always point outside
1366 m_bndNormalDirection[segId] = -1;
1367
1368 // outside
1369 if(!is_inside) {
1370 for(MInt d = 0; d < nDim; d++)
1371 m_bndNormals[segId][d] = avg_normal[d];
1372 }
1373 // inside
1374 else {
1375 for(MInt d = 0; d < nDim; d++)
1376 m_bndNormals[segId][d] = -1.0 * avg_normal[d];
1377 }
1378}
1379
1387template <MInt nDim>
1389 TRACE();
1390
1391 MInt ind = -1;
1392 for(MInt i = 0; i < m_noInOutSegments; i++)
1393 if(m_bndCells[m_bndCndOffsets[index]].m_segmentId[0] == m_inOutSegmentsIds[i]) ind = i;
1394
1395 return ind;
1396}
1397
1403template <MInt nDim>
1405 TRACE();
1406 m_bndCndData[index]; // creates default entry of bndCndData
1407 LbBndCndData& p = m_bndCndData[index];
1408 p.noVars = noVars;
1409 p.noBndCells = 0;
1410 for(MInt i = m_bndCndOffsets[index]; i < m_bndCndOffsets[index + 1]; i++) {
1411 if(!m_solver->a_isHalo(m_bndCells[i].m_cellId)) {
1412 p.noBndCells++;
1413 }
1414 }
1415 p.noBndCellsWithHalos = m_bndCndOffsets[index + 1] - m_bndCndOffsets[index];
1416 const MInt noEntries = p.noBndCellsWithHalos * p.noVars;
1417 mAlloc(p.data, noEntries, "m_bndCndData[" + std::to_string(index) + "].data", F0, AT_);
1418 m_segIdUseBcData[m_bndCndSegIds[index]] = 1;
1419}
1420
1427template <MInt nDim>
1429 TRACE();
1430 using namespace maia::parallel_io;
1431 // Here it is looped over all global segment ids. Since most values are only
1432 // set for local segment ids a mapping is performed. In case of local missing
1433 // segment the number of cells per segment is zeroed.
1434 for(MInt i = 0; i < m_noSegments; i++) {
1435 if(m_segIdUseBcData[i]) {
1436 const MInt localSegIndex = m_mapBndCndSegId2Index[i];
1437 if(localSegIndex != -1) {
1438 // local domain hold this segment
1439 LbBndCndData& p = m_bndCndData[localSegIndex];
1440 const ParallelIo::size_type noEntries = p.noBndCells * p.noVars;
1441 ParallelIo::size_type noEntriesGlobal;
1442 ParallelIo::calcOffset(noEntries, &p.globalOffset, &noEntriesGlobal, m_solver->mpiComm());
1443 if(noEntriesGlobal > 0) {
1444 const MString name = "bcData_segment" + to_string(i);
1445 parallelIo.defineArray(PIO_FLOAT, name, noEntriesGlobal);
1446 parallelIo.setAttribute(name, "name", name);
1447 }
1448 } else {
1449 // local domain does NOT hold this segment
1450 const ParallelIo::size_type noEntries = 0;
1451 ParallelIo::size_type noEntriesGlobal, offset;
1452 ParallelIo::calcOffset(noEntries, &offset, &noEntriesGlobal, m_solver->mpiComm());
1453 if(noEntriesGlobal > 0) {
1454 const MString name = "bcData_segment" + to_string(i);
1455 parallelIo.defineArray(PIO_FLOAT, name, noEntriesGlobal);
1456 parallelIo.setAttribute(name, "name", name);
1457 }
1458 }
1459 }
1460 }
1461}
1462
1469template <MInt nDim>
1471 TRACE();
1472 using namespace maia::parallel_io;
1473 for(MInt i = 0; i < m_noSegments; i++) {
1474 if(m_segIdUseBcData[i]) {
1475 const MInt localSegIndex = m_mapBndCndSegId2Index[i];
1476 const MString name = "bcData_segment" + to_string(i);
1477 if(localSegIndex != -1) {
1478 // local domain hold this segment
1479 LbBndCndData& p = m_bndCndData[localSegIndex];
1480 const MInt noEntries = p.noBndCells * p.noVars;
1481 // create tmp array only containing non-halo data that are written to target file
1482 MFloatScratchSpace tmp(max(noEntries, 1), AT_, "tmp");
1483 MInt l = 0;
1484 const MInt offset = m_bndCndOffsets[localSegIndex];
1485 for(MInt j = 0; j < p.noBndCellsWithHalos; j++) {
1486 if(!m_solver->a_isHalo(m_bndCells[j + offset].m_cellId)) {
1487 for(MInt k = 0; k < p.noVars; k++) {
1488 tmp[l * p.noVars + k] = p.data[j * p.noVars + k];
1489 }
1490 l++;
1491 }
1492 }
1493 parallelIo.setOffset(noEntries, p.globalOffset);
1494 parallelIo.writeArray(&tmp[0], name);
1495 } else {
1496 // local domain does NOT hold this segment -> write no data
1497 const MFloat* dummyData = nullptr;
1498 parallelIo.setOffset(0, 0);
1499 parallelIo.writeArray(&dummyData[0], name);
1500 }
1501 }
1502 }
1503}
1504
1510template <MInt nDim>
1512 TRACE();
1513 using namespace maia::parallel_io;
1514 for(MInt i = 0; i < m_noSegments; i++) {
1515 if(m_segIdUseBcData[i]) {
1516 const MInt localSegIndex = m_mapBndCndSegId2Index[i];
1517 if(localSegIndex != -1) {
1518 // local domain hold this segment
1519 LbBndCndData& p = m_bndCndData[localSegIndex];
1520 const MInt noEntries = p.noBndCells * p.noVars;
1521 ParallelIo::size_type noEntriesGlobal;
1522 ParallelIo::calcOffset(noEntries, &p.globalOffset, &noEntriesGlobal, m_solver->mpiComm());
1523 const MString name = "bcData_segment" + to_string(i);
1524 // create tmp array only containing non-halo data that are written to target file
1525 MFloatScratchSpace tmp(max(noEntries, 1), AT_, "tmp");
1526 parallelIo.setOffset(noEntries, p.globalOffset);
1527 parallelIo.readArray(&tmp[0], name);
1528 // fill tmp array into data (which also contains halo data)
1529 MInt l = 0;
1530 const MInt offset = m_bndCndOffsets[localSegIndex];
1531 for(MInt j = 0; j < p.noBndCellsWithHalos; j++) {
1532 if(!m_solver->a_isHalo(m_bndCells[j + offset].m_cellId)) {
1533 for(MInt k = 0; k < p.noVars; k++) {
1534 p.data[j * p.noVars + k] = tmp[l * p.noVars + k];
1535 }
1536 l++;
1537 }
1538 }
1539 } else {
1540 // local domain does NOT hold this segment -> only participate in offset calculation
1541 const ParallelIo::size_type noEntries = 0;
1542 ParallelIo::size_type noEntriesGlobal, offset;
1543 ParallelIo::calcOffset(noEntries, &offset, &noEntriesGlobal, m_solver->mpiComm());
1544 const MString name = "bcData_segment" + to_string(i);
1545 MFloat* dummyData = nullptr;
1546 parallelIo.setOffset(noEntries, offset);
1547 parallelIo.readArray(&dummyData[0], name);
1548 }
1549 }
1550 }
1551}
1552
1563template <MInt nDim>
1565 TRACE();
1566
1567 if(m_initVelocityMethod != "read" && m_initVelocityMethod != "fromSTL") {
1568 MInt ind = m_mapSegIdsInOutCnd[index];
1569
1570 // wrong direction, mutiplicate with -1
1571 if(m_bndNormalDirection[ind] == -1)
1572 for(MInt i = 0; i < nDim; i++)
1573 m_initialVelocityVecs[ind][i] *= -1.0;
1574 }
1575}
1576
1587template <MInt nDim>
1589 TRACE();
1590
1591 if(m_initVelocityMethod != "read" && m_initVelocityMethod != "fromSTL") {
1592 MInt ind = m_mapSegIdsInOutCnd[index];
1593
1594 // wrong direction, mutiplicate with -1
1595 if(m_bndNormalDirection[ind] == 1)
1596 for(MInt i = 0; i < nDim; i++)
1597 m_initialVelocityVecs[ind][i] *= -1.0;
1598 }
1599}
1600
1613template <MInt nDim>
1615 TRACE();
1616 MInt currentId;
1617 MFloat minmax[2] = {10000000.0, -10000000.0};
1618
1619 MInt x_pos = m_solver->m_referenceLength * m_solver->m_blasiusPos;
1620 MFloat z_pos = 0.0;
1621
1622 set<MFloat> etas;
1623 MFloat eta;
1624
1625 MFloat etamax;
1626 MFloat fppwall = 0.332051914927913096446;
1627
1628 // This is fine enough!
1629 MFloat deta = 0.001;
1630 MInt steps;
1631
1632 // Find min and max Z
1633 for(MInt i = m_bndCndOffsets[index], j = 0; i < m_bndCndOffsets[index + 1]; i++, j++) {
1634 if(m_solver->c_noChildren(m_bndCells[i].m_cellId) > 0) continue;
1635 if(m_solver->a_coordinate(m_bndCells[i].m_cellId, nDim - 1) < minmax[0])
1636 minmax[0] = m_solver->a_coordinate(m_bndCells[i].m_cellId, nDim - 1);
1637 if(m_solver->a_coordinate(m_bndCells[i].m_cellId, nDim - 1) > minmax[1])
1638 minmax[1] = m_solver->a_coordinate(m_bndCells[i].m_cellId, nDim - 1);
1639 }
1640
1641 // Find all etas and store in m_eta
1642 for(MInt i = m_bndCndOffsets[index]; i < m_bndCndOffsets[index + 1]; i++) {
1643 currentId = m_bndCells[i].m_cellId;
1644 if(m_solver->c_noChildren(currentId) > 0) {
1645 m_bndCells[i].m_eta = 0.0;
1646 continue;
1647 }
1648 z_pos = ((m_solver->a_coordinate(currentId, nDim - 1)) - minmax[0]
1649 + ((m_solver->c_cellLengthAtLevel(m_solver->maxLevel())) / 2.0))
1650 / (m_solver->c_cellLengthAtLevel(m_solver->maxLevel()));
1651 eta = z_pos * sqrt((m_Ma * LBCS) / (x_pos * m_solver->m_nu));
1652 etas.insert(eta);
1653
1654 m_bndCells[i].m_eta = eta;
1655 }
1656
1657 // Sort entries
1658 list<MFloat> etas_sorted;
1659 for(set<MFloat>::iterator i = etas.begin(); i != etas.end(); i++)
1660 etas_sorted.push_back(*i);
1661
1662 etas_sorted.sort();
1663
1664 list<MFloat>::iterator it1 = etas_sorted.end();
1665 it1--;
1666 list<MFloat>::iterator it2 = etas_sorted.begin();
1667 it2++;
1668
1669
1670 // Calculate Blasius solution
1671 etamax = *(it1);
1672 it1 = etas_sorted.begin();
1673
1674 steps = etamax / deta;
1675
1676 // This is accurate enough
1677 m_blasius_delta = deta;
1678
1679 mAlloc(m_blasius, steps + 1, 5, "m_blasius", F0, AT_);
1680 m_blasius[0][3] = fppwall;
1681
1682 // Lets use the shooting method for getting the Blasius solution
1683 for(MInt i = 0; i < steps; i++) {
1684 m_blasius[i + 1][0] = m_blasius[i][0] + deta;
1685 m_blasius[i + 1][1] = m_blasius[i][1] + m_blasius[i][2] * deta;
1686 m_blasius[i + 1][2] = m_blasius[i][2] + m_blasius[i][3] * deta;
1687 m_blasius[i + 1][3] = m_blasius[i][3] + (-0.5 * m_blasius[i][1] * m_blasius[i][3]) * deta;
1688 }
1689}
1690
1701template <MInt nDim>
1703 TRACE();
1704
1705 // TODO labels:LB,TIMERS fix timers when sortBoundaryCells is called from lbbndcnddxqy.cpp
1706 /* NEW_SUB_TIMER(t_sortBCCells, "sort boundary cells", m_t_BCAll); */
1707 /* RECORD_TIMER_START(t_sortBCCells); */
1708
1709 // Sort the boundary cells
1710 const MInt tmpCellSize = m_bndCells.size();
1711
1712 m_log << " + Sorting boundary cells..." << endl;
1713 m_log << " - no. boundary cells: " << tmpCellSize << endl;
1714
1715 // using stable_sort to preserve the order by cellId within segmentIds
1716 stable_sort(m_bndCells.begin(), m_bndCells.end(),
1717 [](auto& a, auto& b) { return a.m_segmentId[0] < b.m_segmentId[0]; });
1718
1719 MInt tmpSegmentId = -1; // holds the current id
1720 MInt tmpBndCndId = -1; // holds the current boundary cells bndCndId
1721 MInt counter = 0; // Counts the boundary cells
1722
1723 // setting some default states, which is important in case of redoing this
1724 // method call
1725 m_bndCndIds.clear();
1726 m_bndCndOffsets.clear();
1727 m_bndCndSegIds.clear();
1728 m_mapBndCndSegId2Index.resize(m_noSegments, -1);
1729 m_mapIndex2BndCndSegId.resize(m_noSegments, -1);
1730 m_noBndCellsPerSegment.resize(m_noSegments, 0);
1731 // TODO labels:LB maybe also useful to reset: a_isBndryCell, a_bndId
1732
1733 for(MInt i = 0; i < tmpCellSize; i++) {
1734 if(tmpSegmentId != m_bndCells[i].m_segmentId[0]) {
1735 // Since m_bndCells has been sorted previously and new segmentid differs
1736 // from tmpSegmentId, we sort now for a new tmpSegmentId and co
1737 tmpSegmentId = m_bndCells[i].m_segmentId[0];
1738 tmpBndCndId = m_bndCells[i].m_bndCndId[0];
1739
1740 m_bndCndIds.push_back(tmpBndCndId);
1741 m_bndCndOffsets.push_back(counter);
1742 m_bndCndSegIds.push_back(tmpSegmentId);
1743 m_mapBndCndSegId2Index[tmpSegmentId] = m_bndCndSegIds.size() - 1;
1744 m_mapIndex2BndCndSegId[m_bndCndSegIds.size() - 1] = tmpSegmentId;
1745 }
1746 m_noBndCellsPerSegment[tmpSegmentId]++;
1747 m_solver->a_isBndryCell(m_bndCells[counter].m_cellId) = true;
1748 m_solver->a_bndId(m_bndCells[counter].m_cellId) = counter;
1749
1750 counter++;
1751 }
1752
1753 m_bndCndOffsets.push_back(counter);
1754
1755 // Make the mapping from all segments ids to the one that are just in/outflow
1756 m_mapSegIdsInOutCnd.resize((MInt)m_bndCndSegIds.size());
1757 for(MInt i = 0; i < (MInt)(m_bndCndSegIds.size()); i++) {
1758 MInt seg_id = m_bndCndSegIds[i];
1759
1760 m_log << " - BC " << m_bndCndIds[i] << endl;
1761 m_log << " * index: " << i << endl;
1762 m_log << " * segment id: " << seg_id << endl;
1763 m_log << " * no cells: " << m_noBndCellsPerSegment[seg_id] << endl;
1764 m_log << " * offsets: " << m_bndCndOffsets[i] << " - " << m_bndCndOffsets[i + 1] - 1 << endl;
1765
1766 MInt pos = -1;
1767 for(MInt j = 0; j < m_noInOutSegments; j++)
1768 if(seg_id == m_inOutSegmentsIds[j]) pos = j;
1769
1770 m_mapSegIdsInOutCnd[i] = pos;
1771
1772 m_log << " * mapping: " << m_mapSegIdsInOutCnd[i] << " "
1773 << ((m_mapSegIdsInOutCnd[i] < 0) ? "(this is not an inflow / outflow BC)" : "") << endl;
1774 }
1775 m_log << endl;
1776
1777 /* RECORD_TIMER_STOP(t_sortBCCells); */
1778}
1779
1781
1785template <MInt nDim>
1787 TRACE();
1788 if(!m_solver->isActive()) return;
1789
1790 NEW_SUB_TIMER(t_setBCHandler, "set BC handler", m_t_BCAll);
1791 RECORD_TIMER_START(t_setBCHandler);
1792
1793 m_log << " + Setting the boundary condition handler..." << endl << endl;
1794
1795 // Allocate space for pointer lists which store the boundary functions
1796 bndCndHandlerVariables.resize(m_bndCndIds.size());
1797 bndCndHandlerRHS.resize(m_bndCndIds.size());
1798 bndCndInitiator.resize(m_bndCndIds.size());
1799
1800 m_segIdUseBcData.resize(m_noSegments, 0);
1801
1802 // Fill the function pointer lists with correct bc functions
1803 for(MInt i = 0; i < (MInt)(m_bndCndIds.size()); i++) {
1804 switch(m_bndCndIds[i]) {
1805 case 0:
1806 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1807 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1808 bndCndInitiator[i] = &LbBndCnd::bc0;
1809 DEBUG("ERROR: bndCndHandlers only point to a dummy function", MAIA_DEBUG_LEVEL1);
1810 break;
1811
1812 //----------------------------------------------------
1813 // velocity boundary conditions
1814
1815 case 1000: // velocity (eq)
1816 applyDirectionChangeInflow(i);
1817 bndCndHandlerVariables[i] = &LbBndCnd::bc10000;
1818 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1819 bndCndInitiator[i] = &LbBndCnd::bc0;
1820 break;
1821 case 1001: // velocity (eq)
1822 applyDirectionChangeInflow(i);
1823 bndCndHandlerVariables[i] = &LbBndCnd::bc10001;
1824 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1825 bndCndInitiator[i] = &LbBndCnd::bc0;
1826 break;
1827 case 1002: // Inflow condition for periodic channel (z periodic, x/y is inflow)
1828 applyDirectionChangeInflow(i);
1829 bndCndHandlerRHS[i] = &LbBndCnd::bc10002;
1830 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1831 bndCndInitiator[i] = &LbBndCnd::bc0;
1832 break;
1833 case 1004: // velocity (eq)
1834 applyDirectionChangeInflow(i);
1835 bndCndHandlerVariables[i] = &LbBndCnd::bc10004;
1836 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1837 bndCndInitiator[i] = &LbBndCnd::bc0;
1838 break;
1839 case 1022: // Inflow condition for periodic channel (z periodic, x/y is inflow)
1840 applyDirectionChangeInflow(i);
1841 bndCndHandlerRHS[i] = &LbBndCnd::bc10022;
1842 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1843 bndCndInitiator[i] = &LbBndCnd::bc0;
1844 break;
1845 case 1010: // Inflow condition
1846 applyDirectionChangeInflow(i);
1847 bndCndHandlerVariables[i] = &LbBndCnd::bc10010;
1848 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1849 bndCndInitiator[i] = &LbBndCnd::bc0;
1850 break;
1851 case 1020: // Inflow condition
1852 applyDirectionChangeInflow(i);
1853 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1854 bndCndHandlerRHS[i] = &LbBndCnd::bc10020;
1855 bndCndInitiator[i] = &LbBndCnd::bc0;
1856 break;
1857 case 1040: // velocity NRCBC Izquerdo et al. 2008
1858 bcDataAllocate(i, nDim + 1);
1859 applyDirectionChangeInflow(i);
1860 bndCndHandlerRHS[i] = &LbBndCnd::bc10040;
1861 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1862 bndCndInitiator[i] = &LbBndCnd::bc0;
1863 break;
1864 case 1041:
1865 bcDataAllocate(i, nDim + 1);
1866 applyDirectionChangeInflow(i);
1867 bndCndHandlerRHS[i] = &LbBndCnd::bc10041;
1868 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1869 bndCndInitiator[i] = &LbBndCnd::bc0;
1870 break;
1871 case 1042:
1872 bcDataAllocate(i, nDim + 1);
1873 applyDirectionChangeInflow(i);
1874 bndCndHandlerRHS[i] = &LbBndCnd::bc10042;
1875 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1876 bndCndInitiator[i] = &LbBndCnd::bc0;
1877 break;
1878 case 1043:
1879 bcDataAllocate(i, nDim + 1);
1880 applyDirectionChangeInflow(i);
1881 bndCndHandlerRHS[i] = &LbBndCnd::bc10043;
1882 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1883 bndCndInitiator[i] = &LbBndCnd::bc0;
1884 break;
1885 case 1044:
1886 bcDataAllocate(i, nDim + 1);
1887 applyDirectionChangeInflow(i);
1888 bndCndHandlerRHS[i] = &LbBndCnd::bc10044;
1889 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1890 bndCndInitiator[i] = &LbBndCnd::bc0;
1891 break;
1892 case 1045:
1893 bcDataAllocate(i, nDim + 1);
1894 applyDirectionChangeInflow(i);
1895 bndCndHandlerRHS[i] = &LbBndCnd::bc10045;
1896 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1897 bndCndInitiator[i] = &LbBndCnd::bc0;
1898 break;
1899 case 1046: // velocity CBC LODI (force equilibrium)
1900 applyDirectionChangeInflow(i);
1901 bndCndHandlerRHS[i] = &LbBndCnd::bc10046;
1902 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1903 bndCndInitiator[i] = &LbBndCnd::bc0;
1904 break;
1905 case 1050:
1906 applyDirectionChangeInflow(i);
1907 bndCndHandlerRHS[i] = &LbBndCnd::bc10050;
1908 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1909 bndCndInitiator[i] = &LbBndCnd::bc0;
1910 break;
1911 case 1060: // velocity (eq), thermal
1912 applyDirectionChangeInflow(i);
1913 bndCndHandlerVariables[i] = &LbBndCnd::bc10060;
1914 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1915 bndCndInitiator[i] = &LbBndCnd::bc0;
1916 break;
1917 case 1061: // velocity (eq), thermal, Blasius for velocity
1918 applyDirectionChangeInflow(i);
1919 solveBlasiusZ(i);
1920 bndCndHandlerVariables[i] = &LbBndCnd::bc10061;
1921 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1922 bndCndInitiator[i] = &LbBndCnd::bc0;
1923 break;
1924 case 1070: // keeping local inflow mass flux to rho_0*Ma*Cs
1925 if(m_densityFluctuations) TERMM(1, "BC 1070 not working for densityFluctuations");
1926 applyDirectionChangeInflow(i);
1927 bndCndHandlerVariables[i] = &LbBndCnd::bc10070;
1928 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1929 bndCndInitiator[i] = &LbBndCnd::bc0;
1930 break;
1931
1932 case 1090: // velocity (eq), transport, concentration = 0.0
1933 applyDirectionChangeInflow(i);
1934 bndCndHandlerVariables[i] = &LbBndCnd::bc10090;
1935 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1936 bndCndInitiator[i] = &LbBndCnd::bc0;
1937 break;
1938
1939 //----------------------------------------------------
1940 // Pulsatile BCs
1941
1942 case 1080: // velocity (eq) - sinus
1943 applyDirectionChangeInflow(i);
1944 bndCndHandlerVariables[i] = &LbBndCnd::bc10080;
1945 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1946 bndCndInitiator[i] = &LbBndCnd::bc0;
1947 break;
1948
1949
1950 //----------------------------------------------------
1951 // Povitsky
1952
1953 case 1111: // Povitsky cavity condition (equilibirum dist)
1954 bndCndHandlerVariables[i] = &LbBndCnd::bc10111;
1955 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1956 bndCndInitiator[i] = &LbBndCnd::bc0;
1957 break;
1958
1959 //----------------------------------------------------
1960 // wall boundary conditions
1961
1962 case 2000: // no slip, BFL
1963 bndCndHandlerRHS[i] = &LbBndCnd::bc20000;
1964 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1965 bndCndInitiator[i] = &LbBndCnd::bc0;
1966 break;
1967 case 2001: // no slip, simple bounce back, halfway between nodes
1968 bndCndHandlerRHS[i] = &LbBndCnd::bc20001;
1969 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1970 bndCndInitiator[i] = &LbBndCnd::bc0;
1971 break;
1972 case 2002: // no slip, simple bounce back, on nodes
1973 bndCndHandlerRHS[i] = &LbBndCnd::bc20002;
1974 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1975 bndCndInitiator[i] = &LbBndCnd::bc0;
1976 break;
1977 case 2003: // no slip, equilibrium functions
1978 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
1979 bndCndHandlerVariables[i] = &LbBndCnd::bc20003;
1980 bndCndInitiator[i] = &LbBndCnd::bc0;
1981 break;
1982 case 2004: // no slip, Haenel interpolated
1983 bndCndHandlerRHS[i] = &LbBndCnd::bc20004;
1984 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1985 bndCndInitiator[i] = &LbBndCnd::bc0;
1986 break;
1987 case 2005: // no slip, Guo interpolated
1988 bndCndHandlerRHS[i] = &LbBndCnd::bc20005;
1989 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1990 bndCndInitiator[i] = &LbBndCnd::bc0;
1991 break;
1992 case 2006: // free slip, only for 2d
1993 bndCndHandlerRHS[i] = &LbBndCnd::bc20006;
1994 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
1995 bndCndInitiator[i] = &LbBndCnd::bc0;
1996 break;
1997 case 2010: // no slip, BFL, with force calculation
1998 bndCndHandlerRHS[i] = &LbBndCnd::bc20010;
1999 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2000 bndCndInitiator[i] = &LbBndCnd::bc0;
2001 break;
2002 case 2020: // no slip, BFL, with force calculation
2003 bndCndHandlerRHS[i] = &LbBndCnd::bc20020;
2004 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2005 bndCndInitiator[i] = &LbBndCnd::bc0;
2006 break;
2007 case 2220: // no slip, BFL , Thermal
2008 bndCndHandlerRHS[i] = &LbBndCnd::bc20220;
2009 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2010 bndCndInitiator[i] = &LbBndCnd::bc0;
2011 break;
2012
2013 case 2226: // no slip, BFL, Thermal (Dirichlet condition), cylinder flow
2014 bndCndHandlerRHS[i] = &LbBndCnd::bc20226;
2015 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2016 bndCndInitiator[i] = &LbBndCnd::bc0;
2017 break;
2018 case 2227: // no slip, BFL, Thermal (Dirichlet condition), channel flow
2019 bndCndHandlerRHS[i] = &LbBndCnd::bc20227;
2020 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2021 bndCndInitiator[i] = &LbBndCnd::bc0;
2022 break;
2023 case 2228: // no slip, BFL, Thermal flux (Neumann condition), channel flow
2024 bndCndHandlerRHS[i] = &LbBndCnd::bc20228;
2025 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2026 bndCndInitiator[i] = &LbBndCnd::bcIBBNeumannInit;
2027 break;
2028
2029 case 2022: // no slip, BFL , also for Thermal
2030 bndCndHandlerRHS[i] = &LbBndCnd::bc20022;
2031 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2032 bndCndInitiator[i] = &LbBndCnd::bc0;
2033 break;
2034 case 2023: // no slip, simple bounce back, on nodes for Thermal
2035 bndCndHandlerRHS[i] = &LbBndCnd::bc20023;
2036 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2037 bndCndInitiator[i] = &LbBndCnd::bc0;
2038 break;
2039 case 2024: // no slip, Thermal bc2004
2040 bndCndHandlerRHS[i] = &LbBndCnd::bc20024;
2041 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2042 bndCndInitiator[i] = &LbBndCnd::bc0;
2043 break;
2044 case 2025: // no slip, Thermal, sets eq. dist. fnc. for given mac. vars.
2045 bndCndHandlerRHS[i] = &LbBndCnd::bc20025;
2046 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2047 bndCndInitiator[i] = &LbBndCnd::bc0;
2048 break;
2049 case 2026: // no slip, simple bounce back, halfway between nodes, same as 2001, but also for Thermal
2050 bndCndHandlerRHS[i] = &LbBndCnd::bc20026;
2051 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2052 bndCndInitiator[i] = &LbBndCnd::bc0;
2053 break;
2054 case 2027: // no slip, interpolated bounce back, thermal interpolated
2055 bndCndHandlerRHS[i] = &LbBndCnd::bc20027;
2056 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2057 bndCndInitiator[i] = &LbBndCnd::bc0;
2058 break;
2059 case 2030: // no slip, Haenel interpolated with velocity
2060 bndCndHandlerRHS[i] = &LbBndCnd::bc20030;
2061 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2062 bndCndInitiator[i] = &LbBndCnd::bc0;
2063 break;
2064 case 2230: // no slip, Haenel interpolated with velocity
2065 bndCndHandlerRHS[i] = &LbBndCnd::bc20230;
2066 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2067 bndCndInitiator[i] = &LbBndCnd::bc0;
2068 break;
2069 case 2050: // sliding wall in axis direction
2070 bndCndHandlerVariables[i] = &LbBndCnd::bc20050;
2071 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2072 bndCndInitiator[i] = &LbBndCnd::bc0;
2073 break;
2074 case 2051:
2075 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2076 bndCndHandlerRHS[i] = &LbBndCnd::bc20051;
2077 bndCndInitiator[i] = &LbBndCnd::bc0;
2078 break;
2079 case 2052:
2080 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2081 bndCndHandlerRHS[i] = &LbBndCnd::bc20052;
2082 bndCndInitiator[i] = &LbBndCnd::bc0;
2083 break;
2084 case 2053:
2085 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2086 bndCndHandlerRHS[i] = &LbBndCnd::bc20053;
2087 bndCndInitiator[i] = &LbBndCnd::bc0;
2088 break;
2089 case 2054:
2090 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2091 bndCndHandlerRHS[i] = &LbBndCnd::bc20054;
2092 bndCndInitiator[i] = &LbBndCnd::bc0;
2093 break;
2094 case 2055:
2095 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2096 bndCndHandlerRHS[i] = &LbBndCnd::bc20055;
2097 bndCndInitiator[i] = &LbBndCnd::bc0;
2098 break;
2099
2100 case 2501: // nasal mucosa model, latent heat
2101 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2102 bndCndHandlerRHS[i] = &LbBndCnd::bc20501;
2103 bndCndInitiator[i] = &LbBndCnd::bc20501_init;
2104 break;
2105
2106 //----------------------------------------------------
2107 // zero gradient boundary conditions
2108
2109 //----------------------------------------------------
2110 case 3000: // extrapolation in normal vector direction
2111 bndCndHandlerRHS[i] = &LbBndCnd::bc30000;
2112 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2113 bndCndInitiator[i] = &LbBndCnd::bc0;
2114 break;
2115
2116 case 3010: // extrapolation in axis direction
2117 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2118 bndCndHandlerRHS[i] = &LbBndCnd::bc30010;
2119 bndCndInitiator[i] = &LbBndCnd::bc0;
2120 break;
2121 case 3011:
2122 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2123 bndCndHandlerRHS[i] = &LbBndCnd::bc30011;
2124 bndCndInitiator[i] = &LbBndCnd::bc0;
2125 break;
2126 case 3012:
2127 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2128 bndCndHandlerRHS[i] = &LbBndCnd::bc30012;
2129 bndCndInitiator[i] = &LbBndCnd::bc0;
2130 break;
2131 case 3013:
2132 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2133 bndCndHandlerRHS[i] = &LbBndCnd::bc30013;
2134 bndCndInitiator[i] = &LbBndCnd::bc0;
2135 break;
2136 case 3014:
2137 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2138 bndCndHandlerRHS[i] = &LbBndCnd::bc30014;
2139 bndCndInitiator[i] = &LbBndCnd::bc0;
2140 break;
2141 case 3015:
2142 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2143 bndCndHandlerRHS[i] = &LbBndCnd::bc30015;
2144 bndCndInitiator[i] = &LbBndCnd::bc0;
2145 break;
2146
2147 case 3020:
2148 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2149 bndCndHandlerRHS[i] = &LbBndCnd::bc30020;
2150 bndCndInitiator[i] = &LbBndCnd::bc0;
2151 break;
2152 case 3021:
2153 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2154 bndCndHandlerRHS[i] = &LbBndCnd::bc30021;
2155 bndCndInitiator[i] = &LbBndCnd::bc0;
2156 break;
2157 case 3022:
2158 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2159 bndCndHandlerRHS[i] = &LbBndCnd::bc30022;
2160 bndCndInitiator[i] = &LbBndCnd::bc0;
2161 break;
2162 case 3023:
2163 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2164 bndCndHandlerRHS[i] = &LbBndCnd::bc30023;
2165 bndCndInitiator[i] = &LbBndCnd::bc0;
2166 break;
2167 case 3024:
2168 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2169 bndCndHandlerRHS[i] = &LbBndCnd::bc30024;
2170 bndCndInitiator[i] = &LbBndCnd::bc0;
2171 break;
2172 case 3025:
2173 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2174 bndCndHandlerRHS[i] = &LbBndCnd::bc30025;
2175 bndCndInitiator[i] = &LbBndCnd::bc0;
2176 break;
2177
2178 case 3030:
2179 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2180 bndCndHandlerRHS[i] = &LbBndCnd::bc30030;
2181 bndCndInitiator[i] = &LbBndCnd::bc0;
2182 break;
2183 case 3031:
2184 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2185 bndCndHandlerRHS[i] = &LbBndCnd::bc30031;
2186 bndCndInitiator[i] = &LbBndCnd::bc0;
2187 break;
2188 case 3032:
2189 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2190 bndCndHandlerRHS[i] = &LbBndCnd::bc30032;
2191 bndCndInitiator[i] = &LbBndCnd::bc0;
2192 break;
2193 case 3033:
2194 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2195 bndCndHandlerRHS[i] = &LbBndCnd::bc30033;
2196 bndCndInitiator[i] = &LbBndCnd::bc0;
2197 break;
2198 case 3034:
2199 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2200 bndCndHandlerRHS[i] = &LbBndCnd::bc30034;
2201 bndCndInitiator[i] = &LbBndCnd::bc0;
2202 break;
2203 case 3035:
2204 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2205 bndCndHandlerRHS[i] = &LbBndCnd::bc30035;
2206 bndCndInitiator[i] = &LbBndCnd::bc0;
2207 break;
2208
2209 case 3040:
2210 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2211 bndCndHandlerRHS[i] = &LbBndCnd::bc30040;
2212 bndCndInitiator[i] = &LbBndCnd::bc0;
2213 break;
2214 case 3041:
2215 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2216 bndCndHandlerRHS[i] = &LbBndCnd::bc30041;
2217 bndCndInitiator[i] = &LbBndCnd::bc0;
2218 break;
2219 case 3042:
2220 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2221 bndCndHandlerRHS[i] = &LbBndCnd::bc30042;
2222 bndCndInitiator[i] = &LbBndCnd::bc0;
2223 break;
2224 case 3043:
2225 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2226 bndCndHandlerRHS[i] = &LbBndCnd::bc30043;
2227 bndCndInitiator[i] = &LbBndCnd::bc0;
2228 break;
2229 case 3044:
2230 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2231 bndCndHandlerRHS[i] = &LbBndCnd::bc30044;
2232 bndCndInitiator[i] = &LbBndCnd::bc0;
2233 break;
2234 case 3045:
2235 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2236 bndCndHandlerRHS[i] = &LbBndCnd::bc30045;
2237 bndCndInitiator[i] = &LbBndCnd::bc0;
2238 break;
2239
2240 case 3050:
2241 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2242 bndCndHandlerRHS[i] = &LbBndCnd::bc30050;
2243 bndCndInitiator[i] = &LbBndCnd::bc0;
2244 break;
2245
2246
2247 //----------------------------------------------------
2248 // pressure bc's
2249
2250 case 4000: // prescribe equilibrium distributions
2251 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2252 bndCndHandlerVariables[i] = &LbBndCnd::bc40000;
2253 bndCndInitiator[i] = &LbBndCnd::bc0;
2254 break;
2255 case 4001: // prescribe equilibrium distributions
2256 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2257 bndCndHandlerVariables[i] = &LbBndCnd::bc40001;
2258 bndCndInitiator[i] = &LbBndCnd::bc0;
2259 break;
2260 case 4010: // Extrapolation Chen
2261 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2262 bndCndHandlerVariables[i] = &LbBndCnd::bc40010;
2263 bndCndInitiator[i] = &LbBndCnd::bc0;
2264 break;
2265 case 4020: // relaxed pressure
2266 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2267 bndCndHandlerVariables[i] = &LbBndCnd::bc40020;
2268 bndCndInitiator[i] = &LbBndCnd::bc0;
2269 break;
2270 case 4030: // Extrapolation with non-eq
2271 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2272 bndCndHandlerVariables[i] = &LbBndCnd::bc40030;
2273 bndCndInitiator[i] = &LbBndCnd::bc0;
2274 break;
2275 case 4040: // pressure NRCBC Izquerdo et al. 2008
2276 bcDataAllocate(i, nDim + 1);
2277 bndCndHandlerRHS[i] = &LbBndCnd::bc40040;
2278 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2279 bndCndInitiator[i] = &LbBndCnd::bc0;
2280 break;
2281 case 4041:
2282 bcDataAllocate(i, nDim + 1);
2283 bndCndHandlerRHS[i] = &LbBndCnd::bc40041;
2284 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2285 bndCndInitiator[i] = &LbBndCnd::bc0;
2286 break;
2287 case 4042:
2288 bcDataAllocate(i, nDim + 1);
2289 bndCndHandlerRHS[i] = &LbBndCnd::bc40042;
2290 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2291 bndCndInitiator[i] = &LbBndCnd::bc0;
2292 break;
2293 case 4043:
2294 bcDataAllocate(i, nDim + 1);
2295 bndCndHandlerRHS[i] = &LbBndCnd::bc40043;
2296 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2297 bndCndInitiator[i] = &LbBndCnd::bc0;
2298 break;
2299 case 4044:
2300 bcDataAllocate(i, nDim + 1);
2301 bndCndHandlerRHS[i] = &LbBndCnd::bc40044;
2302 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2303 bndCndInitiator[i] = &LbBndCnd::bc0;
2304 break;
2305 case 4045:
2306 bcDataAllocate(i, nDim + 1);
2307 bndCndHandlerRHS[i] = &LbBndCnd::bc40045;
2308 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2309 bndCndInitiator[i] = &LbBndCnd::bc0;
2310 break;
2311
2312 case 4046: // non-reflective based on LODI by prescribing equilibrium
2313 bndCndHandlerRHS[i] = &LbBndCnd::bc40046;
2314 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2315 bndCndInitiator[i] = &LbBndCnd::bc0;
2316 break;
2317
2318 case 4060:
2319 bndCndHandlerRHS[i] = &LbBndCnd::bc40060;
2320 bndCndHandlerVariables[i] = &LbBndCnd::bc0;
2321 bndCndInitiator[i] = &LbBndCnd::bc0;
2322 break;
2323
2324 case 4070: // relax pressure based on formulations by Hoerschler
2325 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2326 bndCndHandlerVariables[i] = &LbBndCnd::bc40070;
2327 bndCndInitiator[i] = &LbBndCnd::bc0;
2328 break;
2329 case 4071: // hold pressure constant at a given value
2330 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2331 bndCndHandlerVariables[i] = &LbBndCnd::bc40071;
2332 bndCndInitiator[i] = &LbBndCnd::bc0;
2333 break;
2334 case 4072: // adjusts pressure to yield a specified local Reynolds number
2335 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2336 bndCndHandlerVariables[i] = &LbBndCnd::bc40072;
2337 bndCndInitiator[i] = &LbBndCnd::bc40072_40082_init;
2338 break;
2339 case 4073: // adjusts pressure to yield a specified local Reynolds number (measured at a specified location)
2340 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2341 bndCndHandlerVariables[i] = &LbBndCnd::bc40073;
2342 bndCndInitiator[i] = &LbBndCnd::bc0;
2343 break;
2344 case 4080: // relax pressure based on formulations by Hoerschler, additionally set temperature
2345 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2346 bndCndHandlerVariables[i] = &LbBndCnd::bc40080;
2347 bndCndInitiator[i] = &LbBndCnd::bc0;
2348 break;
2349 case 4081: // hold pressure constant at a given value, extrapolate temperature and velcoities
2350 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2351 bndCndHandlerVariables[i] = &LbBndCnd::bc40081;
2352 bndCndInitiator[i] = &LbBndCnd::bc0;
2353 break;
2354 case 4082: // adjusts pressure to yield a specified local Reynolds number
2355 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2356 bndCndHandlerVariables[i] = &LbBndCnd::bc40082;
2357 bndCndInitiator[i] = &LbBndCnd::bc40072_40082_init;
2358 break;
2359
2360 case 4100: // prescribe equilibrium distributions
2361 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2362 bndCndHandlerVariables[i] = &LbBndCnd::bc40100;
2363 bndCndInitiator[i] = &LbBndCnd::bc0;
2364 break;
2365 case 4110: // prescribe equilibrium distributions (similar to bc4030)
2366 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2367 bndCndHandlerVariables[i] = &LbBndCnd::bc40110;
2368 bndCndInitiator[i] = &LbBndCnd::bc0;
2369 break;
2370
2371 case 4120: // prescribe equilibrium distributions (similar to bc4030)
2372 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2373 bndCndHandlerVariables[i] = &LbBndCnd::bc40120;
2374 bndCndInitiator[i] = &LbBndCnd::bc0;
2375 break;
2376
2377 case 4130: // Extrapolation with non-eq
2378 bndCndHandlerRHS[i] = &LbBndCnd::bc0;
2379 bndCndHandlerVariables[i] = &LbBndCnd::bc40130;
2380 bndCndInitiator[i] = &LbBndCnd::bc0;
2381 break;
2382 default:
2383 stringstream errorMessage;
2384 errorMessage << " LbBncCndDxQy::setBndCndHandler : Unknown boundary condition " << m_bndCndIds[i]
2385 << " exiting program.";
2386 TERMM(1, errorMessage.str());
2387 }
2388 }
2389
2390 // Communications
2391 MPI_Allreduce(MPI_IN_PLACE, m_segIdUseBcData.data(), m_segIdUseBcData.size(), MPI_INT, MPI_SUM, m_solver->mpiComm(),
2392 AT_, "MPI_IN_PLACE", "m_SegIdUseBcData.data()");
2393
2394 RECORD_TIMER_STOP(t_setBCHandler);
2395}
2396
2397
2406template <MInt nDim>
2408 TRACE();
2409
2410 m_noAllBoundaryIds = 0;
2411 m_allBoundaryIds = m_solver->m_geometry->GetBoundaryIds(&m_noAllBoundaryIds);
2412
2413 for(MInt i = 0; i < m_noAllBoundaryIds; i++) {
2414 switch(m_allBoundaryIds[i]) {
2415 case 2000: {
2416 return true;
2417 // The following statement was commented since it is not reachable. Remove if not needed anymore.
2418 // break;
2419 }
2420 default: {
2421 }
2422 }
2423 }
2424 return false;
2425}
2426
2436template <MInt nDim>
2438 TRACE();
2439
2440 NEW_SUB_TIMER(t_setBCNC, "set BC neighbor communicators", m_t_BCAll);
2441 RECORD_TIMER_START(t_setBCNC);
2442
2443 // first of all check if we have a BC which requries communication
2444 m_hasCommForce = checkForCommForce();
2445 if(!m_hasCommForce) {
2446 RECORD_TIMER_STOP(t_setBCNC);
2447 return;
2448 }
2449
2450 m_log << " + Found a BC which requires communication:" << endl;
2451
2452 // currently working only for one BC
2453 for(MInt i = 0; i < m_noAllBoundaryIds; i++) {
2454 MBool found = false;
2455 switch(m_allBoundaryIds[i]) {
2456 case 2000: {
2457 prepareBC2000();
2458 found = true;
2459 break;
2460 }
2461 default: {
2462 }
2463 }
2464 if(found) {
2465 break;
2466 }
2467 }
2468
2469 RECORD_TIMER_STOP(t_setBCNC);
2470}
2471
2485template <MInt nDim>
2487 TRACE();
2488
2489 if(!m_calcWallForces) return;
2490
2491 MInt noAllBoundaryIds = 0;
2492 const MInt* const allBoundaryIds = m_solver->m_geometry->GetBoundaryIds(&noAllBoundaryIds);
2493 TERMM_IF_COND(noAllBoundaryIds != m_noSegments, "noAllBoundaryIds != m_noSegments");
2494
2495 m_mapWallForceContainer.clear();
2496 for(MInt i = 0; i < m_noSegments; i++) {
2497 if(allBoundaryIds[i] == 2000) {
2498 m_mapWallForceContainer[i];
2499 }
2500 }
2501
2502 for(auto& mapWallForceIterator : m_mapWallForceContainer) {
2503 const MInt segId = mapWallForceIterator.first;
2504 const MInt index = m_mapBndCndSegId2Index[segId];
2505 auto& cwfc = mapWallForceIterator.second;
2506
2507 const MInt noCalcForceCells = (index > -1) ? (m_bndCndOffsets[index + 1] - m_bndCndOffsets[index]) : 0;
2508
2509 // unfortunately a global communication is requried
2510 std::vector<MInt> noCalcForceCellsPerDomain(m_solver->noDomains(), 0);
2511 MPI_Allgather(&noCalcForceCells, 1, MPI_INT, noCalcForceCellsPerDomain.data(), 1, MPI_INT, m_solver->mpiComm(), AT_,
2512 "noCalcForceCells", "noCalcForceCellsPerDomain");
2513 std::vector<MInt> bcWallNeighbors;
2514 for(MInt i = 0; i < m_solver->noDomains(); i++) {
2515 if(noCalcForceCellsPerDomain[i] > 0) {
2516 bcWallNeighbors.push_back(i);
2517 }
2518 }
2519
2520 cwfc.noComm = bcWallNeighbors.size();
2521
2522 // build a new communicator
2523 if(cwfc.noComm != 0) {
2524 MPI_Group tmp_bcGroupWall;
2525 MPI_Group bcGroupWall;
2526 MPI_Comm_group(m_solver->mpiComm(), &tmp_bcGroupWall, AT_, "tmp_group");
2527 MPI_Group_incl(tmp_bcGroupWall, cwfc.noComm, bcWallNeighbors.data(), &bcGroupWall, AT_);
2528 MPI_Comm_create(m_solver->mpiComm(), bcGroupWall, &cwfc.comm, AT_, "cwfc.comm");
2529
2530 cwfc.isRoot = (m_solver->domainId() == bcWallNeighbors[0]);
2531 if(cwfc.isRoot) {
2532 if(m_mapWallForceContainer.size() > 1) {
2533 std::stringstream fileNameS;
2534 fileNameS << m_forceFile << m_bndCndSegIds[index];
2535 cwfc.fileName = fileNameS.str();
2536 } else {
2537 cwfc.fileName = m_forceFile;
2538 }
2539 // Write header
2540 std::FILE* forceFile;
2541 forceFile = fopen(cwfc.fileName.c_str(), "a+");
2542 fprintf(forceFile, "# Re=%f, Ma=%f, refLength_LB=%f, dx(maxLvl)=%e\n", m_solver->m_Re, m_solver->m_Ma,
2543 m_solver->m_referenceLength, m_solver->c_cellLengthAtLevel(m_solver->maxLevel()));
2544 fprintf(forceFile, "#");
2545 fprintf(forceFile, "%s\t", "1:TS");
2546 constexpr MInt columnLength = 15;
2547 fprintf(forceFile, "%*s\t", columnLength, "2:F_x");
2548 fprintf(forceFile, "%*s\t", columnLength, "3:F_y");
2549 if constexpr(nDim == 3) {
2550 fprintf(forceFile, "%*s\t", columnLength, "4:F_z");
2551 }
2552 fprintf(forceFile, "\n");
2553 fclose(forceFile);
2554 }
2555 }
2556 }
2557}
2558
2559
2568template <MInt nDim>
2570 TRACE();
2571
2572 if(m_solver->m_geometry->m_parallelGeometry) {
2573 set<MInt> tmplist;
2574 for(MInt i = 0; i < m_noSegments; i++)
2575 tmplist.insert(*(m_solver->m_geometry->geometryContext().getProperty("BC", i)->asInt()));
2576 m_noAllBoundaryIds = tmplist.size();
2577 mAlloc(m_allBoundaryIds, m_noAllBoundaryIds, "m_allBoundaryIds", 0, AT_);
2578 MInt pos = 0;
2579 for(set<MInt>::iterator it = tmplist.begin(); it != tmplist.end(); ++it, pos++)
2580 m_allBoundaryIds[pos] = *it;
2581 } else {
2582 m_noAllBoundaryIds = 0;
2583 m_allBoundaryIds = m_solver->m_geometry->GetBoundaryIds(&m_noAllBoundaryIds);
2584 }
2585
2586 for(MInt i = 0; i < m_noAllBoundaryIds; i++) {
2587 switch(m_allBoundaryIds[i]) {
2588 case 1000: {
2589 m_numberOfCommBCs++;
2590 break;
2591 }
2592 case 1022: {
2593 m_numberOfCommBCs++;
2594 break;
2595 }
2596 case 1060: {
2597 m_numberOfCommBCs++;
2598 break;
2599 }
2600 case 1080: {
2601 m_numberOfCommBCs++;
2602 break;
2603 }
2604 case 4000: {
2605 m_numberOfCommBCs++;
2606 break;
2607 }
2608 case 4030: {
2609 m_numberOfCommBCs++;
2610 break;
2611 }
2612 case 4130: {
2613 m_numberOfCommBCs++;
2614 break;
2615 }
2616 case 4070: {
2617 m_numberOfCommBCs++;
2618 break;
2619 }
2620 case 4071: {
2621 m_numberOfCommBCs++;
2622 break;
2623 }
2624 case 4072: {
2625 m_numberOfCommBCs++;
2626 break;
2627 }
2628 case 4073: {
2629 m_numberOfCommBCs++;
2630 break;
2631 }
2632 case 4080: {
2633 m_numberOfCommBCs++;
2634 break;
2635 }
2636 case 4081: {
2637 m_numberOfCommBCs++;
2638 break;
2639 }
2640 case 4082: {
2641 m_numberOfCommBCs++;
2642 break;
2643 }
2644 case 4110: {
2645 m_numberOfCommBCs++;
2646 break;
2647 }
2648 default: {
2649 }
2650 }
2651 }
2652 return m_numberOfCommBCs;
2653}
2654
2668template <MInt nDim>
2669void LbBndCnd<nDim>::prepareBC(MInt index, MInt BCCounter, MInt segId) {
2670 TRACE();
2671
2672 for(MInt count = 0; count < (MInt)m_bndCndSegIds.size(); count++) {
2673 if(m_bndCndIds[count] == index && m_bndCndSegIds[count] == segId) {
2674 const MInt bndCndIdIndex = count;
2675 m_allDomainsHaveBC[BCCounter][m_solver->domainId()] =
2676 m_bndCndOffsets[bndCndIdIndex + 1] - m_bndCndOffsets[bndCndIdIndex];
2677 m_mapBndCndIdSegId[count] = BCCounter;
2678 break;
2679 } else
2680 m_allDomainsHaveBC[BCCounter][m_solver->domainId()] = 0;
2681 }
2682
2683 if(m_solver->noDomains() > 1) {
2684 // unfortunately a global communication is requried
2685 const MInt sndBuf = m_allDomainsHaveBC[BCCounter][m_solver->domainId()];
2686 MIntScratchSpace domainsHaveBC(m_solver->noDomains(), AT_, "domainsHaveBC");
2687 MPI_Allgather(&sndBuf, 1, MPI_INT, domainsHaveBC.getPointer(), 1, MPI_INT, m_solver->mpiComm(), AT_, "sndBuf",
2688 "m_allDomainsHaveBC");
2689
2690 for(MInt count = 0; count < m_solver->noDomains(); count++) {
2691 m_allDomainsHaveBC[BCCounter][count] = domainsHaveBC(count);
2692 }
2693
2694 std::vector<MInt> BCneighborsPerSeg;
2695 m_totalNoBcCells[BCCounter] = 0;
2696 for(MInt i = 0; i < m_solver->noDomains(); i++) {
2697 if(m_allDomainsHaveBC[BCCounter][i] > 0) {
2698 BCneighborsPerSeg.push_back(i);
2699 m_totalNoBcCells[BCCounter] += m_allDomainsHaveBC[BCCounter][i];
2700 }
2701 }
2702
2703 m_BCneighbors.push_back(BCneighborsPerSeg);
2704
2705 m_noBCNeighbors[BCCounter] = (MInt)m_BCneighbors[BCCounter].size();
2706
2707 if(m_noBCNeighbors[BCCounter] > 1) {
2708 MIntScratchSpace ptBCneighbors(m_noBCNeighbors[BCCounter], AT_, "ptBCneighbors");
2709 for(MInt i = 0; i < m_noBCNeighbors[BCCounter]; i++)
2710 ptBCneighbors.p[i] = m_BCneighbors[BCCounter][i];
2711
2712 MPI_Comm_group(m_solver->mpiComm(), &tmp_group[BCCounter], AT_, "tmp_group");
2713
2714 MPI_Group_incl(tmp_group[BCCounter], m_noBCNeighbors[BCCounter], ptBCneighbors.getPointer(), &BCGroup[BCCounter],
2715 AT_);
2716 MPI_Comm_create(m_solver->mpiComm(), BCGroup[BCCounter], &m_BCComm[BCCounter], AT_, "m_BCComm");
2717 }
2718 } else {
2719 std::vector<MInt> BCneighborsPerSeg;
2720 BCneighborsPerSeg.push_back(m_solver->domainId());
2721 m_BCneighbors.push_back(BCneighborsPerSeg);
2722 m_totalNoBcCells[BCCounter] = m_allDomainsHaveBC[BCCounter][0];
2723 m_noBCNeighbors[BCCounter] = 1;
2724 }
2725}
2726
2727template <MInt nDim>
2729 m_log << " - BC 4073" << endl;
2730 m_log << " * reading properties from file" << endl;
2731 // get the plane from the geomtry file that specifies the plane that should be used for
2732 // the calculation of the local Reynolds number
2733 if(m_solver->m_geometry->geometryContext().propertyExists("localReCut", 0)) {
2734 MInt num = m_solver->m_geometry->geometryContext().getProperty("localReCut", 0)->count();
2735 if((nDim == 2 && num != 4) || (nDim == 3 && num != 6)) {
2736 stringstream errorMsg;
2737 errorMsg << "ERROR: no wrong number of entries in the geometry property 'localReCut' for BC 4073" << endl;
2738 m_log << errorMsg.str();
2739 TERMM(1, errorMsg.str());
2740 }
2741
2742 // this holds the cut information for the local Reynolds number calculation
2743 mAlloc(m_localReCutPoint, nDim, "m_localReCutPoint", 0.0, AT_);
2744 mAlloc(m_localReCutNormal, nDim, "m_localReCutNormal", 0.0, AT_);
2745
2746 MFloat len = 0.0;
2747 for(MInt i = 0; i < nDim; i++) {
2748 m_localReCutPoint[i] = *m_solver->m_geometry->geometryContext().getProperty("localReCut", 0)->asFloat(i);
2749 m_localReCutNormal[i] = *m_solver->m_geometry->geometryContext().getProperty("localReCut", 0)->asFloat(i + nDim);
2750 len += m_localReCutNormal[i] * m_localReCutNormal[i];
2751 }
2752 len = sqrt(len);
2753 if(approx(len, 0.0, MFloatEps)) {
2754 stringstream errorMsg;
2755 errorMsg << "ERROR: the normal defined by the geometry property 'localReCut' seems to be wrong" << endl;
2756 m_log << errorMsg.str();
2757 TERMM(1, errorMsg.str());
2758 }
2759
2760 // normalize
2761 for(MInt i = 0; i < nDim; i++)
2762 m_localReCutNormal[i] /= len;
2763
2764 if(m_solver->m_geometry->geometryContext().propertyExists("localReCutDistance", 0))
2765 m_localReCutDistance = *m_solver->m_geometry->geometryContext().getProperty("localReCutDistance", 0)->asFloat();
2766 else
2767 m_localReCutDistance = m_solver->c_cellLengthAtLevel(0);
2768
2769 if(m_solver->m_geometry->geometryContext().propertyExists("localReCutInterval", 0))
2770 m_localReCutInterval = *m_solver->m_geometry->geometryContext().getProperty("localReCutInterval", 0)->asInt();
2771 else {
2772 stringstream errorMsg;
2773 errorMsg << "ERROR: no geometry property 'localReCutInterval' defined for BC 4073" << endl;
2774 m_log << errorMsg.str();
2775 TERMM(1, errorMsg.str());
2776 }
2777 } else {
2778 stringstream errorMsg;
2779 errorMsg << "ERROR: no geometry property 'localReCut' defined for BC 4073" << endl;
2780 m_log << errorMsg.str();
2781 TERMM(1, errorMsg.str());
2782 }
2783
2784 m_localReCutReportInterval = 1000;
2785 if(m_solver->m_geometry->geometryContext().propertyExists("localReCutReportInterval", 0))
2786 m_localReCutReportInterval =
2787 *m_solver->m_geometry->geometryContext().getProperty("localReCutReportInterval", 0)->asInt();
2788
2789 m_localReCutRe = m_solver->m_Re;
2790 if(m_solver->m_geometry->geometryContext().propertyExists("localReCutRe", 0))
2791 m_localReCutRe = *m_solver->m_geometry->geometryContext().getProperty("localReCutRe", 0)->asFloat();
2792
2793 m_localReCutDiameter = m_referenceLength;
2794 if(m_solver->m_geometry->geometryContext().propertyExists("localReCutDiameter", 0))
2795 m_localReCutDiameter = *m_solver->m_geometry->geometryContext().getProperty("localReCutDiameter", 0)->asFloat();
2796
2797 m_localReCutAdpPerc = 0.2;
2798 if(m_solver->m_geometry->geometryContext().propertyExists("localReCutAdpPerc", 0))
2799 m_localReCutAdpPerc = *m_solver->m_geometry->geometryContext().getProperty("localReCutAdpPerc", 0)->asFloat();
2800
2801 // load from restart? -> overwrite local data
2802 m_log << " * reading information for restart" << endl;
2803 if(m_solver->m_restartFile) {
2804 if(m_solver->m_geometry->geometryContext().propertyExists("localReCut_rho1", 0))
2805 m_solver->m_rho1 = *m_solver->m_geometry->geometryContext().getProperty("localReCut_rho1", 0)->asFloat();
2806 else {
2807 stringstream errorMsg;
2808 errorMsg << "ERROR: no geometry property 'localReCut_rho1' defined for BC 4073 (as required for restart)" << endl;
2809 m_log << errorMsg.str();
2810 TERMM(1, errorMsg.str());
2811 }
2812
2813 if(m_solver->m_geometry->geometryContext().propertyExists("localReCut_lRho", 0))
2814 m_lRho = *m_solver->m_geometry->geometryContext().getProperty("localReCut_lRho", 0)->asFloat();
2815 else {
2816 stringstream errorMsg;
2817 errorMsg << "ERROR: no geometry property 'localReCut_lRho' defined for BC 4073 (as required for restart)" << endl;
2818 m_log << errorMsg.str();
2819 TERMM(1, errorMsg.str());
2820 }
2821
2822 if(m_solver->m_geometry->geometryContext().propertyExists("localReCut_rhoLast", 0))
2823 m_rhoLast = *m_solver->m_geometry->geometryContext().getProperty("localReCut_rhoLast", 0)->asFloat();
2824 else {
2825 stringstream errorMsg;
2826 errorMsg << "ERROR: no geometry property 'localReCut_rhoLast' defined for BC 4073 (as required for restart)"
2827 << endl;
2828 m_log << errorMsg.str();
2829 TERMM(1, errorMsg.str());
2830 }
2831
2832 if(m_solver->m_geometry->geometryContext().propertyExists("localReCut_deltaRho", 0))
2833 m_deltaRho = *m_solver->m_geometry->geometryContext().getProperty("localReCut_deltaRho", 0)->asFloat();
2834 else {
2835 stringstream errorMsg;
2836 errorMsg << "ERROR: no geometry property 'localReCut_deltaRho' defined for BC 4073 (as required for restart)"
2837 << endl;
2838 m_log << errorMsg.str();
2839 TERMM(1, errorMsg.str());
2840 }
2841
2842 if(m_solver->m_geometry->geometryContext().propertyExists("localReCut_ReLast", 0))
2843 m_ReLast = *m_solver->m_geometry->geometryContext().getProperty("localReCut_ReLast", 0)->asFloat();
2844 else {
2845 stringstream errorMsg;
2846 errorMsg << "ERROR: no geometry property 'localReCut_ReLast' defined for BC 4073 (as required for restart)"
2847 << endl;
2848 m_log << errorMsg.str();
2849 TERMM(1, errorMsg.str());
2850 }
2851 }
2852
2853 // find all cells that have a cut with the line/plane and the according distance
2854 m_log << " * finding cells that have a cut with the reference plane" << endl;
2855 for(MInt i = 0; i < m_solver->m_cells.size(); i++) {
2856 // only leaf cells
2857 if(m_solver->c_noChildren(i) > 0 || m_solver->a_isHalo(i)) continue;
2858
2859 MFloat cellHalfLength = m_solver->c_cellLengthAtLevel(m_solver->a_level(i) + 1);
2860 const MFloat* const coordinates = &(m_solver->a_coordinate(i, 0));
2861
2862 std::array<MFloat, nDim> edge;
2863
2864 // fill edge and projection dist = edge * normal (which is normalized)
2865 MFloat prodist = 0.0;
2866 MFloat dist = 0.0;
2867 for(MInt d = 0; d < nDim; d++) {
2868 edge[d] = coordinates[d] - m_localReCutPoint[d];
2869 prodist += edge[d] * m_localReCutNormal[d];
2870 dist += edge[d] * edge[d];
2871 }
2872
2873 dist = sqrt(dist);
2874
2875 if(fabs(prodist) < cellHalfLength && dist <= m_localReCutDistance) m_localReCutCells.push_back(i);
2876 }
2877 m_log << " = no of cells for this domain: " << m_localReCutCells.size() << endl;
2878 m_hasLocalReCut = (m_localReCutCells.size() > 0);
2879
2880 // does this domain have the according BC?
2881 MBool has_bc4073 = false;
2882 for(MInt i = 0; i < (MInt)(m_bndCndIds.size()); i++)
2883 if(m_bndCndIds[i] == 4073 && m_mapSegIdsInOutCnd[i] != -1 && m_bndCndSegIds[i] == segId) {
2884 has_bc4073 = true;
2885 break;
2886 }
2887
2888 m_allDomainsHaveBC[BCCounter][m_solver->domainId()] = m_hasLocalReCut ? m_localReCutCells.size() : -1;
2889
2890 if(m_allDomainsHaveBC[BCCounter][m_solver->domainId()] == -1 && has_bc4073)
2891 m_allDomainsHaveBC[BCCounter][m_solver->domainId()] = 0;
2892
2893 // unfortunately a global communication is requried
2894 MInt* const sndBuf = &(m_allDomainsHaveBC[BCCounter][m_solver->domainId()]);
2895 MPI_Allgather(sndBuf, 1, MPI_INT, m_allDomainsHaveBC[BCCounter], 1, MPI_INT, m_solver->mpiComm(), AT_, "sndBuf",
2896 "m_allDomainsHaveBC");
2897
2898 std::vector<MInt> BCneighborsPerSeg;
2899
2900 m_totalNoDomainsReCut = 0;
2901 m_totalNoBcCells[BCCounter] = 0;
2902 for(MInt i = 0; i < m_solver->noDomains(); i++)
2903 if(m_allDomainsHaveBC[BCCounter][i] != -1) {
2904 BCneighborsPerSeg.push_back(i);
2905 if(m_allDomainsHaveBC[BCCounter][i] > 0) {
2906 m_totalNoDomainsReCut++;
2907 m_totalNoBcCells[BCCounter] += m_allDomainsHaveBC[BCCounter][i];
2908 }
2909 }
2910
2911 m_BCneighbors.push_back(BCneighborsPerSeg);
2912 m_noBCNeighbors[BCCounter] = (MInt)m_BCneighbors[BCCounter].size();
2913
2914 m_firstBCinComm = 0;
2915 if(m_noBCNeighbors[BCCounter] > 0) m_firstBCinComm = m_BCneighbors[BCCounter][0];
2916
2917 MIntScratchSpace ptBCneighbors(m_noBCNeighbors[BCCounter], AT_, "ptBCneighbors");
2918 for(MInt i = 0; i < m_noBCNeighbors[BCCounter]; i++)
2919 ptBCneighbors.p[i] = m_BCneighbors[BCCounter][i];
2920
2921 // build a new communicator
2922 m_log << " * building MPI communicator" << endl;
2923 if(m_noBCNeighbors[BCCounter] != 0 && m_solver->noDomains() > 1) {
2924 // MPI_Group tmp_group, BCGroup;
2925
2926 MPI_Comm_group(m_solver->mpiComm(), &tmp_group[BCCounter], AT_, "tmp_group");
2927
2928 MPI_Group_incl(tmp_group[BCCounter], m_noBCNeighbors[BCCounter], ptBCneighbors.getPointer(), &BCGroup[BCCounter],
2929 AT_);
2930#ifdef MAIA_MPI_DEBUG
2931 MPI_Comm_create(m_solver->mpiComm(), BCGroup[BCCounter], &m_BCComm[BCCounter], AT_, "m_BCComm");
2932#else
2933 MPI_Comm_create(m_solver->mpiComm(), BCGroup[BCCounter], &m_BCComm[BCCounter], AT_, "m_BCComm");
2934#endif
2935 }
2936 if(m_calcBcResidual && m_solver->domainId() == m_firstBCinComm) {
2937 m_BCResidualStream[BCCounter].open(m_BCOutputFileName[BCCounter], ios_base::app);
2938
2939 if(!m_solver->m_restartFile)
2940 m_BCResidualStream[BCCounter] << "############################\n"
2941 << "# Order of appearance:\n"
2942 << "# 1: globalTimeStep\n"
2943 << "# 2: m_localReCutRe\n"
2944 << "# 3: l_Re\n"
2945 << "# 4: m_ReLast\n"
2946 << "# 5: Re_diff\n"
2947 << "# 6: m_lRho\n"
2948 << "# 7: m_rhoLast\n"
2949 << "# 8: m_deltaRho\n"
2950 << "############################\n"
2951 << endl;
2952 }
2953
2954 // special treatment for those domains that have a cut with the plane/line but do not contain any BC 4073 cells
2955 m_log << " * updating boundary condition list" << endl;
2956 if(!has_bc4073 && m_hasLocalReCut) {
2957 // we need to add bc4073
2958 m_bndCndIds.push_back(4073);
2959 m_bndCndOffsets.push_back(m_bndCndOffsets[m_bndCndOffsets.size() - 1]);
2960 // empty treatment
2961 m_bndCndSegIds.push_back(-1);
2962 m_mapSegIdsInOutCnd.push_back(-1);
2963
2964 m_log << " + created new BC 4073" << endl;
2965 }
2966
2967 m_log << " * update interval: " << m_localReCutInterval << endl;
2968 m_log << " * update percentage: " << m_localReCutAdpPerc << endl;
2969 m_log << " * report interval: " << m_localReCutReportInterval << endl;
2970 m_log << " * point: ";
2971 for(MInt i = 0; i < nDim; i++)
2972 m_log << m_localReCutPoint[i] << " ";
2973 m_log << endl;
2974 m_log << " * distance: " << m_localReCutDistance << endl;
2975 m_log << " * normal: ";
2976 for(MInt i = 0; i < nDim; i++)
2977 m_log << m_localReCutNormal[i] << " ";
2978 m_log << endl;
2979 m_log << " * target Re: " << m_localReCutRe
2980 << (approx(m_localReCutRe, m_solver->m_Re, MFloatEps) ? " (same as global Re)" : " (different than global Re)")
2981 << endl;
2982 m_log << " * reference length " << m_localReCutDiameter
2983 << (approx(m_localReCutDiameter, m_referenceLength, MFloatEps) ? " (same as global ref. length)"
2984 : " (different than global ref. length)")
2985 << endl;
2986 m_log << " * local cut: " << (m_hasLocalReCut ? "yes" : "no") << endl;
2987 m_log << " * no. cut cells: " << m_localReCutCells.size() << endl;
2988 m_log << " * no. total cut cells: " << m_totalNoBcCells[BCCounter] << endl;
2989 m_log << " * domain owns BC: " << (has_bc4073 ? "yes" : "no") << endl;
2990 m_log << " * no. domains cut: " << m_totalNoDomainsReCut << endl;
2991 m_log << " * no. comm. domains: " << m_noBCNeighbors[BCCounter] << endl;
2992 m_log << " * first comm. domain: " << m_firstBCinComm << endl;
2993 m_log << " * comm. domains: ";
2994 for(MInt i = 0; i < m_noBCNeighbors[BCCounter]; i++)
2995 m_log << m_BCneighbors[BCCounter][i] << " ";
2996 m_log << endl;
2997 if(m_solver->m_restartFile) {
2998 m_log << " * restart details: " << endl;
2999 m_log << " > rho1: " << m_solver->m_rho1 << endl;
3000 m_log << " > lRho: " << m_lRho << endl;
3001 m_log << " > rhoLast: " << m_rhoLast << endl;
3002 m_log << " > deltaRho: " << m_deltaRho << endl;
3003 m_log << " > ReLast: " << m_ReLast << endl;
3004 }
3005 m_log << endl;
3006}
3007
3008
3019template <MInt nDim>
3021 TRACE();
3022
3023 NEW_SUB_TIMER(t_setBCNC, "set BC neighbor communicators", m_t_BCAll);
3024 RECORD_TIMER_START(t_setBCNC);
3025
3026 // first of all check if we have a BC which requries communication
3027 m_numberOfCommBCs = checkForCommBC();
3028 if(m_numberOfCommBCs == 0) {
3029 RECORD_TIMER_STOP(t_setBCNC);
3030 return;
3031 }
3032
3033 mAlloc(m_allDomainsHaveBC, m_numberOfCommBCs, m_solver->noDomains(), "m_allDomainsHaveBC", 0, AT_);
3034 mAlloc(m_noBCNeighbors, m_numberOfCommBCs, "m_noBCNeighbors", 0, AT_);
3035 mAlloc(m_totalNoBcCells, m_numberOfCommBCs, "m_totalNoBcCells", 0, AT_);
3036
3037 mAlloc(tmp_group, m_numberOfCommBCs, "tmp_group", AT_);
3038 mAlloc(BCGroup, m_numberOfCommBCs, "BCGroup", AT_);
3039 mAlloc(m_BCComm, m_numberOfCommBCs, "m_BCComm", AT_);
3040
3041 if(m_calcBcResidual) mAlloc(m_BCResidualStream, m_numberOfCommBCs, "m_BCResidualStream", AT_);
3042 mAlloc(m_BCOutputFileName, m_numberOfCommBCs, "m_BCOutputFileName", AT_);
3043
3044 if((MInt)(m_bndCndIds.size()) > 0)
3045 mAlloc(m_mapBndCndIdSegId, (MInt)(m_bndCndIds.size()), "m_mapBndCndIdSegId", 0, AT_);
3046
3047 m_log << " + Found a BC which requires communication:" << endl;
3048
3049 MInt counterCommBC = 0;
3050
3051 for(MInt segId = 0; segId < m_noAllBoundaryIds; segId++) {
3052 stringstream s;
3053 MBool found = false;
3054 switch(m_allBoundaryIds[segId]) {
3055 case 1000: {
3056 s << "Output_SegNo_" << segId << "_BC_" << 1000 << ".dat";
3057 m_BCOutputFileName[counterCommBC] = s.str();
3058 prepareBC(1000, counterCommBC, segId);
3059 found = true;
3060 break;
3061 }
3062 case 1022: {
3063 s << "Output_SegNo_" << segId << "_BC_" << 1022 << ".dat";
3064 m_BCOutputFileName[counterCommBC] = s.str();
3065 prepareBC(1022, counterCommBC, segId);
3066 found = true;
3067 break;
3068 }
3069 case 1060: {
3070 s << "Output_SegNo_" << segId << "_BC_" << 1060 << ".dat";
3071 m_BCOutputFileName[counterCommBC] = s.str();
3072 prepareBC(1060, counterCommBC, segId);
3073 found = true;
3074 break;
3075 }
3076 case 1080: {
3077 s << "Output_SegNo_" << segId << "_BC_" << 1080 << ".dat";
3078 m_BCOutputFileName[counterCommBC] = s.str();
3079 prepareBC(1080, counterCommBC, segId);
3080 found = true;
3081 break;
3082 }
3083 case 4000: {
3084 s << "Output_SegNo_" << segId << "_BC_" << 4000 << ".dat";
3085 m_BCOutputFileName[counterCommBC] = s.str();
3086 prepareBC(4000, counterCommBC, segId);
3087 found = true;
3088 break;
3089 }
3090 case 4030: {
3091 s << "Output_SegNo_" << segId << "_BC_" << 4030 << ".dat";
3092 m_BCOutputFileName[counterCommBC] = s.str();
3093 prepareBC(4030, counterCommBC, segId);
3094 found = true;
3095 break;
3096 }
3097 case 4130: {
3098 s << "Output_SegNo_" << segId << "_BC_" << 4130 << ".dat";
3099 m_BCOutputFileName[counterCommBC] = s.str();
3100 prepareBC(4130, counterCommBC, segId);
3101 found = true;
3102 break;
3103 }
3104 case 4070: {
3105 s << "Output_SegNo_" << segId << "_BC_" << 4070 << ".dat";
3106 m_BCOutputFileName[counterCommBC] = s.str();
3107 prepareBC(4070, counterCommBC, segId);
3108 found = true;
3109 break;
3110 }
3111 case 4071: {
3112 s << "Output_SegNo_" << segId << "_BC_" << 4071 << ".dat";
3113 m_BCOutputFileName[counterCommBC] = s.str();
3114 prepareBC(4071, counterCommBC, segId);
3115 found = true;
3116 break;
3117 }
3118 case 4072: {
3119 s << "Output_SegNo_" << segId << "_BC_" << 4072 << ".dat";
3120 m_BCOutputFileName[counterCommBC] = s.str();
3121 prepareBC(4072, counterCommBC, segId);
3122 found = true;
3123 break;
3124 }
3125 case 4073: {
3126 s << "Output_SegNo_" << segId << "_BC_" << 4073 << ".dat";
3127 m_BCOutputFileName[counterCommBC] = s.str();
3128 prepareBC4073(counterCommBC, segId);
3129 found = true;
3130 break;
3131 }
3132 case 4080: {
3133 s << "Output_SegNo_" << segId << "_BC_" << 4080 << ".dat";
3134 m_BCOutputFileName[counterCommBC] = s.str();
3135 prepareBC(4080, counterCommBC, segId);
3136 found = true;
3137 break;
3138 }
3139 case 4081: {
3140 s << "Output_SegNo_" << segId << "_BC_" << 4081 << ".dat";
3141 m_BCOutputFileName[counterCommBC] = s.str();
3142 prepareBC(4081, counterCommBC, segId);
3143 found = true;
3144 break;
3145 }
3146 case 4082: {
3147 s << "Output_SegNo_" << segId << "_BC_" << 4082 << ".dat";
3148 m_BCOutputFileName[counterCommBC] = s.str();
3149 prepareBC(4082, counterCommBC, segId);
3150 found = true;
3151 break;
3152 }
3153 case 4110: {
3154 s << "Output_SegNo_" << segId << "_BC_" << 4110 << ".dat";
3155 m_BCOutputFileName[counterCommBC] = s.str();
3156 prepareBC(4110, counterCommBC, segId);
3157 found = true;
3158 break;
3159 }
3160 default: {
3161 }
3162 }
3163
3164 if(found) {
3165 counterCommBC++;
3166 }
3167 }
3168
3169 RECORD_TIMER_STOP(t_setBCNC);
3170}
3171
3173template <MInt nDim>
3175 TRACE();
3176
3177 for(MInt i = 0; i < (MInt)(m_bndCndIds.size()); i++) {
3178 (this->*bndCndHandlerVariables[i])(i);
3179 }
3180}
3181
3182
3184template <MInt nDim>
3186 TRACE();
3187 for(MInt i = 0; i < (MInt)(m_bndCndIds.size()); i++) {
3188 (this->*bndCndHandlerRHS[i])(i);
3189 }
3190}
3191
3206template <MInt nDim>
3208 TRACE();
3209
3210 NEW_SUB_TIMER(t_createBCCells, "create boundary cells", m_t_BCAll);
3211 RECORD_TIMER_START(t_createBCCells);
3212
3213 MInt bndCellsIt = 0, bndCellsIt2 = 0;
3214 MFloat cellHalfLength = 0.0;
3215 ScratchSpace<MFloat> target(2 * nDim, AT_, "target");
3216
3217 m_log << " + Creating boundary cells..." << endl;
3218 m_log << " - Multiple BC treatment: " << m_multiBCTreatment << endl;
3219
3220 // This temporary, has to be filled into m_bndCells later on
3221 for(MInt i = 0; i < m_solver->m_cells.size(); i++) {
3222 // skip inActive cells (neither leaf nor interfaceParent)
3223 if(!m_solver->c_isLeafCell(i) && !m_solver->a_isInterfaceParent(i)) continue;
3224
3225 // Define corners of current cell in target
3226 for(MInt j = 0; j < nDim; j++) {
3227 cellHalfLength = m_solver->c_cellLengthAtLevel(m_solver->a_level(i) + 1);
3228 target[j] = m_solver->a_coordinate(i, j) - cellHalfLength;
3229 target[j + nDim] = m_solver->a_coordinate(i, j) + cellHalfLength;
3230 }
3231
3232 // Check for intersection with geometry elements
3233 MFloat* targetPtr = &target[0];
3234 std::vector<MInt> nodeList;
3235 if(m_gridCutTest == "SAT")
3236 m_solver->m_geometry->getIntersectionElements(targetPtr, nodeList, cellHalfLength, &m_solver->a_coordinate(i, 0));
3237 else
3238 m_solver->m_geometry->getIntersectionElements(targetPtr, nodeList);
3239 const MInt noNodes = nodeList.size();
3240
3241 if(noNodes > 0) {
3242 m_solver->a_onlyBoundary(i) = true;
3243 m_solver->a_isBndryCell(i) = true;
3244
3245 // Create a new boundary cell for our found cuts
3246 m_bndCells.emplace_back();
3247
3248 bndCellsIt = m_bndCells.size() - 1;
3249 m_bndCells[bndCellsIt].m_cellId = i;
3250
3251 // Fill the segmentIds of the boundary cell
3252 for(MInt j = 0; j < noNodes; j++) {
3253 MBool already_in = false;
3254 for(MInt k = 0; k < (MInt)(m_bndCells[bndCellsIt].m_segmentId.size()); k++)
3255 if(m_bndCells[bndCellsIt].m_segmentId[k] == m_solver->m_geometry->elements[nodeList[j]].m_segmentId) {
3256 already_in = true;
3257 break;
3258 }
3259 if(!already_in) {
3260 m_bndCells[bndCellsIt].m_segmentId.push_back(m_solver->m_geometry->elements[nodeList[j]].m_segmentId);
3261 m_bndCells[bndCellsIt].m_bndCndId.push_back(m_solver->m_geometry->elements[nodeList[j]].m_bndCndId);
3262 }
3263 }
3264
3265 if(m_bndCells[bndCellsIt].m_segmentId.size() > 1) {
3266 // exists inout / wall / periodic ?
3267 MInt positions[3] = {-1, -1, -1};
3268
3269 for(MInt j = 0; j < (MInt)(m_bndCells[bndCellsIt].m_segmentId.size()); j++) {
3270 MBool is_inout = false;
3271 MBool is_periodic = false;
3272
3273 for(MInt k = 0; k < m_noInOutSegments; k++)
3274 if(m_bndCells[bndCellsIt].m_segmentId[j] == m_inOutSegmentsIds[k]) {
3275 is_inout = true;
3276 break;
3277 }
3278 if(m_noPeriodicSegments != 0)
3279 for(MInt k = 0; k < m_noPeriodicSegments; k++)
3280 if(m_bndCells[bndCellsIt].m_segmentId[j] == m_periodicSegmentsIds[k]) {
3281 is_periodic = true;
3282 break;
3283 }
3284 if(is_inout)
3285 positions[0] = j;
3286 else if(!is_inout && !is_periodic)
3287 positions[1] = j;
3288 else if(is_periodic)
3289 positions[2] = j;
3290 }
3291
3292 MInt swap_pos = 0;
3293 if(m_multiBCTreatment == "W-P-I") {
3294 // Make wall first (if exists)
3295 if(positions[1] != -1) swap_pos = positions[1];
3296 // Make periodic first (if exists)
3297 else if(positions[2] != -1)
3298 swap_pos = positions[2];
3299
3300 } else if(m_multiBCTreatment == "W-I-P") {
3301 // Make wall first (if exists)
3302 if(positions[1] != -1) swap_pos = positions[1];
3303 // Make inout first (if exists)
3304 else if(positions[0] != -1)
3305 swap_pos = positions[0];
3306 } else if(m_multiBCTreatment == "I-W-P") {
3307 // Make inout first (if exists)
3308 if(positions[0] != -1) swap_pos = positions[0];
3309 // Make wall first (if exists)
3310 else if(positions[1] != -1)
3311 swap_pos = positions[1];
3312 } else if(m_multiBCTreatment == "I-P-W") {
3313 // Make inout first (if exists)
3314 if(positions[0] != -1) swap_pos = positions[0];
3315 // Make periodic first (if exists)
3316 else if(positions[2] != -1)
3317 swap_pos = positions[2];
3318 } else if(m_multiBCTreatment == "P-W-I") {
3319 // Make periodic first (if exists)
3320 if(positions[2] != -1) swap_pos = positions[2];
3321 // Make wall first (if exists)
3322 else if(positions[1] != -1)
3323 swap_pos = positions[1];
3324 } else if(m_multiBCTreatment == "P-I-W") {
3325 // Make periodic first (if exists)
3326 if(positions[2] != -1) swap_pos = positions[2];
3327 // Make inout first (if exists)
3328 else if(positions[0] != -1)
3329 swap_pos = positions[0];
3330 }
3331
3332 /********************************/
3333 /* Georg 24.06.2010 */
3334 /* */
3335 /********************************/
3336 else if(m_multiBCTreatment == "multiple") {
3337 // Add the bndCell n more times according to the number of different bc's.
3338 // No sorting of segmentIds is applied.
3339
3340 bndCellsIt2 = bndCellsIt;
3341 for(MInt j = 1; j < (MInt)(m_bndCells[bndCellsIt].m_segmentId.size()); j++) {
3342 // make sure that m_bndCells are only added if there is another bc
3343 MBool already_in = false;
3344 for(MInt k = 0; k <= (bndCellsIt2 - bndCellsIt); k++) {
3345 if(m_bndCells[bndCellsIt].m_bndCndId[bndCellsIt2 - bndCellsIt] == m_bndCells[bndCellsIt].m_bndCndId[j]) {
3346 already_in = true;
3347 break;
3348 }
3349 }
3350
3351 if(!already_in) {
3352 bndCellsIt2++;
3353 m_bndCells.emplace_back(); // add new m_bndCells
3354 m_bndCells[bndCellsIt2].m_cellId = i; // new m_bndCells has the same cellId as the previous one
3355
3356 m_bndCells[bndCellsIt2].m_segmentId.push_back(m_bndCells[bndCellsIt].m_segmentId[j]);
3357 m_bndCells[bndCellsIt2].m_bndCndId.push_back(m_bndCells[bndCellsIt].m_bndCndId[j]);
3358
3359 // m_bndCells[bndCellsIt2].m_segmentId[0] = m_bndCells[bndCellsIt].m_segmentId[j];
3360 // m_bndCells[bndCellsIt2].m_bndCndId[0] = m_bndCells[bndCellsIt].m_bndCndId[j];
3361 }
3362 }
3363 }
3364
3365 MInt tmp = m_bndCells[bndCellsIt].m_segmentId[0];
3366 m_bndCells[bndCellsIt].m_segmentId[0] = m_bndCells[bndCellsIt].m_segmentId[swap_pos];
3367 m_bndCells[bndCellsIt].m_segmentId[swap_pos] = tmp;
3368
3369 tmp = m_bndCells[bndCellsIt].m_bndCndId[0];
3370 m_bndCells[bndCellsIt].m_bndCndId[0] = m_bndCells[bndCellsIt].m_bndCndId[swap_pos];
3371 m_bndCells[bndCellsIt].m_bndCndId[swap_pos] = tmp;
3372 }
3373 }
3374 }
3375
3376 m_log << " - noBndCells: " << m_bndCells.size() << endl << endl;
3377
3378 for(auto& bndCell : m_bndCells) {
3379 bndCell.m_multiplier = 1.0;
3380 }
3381
3382 RECORD_TIMER_STOP(t_createBCCells);
3383}
3384
3389template <MInt nDim>
3391 // Initialize BC
3392 for(MInt i = 0; i < (MInt)(m_bndCndIds.size()); i++) {
3393 (this->*bndCndInitiator[i])(i);
3394 }
3395 if(!m_solver->m_restartFile) {
3396 for(auto p : m_bndCndData) {
3397 const MInt& p_index = p.first;
3398 const LbBndCndData& p_data = p.second;
3399 const MInt bndCndOffset = m_bndCndOffsets[p_index];
3400 for(MInt i = 0; i < p_data.noBndCellsWithHalos; i++) {
3401 for(MInt j = 0; j < p_data.noVars; j++) {
3402 p_data.data[i * p_data.noVars + j] = m_solver->a_oldVariable(m_bndCells[i + bndCndOffset].m_cellId, j);
3403 }
3404 }
3405 }
3406 }
3407}
3408
3415template <MInt nDim>
3417 TRACE();
3418
3419 if(!m_calcWallForces) return;
3420
3421 if(!m_solver->grid().isActive()) {
3422 return;
3423 }
3424
3425 if(m_solver->noDomains() > 1) {
3426 if( (m_BCWallMBComm != MPI_COMM_NULL)) {
3427 MPI_Comm_free(&m_BCWallMBComm, AT_, "m_BCWallMBComm");
3428 }
3429
3430 m_allDomainsCalcForceMB[m_solver->domainId()] = m_solver->m_currentNoG0Cells;
3431
3432 if(!m_BCWallMBNeighbors.empty()) m_BCWallMBNeighbors.clear();
3433
3434 // unfortunately a global communication is requried
3435 MInt* const sndBuf = &(m_allDomainsCalcForceMB[m_solver->domainId()]);
3436 MPI_Allgather(sndBuf, 1, MPI_INT, m_allDomainsCalcForceMB, 1, MPI_INT, m_solver->mpiComm(), AT_, "sendBuf",
3437 "m_allDomainsCalcForceMB");
3438
3439 // for(MInt count = 0; count < m_solver->noDomains(); count++) {
3440 // if(m_allDomainsCalcForceMB[count] != 0)
3441 // m_log << " Domain[" << count << "] carries " << m_allDomainsCalcForceMB[count] << " MB cells. " <<
3442 // endl;
3443 // }
3444 for(MInt i = 0; i < m_solver->noDomains(); i++) {
3445 if(m_allDomainsCalcForceMB[i] > 0) {
3446 m_BCWallMBNeighbors.push_back(i);
3447 }
3448 }
3449
3450 m_noBCWallMBNeighbors = (MInt)m_BCWallMBNeighbors.size();
3451
3452 MIntScratchSpace ptBCWallMBNeighbors(m_noBCWallMBNeighbors, AT_, "ptBCWallMBNeighbors");
3453 for(MInt i = 0; i < m_noBCWallMBNeighbors; i++)
3454 ptBCWallMBNeighbors[i] = m_BCWallMBNeighbors[i];
3455
3456 // build a new communicator
3457 if(m_noBCWallMBNeighbors != 0) {
3458 MPI_Group tmp_groupMB, BCGroupMB;
3459 MPI_Comm_group(m_solver->mpiComm(), &tmp_groupMB, AT_, "tmp_groupMB");
3460 MPI_Group_incl(tmp_groupMB, m_noBCWallMBNeighbors, ptBCWallMBNeighbors.getPointer(), &BCGroupMB, AT_);
3461
3462 MPI_Comm_create(m_solver->mpiComm(), BCGroupMB, &m_BCWallMBComm, AT_, "m_BCWallMBComm");
3463 MPI_Group_free(&tmp_groupMB, AT_);
3464 MPI_Group_free(&BCGroupMB, AT_);
3465 if(m_solver->domainId() == m_BCWallMBNeighbors[0]) {
3466 m_forceFile = "forcesMB.log";
3467 // Write header
3468 std::FILE* forceFile;
3469 forceFile = fopen(m_forceFile.c_str(), "a+");
3470 fprintf(forceFile, "# Re=%f, Ma=%f, refLength_LB=%f, dx(maxLvl)=%e\n", m_solver->m_Re, m_solver->m_Ma,
3471 m_solver->m_referenceLength, m_solver->c_cellLengthAtLevel(m_solver->maxLevel()));
3472 fprintf(forceFile, "#");
3473 fprintf(forceFile, "%s\t", "1:timeStep");
3474 constexpr MInt columnLength = 15;
3475 fprintf(forceFile, "%*s\t", columnLength, "2:F_x");
3476 fprintf(forceFile, "%*s\t", columnLength, "3:F_y");
3477 if(nDim == 3) {
3478 fprintf(forceFile, "%*s\t", columnLength, "4:F_z");
3479 }
3480 fprintf(forceFile, "\n");
3481 fclose(forceFile);
3482 }
3483 }
3484
3485 } else {
3486 m_noBCWallMBNeighbors = 1;
3487 m_BCWallMBNeighbors.push_back(m_solver->domainId());
3488 }
3489}
3490
3491
3497template <MInt nDim>
3499 TRACE();
3500
3501 //#####################################################################
3502 // Allocate space for pointer lists which store the boundary functions
3503 //#####################################################################
3504
3505 m_log << " + Setting the boundary condition handler for LB_LS..." << endl << endl;
3506 bndCndHandlerVariables_MB.resize(1);
3507 bndCndHandlerVariables_MB[0] = &LbBndCnd::bc0;
3508 bndCndHandlerRHS_MB.resize(1);
3509 // TODO labels:LB,toenhance Generalize the configuration of mb bnd cnd
3510 // Use real boundary conditions for InitGFieldFromSTL stls ??
3511 bndCndHandlerRHS_MB[0] = &LbBndCnd::bc66666;
3512 /*if(m_solver->m_bernoulliBeam)
3513 bndCndHandlerRHS_MB[0] = &LbBndCnd::bc66667;*/
3514 // Free surface
3515 // bndCndHandlerRHS_MB[0] = &LbBndCnd::bc66668;
3516
3517 //#####################################################################
3518 // Allocation of all lists needed
3519 // Setting the required constants
3520 //#####################################################################
3521
3522 // Create Communicator
3523 mAlloc(m_allDomainsCalcForceMB, m_solver->noDomains(), "m_allDomainsCalcForceMB", 0, AT_);
3524
3525 //#####################################################################
3526 // Create Communicator
3527 //#####################################################################
3528
3529 m_BCWallMBComm = MPI_COMM_NULL;
3530}
3531
3537template <MInt nDim>
3539 if(!m_solver->grid().isActive()) {
3540 return;
3541 }
3542
3543 const MInt startSet = m_solver->m_levelSetId;
3544 for(MInt set = startSet; set < m_solver->m_maxNoSets; set++) {
3545 (this->*bndCndHandlerVariables_MB[0])(set);
3546 (this->*bndCndHandlerRHS_MB[0])(set);
3547 }
3548}
3549
3550// Explicit instantiations for 2D and 3D
3551template class LbBndCnd<2>;
3552template class LbBndCnd<3>;
void mAlloc(T *&a, const MLong N, const MString &objectName, MString function)
allocates memory for one-dimensional array 'a' of size N
Definition: alloc.h:173
MBool mDeallocate(T *&a)
deallocates the memory previously allocated for element 'a'
Definition: alloc.h:544
MFloat ** m_vertices
virtual void bc20051(MInt)
Definition: lbbndcnd.h:297
virtual void initializeBndMovingBoundaries()
This function initializes the LbBndCnd for coupled simulations.
Definition: lbbndcnd.cpp:3498
void calculateBndNormals()
Definition: lbbndcnd.cpp:1279
virtual void updateVariables()
Dereferences bndCndHandlerVariables.
Definition: lbbndcnd.cpp:3174
virtual void setBCWallNeighborCommunicator()
Sets up a neighbor-communicator for certain BCs.
Definition: lbbndcnd.cpp:2437
MBool calculateNormalFromTriangle(GeometryElement< nDim > ge, MFloat *normal)
Calculate the normal based on a triangle.
Definition: lbbndcnd.cpp:803
virtual void bc30042(MInt)
Definition: lbbndcnd.h:328
virtual void bc20227(MInt)
Definition: lbbndcnd.h:280
virtual void createMBComm()
This function creates the communicator for calculating the wall forces of the level-set boundaries.
Definition: lbbndcnd.cpp:3416
virtual void bc10041(MInt)
Definition: lbbndcnd.h:251
virtual void bc10002(MInt)
Definition: lbbndcnd.h:245
virtual MInt checkForCommBC()
Checks if a BC exists that requires communication.
Definition: lbbndcnd.cpp:2569
virtual void bc40043(MInt)
Definition: lbbndcnd.h:344
virtual void bc30013(MInt)
Definition: lbbndcnd.h:308
virtual void bc10010(MInt)
Definition: lbbndcnd.h:248
virtual void bcIBBNeumannInit(MInt)
Definition: lbbndcnd.h:285
virtual void prepareBC2000()
Prepares the BC 4072.
Definition: lbbndcnd.cpp:2486
virtual void bc40073(MInt)
Definition: lbbndcnd.h:354
virtual void normalParallelGeomNormals3D(std::vector< std::pair< MInt, MInt > > own_segments)
Definition: lbbndcnd.cpp:1097
virtual void prepareBC4073(MInt BCCounter, MInt segId)
Definition: lbbndcnd.cpp:2728
virtual void bc30023(MInt)
Definition: lbbndcnd.h:315
virtual void bc40046(MInt)
Definition: lbbndcnd.h:347
virtual void bc20228(MInt)
Definition: lbbndcnd.h:281
virtual void bc30012(MInt)
Definition: lbbndcnd.h:307
virtual void bc10022(MInt)
Definition: lbbndcnd.h:247
virtual void bc30024(MInt)
Definition: lbbndcnd.h:316
virtual void bc20002(MInt)
Definition: lbbndcnd.h:270
virtual ~LbBndCnd()
The destructor.
Definition: lbbndcnd.cpp:347
virtual void bc40072_40082_init(MInt)
Definition: lbbndcnd.h:359
virtual void bc20005(MInt)
Definition: lbbndcnd.h:273
virtual void bc10040(MInt)
Definition: lbbndcnd.h:250
virtual void bc20022(MInt)
Definition: lbbndcnd.h:287
virtual void bc20001(MInt)
Definition: lbbndcnd.h:269
virtual void bc20006(MInt)
Definition: lbbndcnd.h:274
virtual void setBCNeighborCommunicator()
Sets up a neighbor-communicator for certain BCs.
Definition: lbbndcnd.cpp:3020
virtual void bc40040(MInt)
Definition: lbbndcnd.h:341
virtual void bc40042(MInt)
Definition: lbbndcnd.h:343
virtual void bc30014(MInt)
Definition: lbbndcnd.h:309
virtual void bc20226(MInt)
Definition: lbbndcnd.h:279
virtual void calculateAveragedNormalAndCenter(MInt segmentId, MFloat *const normal, MFloat *const center)
Definition: lbbndcnd.cpp:882
virtual void bc20501_init(MInt)
Definition: lbbndcnd.h:283
virtual void bc0(MInt)
Definition: lbbndcnd.h:241
virtual void calculateVectors()
virtual void bc10000(MInt)
Definition: lbbndcnd.h:243
virtual void processAngles()
Definition: lbbndcnd.cpp:382
virtual void bc30030(MInt)
Definition: lbbndcnd.h:319
virtual void setBndCndHandler()
Sets the BndCndHandler objects at solver setup.
Definition: lbbndcnd.cpp:1786
virtual void bc10044(MInt)
Definition: lbbndcnd.h:254
virtual void bc30022(MInt)
Definition: lbbndcnd.h:314
virtual void bc20010(MInt)
Definition: lbbndcnd.h:275
virtual void bc66666(MInt)
Definition: lbbndcnd.h:370
virtual void bc30043(MInt)
Definition: lbbndcnd.h:329
virtual void bc20220(MInt)
Definition: lbbndcnd.h:277
virtual void bc30000(MInt)
Definition: lbbndcnd.h:303
virtual void bc20000(MInt)
Definition: lbbndcnd.h:268
void bcDataReadRestartData(ParallelIo &parallelIo)
Read bndCndData data in given ParallelIo file.
Definition: lbbndcnd.cpp:1511
virtual void updateRHS()
Dereferences bndCndHandlerRHS.
Definition: lbbndcnd.cpp:3185
virtual void bc30040(MInt)
Definition: lbbndcnd.h:326
virtual void bc10111(MInt)
Definition: lbbndcnd.h:368
virtual void bc40071(MInt)
Definition: lbbndcnd.h:352
virtual void bc10090(MInt)
Definition: lbbndcnd.h:262
virtual void createBoundaryCells()
Creates boundary cells according to the geometry information.
Definition: lbbndcnd.cpp:3207
virtual void bc10060(MInt)
Definition: lbbndcnd.h:259
virtual void bc40072(MInt)
Definition: lbbndcnd.h:353
virtual void bc40030(MInt)
Definition: lbbndcnd.h:339
void bcDataAllocate(MInt index, MInt noVars)
Allocate data for given boundary index.
Definition: lbbndcnd.cpp:1404
virtual void bc20024(MInt)
Definition: lbbndcnd.h:289
virtual void prepareBC(MInt index, MInt BCCounter, MInt segId)
Prepares the BC 4070, 4071, 4072, 4080, 4081, and 4082.
Definition: lbbndcnd.cpp:2669
virtual void bc40120(MInt)
Definition: lbbndcnd.h:364
virtual void bc40110(MInt)
Definition: lbbndcnd.h:362
virtual void bc40070(MInt)
Definition: lbbndcnd.h:351
virtual void bc10004(MInt)
Definition: lbbndcnd.h:246
virtual MBool checkForCommForce()
Checks if a BC exists that requires communication.
Definition: lbbndcnd.cpp:2407
virtual void bc40080(MInt)
Definition: lbbndcnd.h:355
virtual void bc20050(MInt)
Definition: lbbndcnd.h:296
virtual void bc40081(MInt)
Definition: lbbndcnd.h:356
void initializeBcData()
Initialize BC data variables.
Definition: lbbndcnd.cpp:3390
virtual void printBndVelInfo()
This function prints the gathered information on the boundary vectors and the initial velocity vector...
Definition: lbbndcnd.cpp:551
void applyDirectionChangeInflow(MInt index)
This function checks if for an inflow boundary the normal points into the according direction and cha...
Definition: lbbndcnd.cpp:1564
virtual void bc10001(MInt)
Definition: lbbndcnd.h:244
void sortBoundaryCells()
This function sorts the boundary cells according to the BC id.
Definition: lbbndcnd.cpp:1702
virtual void bc30034(MInt)
Definition: lbbndcnd.h:323
virtual void fastParallelGeomNormals3D(std::vector< std::pair< MInt, MInt > > own_segments)
Definition: lbbndcnd.cpp:963
virtual void bc30041(MInt)
Definition: lbbndcnd.h:327
virtual void bc20023(MInt)
Definition: lbbndcnd.h:288
virtual void bc30050(MInt)
Definition: lbbndcnd.h:333
virtual void bc40020(MInt)
Definition: lbbndcnd.h:338
virtual void bc20025(MInt)
Definition: lbbndcnd.h:290
virtual void bc40044(MInt)
Definition: lbbndcnd.h:345
virtual void bc30031(MInt)
Definition: lbbndcnd.h:320
virtual void bc20055(MInt)
Definition: lbbndcnd.h:301
virtual void bc40010(MInt)
Definition: lbbndcnd.h:337
virtual void initMembers()
virtual void updateBndNormals(MInt segId, MBool inside, MFloat *avg_normal)
Updates the normals of an inlet/outlet based on inside / outside detection.
Definition: lbbndcnd.cpp:1364
virtual void bc30010(MInt)
Definition: lbbndcnd.h:305
virtual void bc20052(MInt)
Definition: lbbndcnd.h:298
virtual void bc30015(MInt)
Definition: lbbndcnd.h:310
virtual void bc30033(MInt)
Definition: lbbndcnd.h:322
virtual void bc20501(MInt)
Definition: lbbndcnd.h:282
virtual void bc40041(MInt)
Definition: lbbndcnd.h:342
virtual void bc20053(MInt)
Definition: lbbndcnd.h:299
virtual void bc40060(MInt)
Definition: lbbndcnd.h:349
MBool getNormalFromSTL(GeometryElement< nDim > ge, MFloat *normal)
Get the normal from the STL.
Definition: lbbndcnd.cpp:851
virtual void bc30025(MInt)
Definition: lbbndcnd.h:317
virtual void bc10020(MInt)
Definition: lbbndcnd.h:249
virtual void bc10050(MInt)
Definition: lbbndcnd.h:258
void bcDataWriteRestartHeader(ParallelIo &parallelio)
Write bndCndData info in given ParallelIo file's header.
Definition: lbbndcnd.cpp:1428
void applyDirectionChangeOutflow(MInt index)
This function checks if for an outflow boundary the normal points into the according direction and ch...
Definition: lbbndcnd.cpp:1588
LbBndCnd(LbSolver< nDim > *solver)
virtual void bc30044(MInt)
Definition: lbbndcnd.h:330
virtual void bc40100(MInt)
Definition: lbbndcnd.h:361
virtual void bc30035(MInt)
Definition: lbbndcnd.h:324
virtual void bc10043(MInt)
Definition: lbbndcnd.h:253
virtual void bc30011(MInt)
Definition: lbbndcnd.h:306
virtual void bc40000(MInt)
Definition: lbbndcnd.h:335
virtual void bc20027(MInt)
Definition: lbbndcnd.h:292
virtual void bc10061(MInt)
Definition: lbbndcnd.h:260
virtual void bc20030(MInt)
Definition: lbbndcnd.h:293
virtual void bc30045(MInt)
Definition: lbbndcnd.h:331
virtual void bc40001(MInt)
Definition: lbbndcnd.h:336
virtual void bc20026(MInt)
Definition: lbbndcnd.h:291
virtual MInt findBndCnd(MInt index)
This function returns the index in the array of the boundary conditions that are inflow/outflow condi...
Definition: lbbndcnd.cpp:1388
virtual void bc10042(MInt)
Definition: lbbndcnd.h:252
virtual void postCouple()
This function does the sub coupling step called from the coupling class.
Definition: lbbndcnd.cpp:3538
virtual void bc10045(MInt)
Definition: lbbndcnd.h:255
virtual void bc20003(MInt)
Definition: lbbndcnd.h:271
void bcDataWriteRestartData(ParallelIo &parallelIo)
Write bndCndData data in given ParallelIo file.
Definition: lbbndcnd.cpp:1470
virtual void bc10046(MInt)
Definition: lbbndcnd.h:256
virtual void bc40082(MInt)
Definition: lbbndcnd.h:357
virtual void bc40130(MInt)
Definition: lbbndcnd.h:366
virtual void bc20054(MInt)
Definition: lbbndcnd.h:300
virtual void solveBlasiusZ(MInt index)
Solves the Blasius equation for f,f',f".
Definition: lbbndcnd.cpp:1614
virtual void bc30032(MInt)
Definition: lbbndcnd.h:321
virtual void bc10070(MInt)
Definition: lbbndcnd.h:264
virtual void bc30021(MInt)
Definition: lbbndcnd.h:313
virtual void bc30020(MInt)
Definition: lbbndcnd.h:312
virtual void bc20020(MInt)
Definition: lbbndcnd.h:276
virtual void bc20230(MInt)
Definition: lbbndcnd.h:294
virtual void bc10080(MInt)
Definition: lbbndcnd.h:266
virtual void bc20004(MInt)
Definition: lbbndcnd.h:272
virtual void bc40045(MInt)
Definition: lbbndcnd.h:346
This class is a ScratchSpace.
Definition: scratch.h:758
size_type size() const
Definition: scratch.h:302
T * getPointer() const
Deprecated: use begin() instead!
Definition: scratch.h:316
pointer p
Deprecated: use [] instead!
Definition: scratch.h:315
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
InfoOutFile m_log
std::vector< std::pair< MString, MInt > > g_tc_geometry
int32_t MInt
Definition: maiatypes.h:62
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
MInt id
Definition: maiatypes.h:71
int MPI_Comm_free(MPI_Comm *comm, const MString &name, const MString &varname)
same as MPI_Comm_free, but updates the number of MPI communicators
int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_create, but updates the number of MPI communicators
int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup, const MString &name)
same as MPI_Group_incl
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group, const MString &name, const MString &varname)
same as MPI_Comm_group
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
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather
int MPI_Group_free(MPI_Group *group, const MString &name)
same as MPI_Group_free
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
MInt noBndCellsWithHalos
number of boundary cells represented in data
Definition: lbbndcnd.h:29
MInt noVars
number of variables that are stored for BC
Definition: lbbndcnd.h:30
MFloat * data
pointer the relevant data
Definition: lbbndcnd.h:32
LB lattice descriptor for arrays depending on D.
static constexpr MInt idFld(MInt i, MInt j)
Definition: contexttypes.h:19