26 : m_noInternalCells(solver->grid().noInternalCells()),
27 m_solverId(solver->m_solverId),
29 m_noDistributions(solver->m_noDistributions),
30 m_methodId(solver->m_methodId),
32 m_referenceLength(solver->m_referenceLength),
33 m_domainLength(solver->m_domainLength),
34 m_densityFluctuations(solver->m_densityFluctuations),
35 m_pulsatileFrequency(solver->m_pulsatileFrequency) {
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);
41 RECORD_TIMER_START(t_BCAll);
46 m_log <<
"#########################################################################################################"
49 m_log <<
"## Boundary Conditions "
52 m_log <<
"#########################################################################################################"
58 m_Fext = solver->m_Fext;
60 m_gridCutTest =
"SAT";
61 m_gridCutTest = Context::getSolverProperty<MString>(
"gridCutTest", m_solverId, AT_, &m_gridCutTest);
76 m_interpolationDistMethod =
"perpOp";
77 m_interpolationDistMethod =
78 Context::getSolverProperty<MString>(
"interpolationDistMethod", m_solverId, AT_, &m_interpolationDistMethod);
87 m_outputWallDistanceField =
88 Context::getSolverProperty<MBool>(
"outputWallDistanceField", m_solverId, AT_, &m_outputWallDistanceField);
105 m_multiBCTreatment =
"I-W-P";
106 m_multiBCTreatment = Context::getSolverProperty<MString>(
"multiBCTreatment", m_solverId, AT_, &m_multiBCTreatment);
118 m_lbNoMovingWalls = 0;
119 m_lbNoMovingWalls = Context::getSolverProperty<MInt>(
"lbNoMovingWalls", m_solverId, AT_, &m_lbNoMovingWalls);
121 if(m_lbNoMovingWalls > 0) {
122 mAlloc(m_segIdMovingWalls, m_lbNoMovingWalls,
"m_segIdMovingWalls", 0, AT_);
134 for(
MInt i = 0; i < m_lbNoMovingWalls; i++) {
135 m_segIdMovingWalls[i] = Context::getSolverProperty<MInt>(
"segIdMovingWalls", m_solverId, AT_, i);
138 mAlloc(m_lbWallVelocity, m_lbNoMovingWalls * nDim,
"m_lbWallVelocity", F0, AT_);
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;
170 m_calcWallForces =
false;
171 m_calcWallForces = Context::getSolverProperty<MBool>(
"calculateWallForces", m_solverId, AT_, &m_calcWallForces);
173 if(m_calcWallForces) {
184 m_calcWallForcesInterval = 1;
185 m_calcWallForcesInterval =
186 Context::getSolverProperty<MInt>(
"calculateWallForcesInterval", m_solverId, AT_, &m_calcWallForcesInterval);
198 m_forceFile =
"forces.log";
199 m_forceFile = Context::getSolverProperty<MString>(
"forceFileName", m_solverId, AT_, &m_forceFile);
213 m_calcBcResidual =
false;
214 m_calcBcResidual = Context::getSolverProperty<MBool>(
"calcBcResidual", m_solverId, AT_, &m_calcBcResidual);
226 m_lbNoHeatedWalls = 0;
227 m_lbNoHeatedWalls = Context::getSolverProperty<MInt>(
"lbNoHeatedWalls", m_solverId, AT_, &m_lbNoHeatedWalls);
229 if(m_lbNoHeatedWalls > 0) {
230 mAlloc(m_segIdHeatedWalls, m_lbNoHeatedWalls,
"m_segIdHeatedWalls", 0, AT_);
242 for(
MInt i = 0; i < m_lbNoHeatedWalls; i++) {
243 m_segIdHeatedWalls[i] = Context::getSolverProperty<MInt>(
"segIdHeatedWalls", m_solverId, AT_, i);
246 mAlloc(m_lbWallTemperature, m_lbNoHeatedWalls,
"m_lbWallTemperature", F0, AT_);
258 for(
MInt i = 0; i < m_lbNoHeatedWalls; i++) {
259 m_lbWallTemperature[i] = Context::getSolverProperty<MFloat>(
"lbWallTemperature", m_solverId, AT_, i);
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();
269 mAlloc(m_periodicSegmentsIds, m_noPeriodicSegments,
"m_periodicSegmentsIds", 0, AT_);
271 for(
MInt i = 0; i < m_noPeriodicSegments; i++)
272 m_periodicSegmentsIds[i] =
273 *m_solver->m_geometry->geometryContext().getProperty(
"periodicSegmentsIds", 0)->asInt(i);
277 if(m_solver->grid().isActive()) {
281 createBoundaryCells();
290 if(m_solver->grid().isActive()) {
291 setBCNeighborCommunicator();
292 setBCWallNeighborCommunicator();
306 m_latentHeat =
false;
307 m_latentHeat = Context::getSolverProperty<MBool>(
"latentHeat", m_solverId, AT_, &m_latentHeat);
324 m_calcSublayerDist =
false;
325 m_calcSublayerDist = Context::getSolverProperty<MBool>(
"calcSublayerDist", m_solverId, AT_, &m_calcSublayerDist);
328 if(m_solver->isActive()) {
332 RECORD_TIMER_STOP(t_BCAll);
334 if(m_solver->m_geometry->m_debugParGeom) {
335 DISPLAY_ALL_GROUP_TIMERS(tgrp_BC);
350 if(m_numberOfCommBCs > 0) {
357 if(m_calcBcResidual)
mDeallocate(m_BCResidualStream);
372 bndCndHandlerVariables.clear();
373 bndCndHandlerRHS.clear();
374 bndCndInitiator.clear();
378 m_boundaryCellsMb.clear();
385 NEW_SUB_TIMER(t_processAngles,
"process angles", m_t_BCAll);
386 RECORD_TIMER_START(t_processAngles);
389 m_log <<
" + Processing angles..." << endl;
396 MFloat projection, angle1, angle2;
402 for(
MInt id = 0;
id < m_noInOutSegments;
id++) {
404 for(
MInt o = 0; o < (
MInt)m_bndCndSegIds.size(); o++)
405 if(m_inOutSegmentsIds[
id] == m_bndCndSegIds[o]) {
410 if(seg_id < 0)
continue;
412 if(m_bndNormals[
id][0] > 0) {
413 m_phi[
id] = atan(m_bndNormals[
id][1] / m_bndNormals[
id][0]);
417 if(m_bndNormals[
id][1] > 0)
424 if(m_bndNormals[
id][1] > 0) {
425 if(
approx(m_bndNormals[
id][0], 0.0, MFloatEps)) {
428 m_phi[
id] = PI + atan(m_bndNormals[
id][1] / m_bndNormals[
id][0]);
434 if(
approx(m_bndNormals[
id][0], 0.0, MFloatEps)) {
437 m_phi[
id] = -PI + atan(m_bndNormals[
id][1] / m_bndNormals[
id][0]);
443 IF_CONSTEXPR(nDim == 3) {
444 m_theta[
id] = asin(m_bndNormals[
id][2]);
446 if(m_bndNormals[
id][2] > 0)
451 else m_theta[
id] = 0;
453 for(
MInt i = 0; i < nDim; i++) {
454 projections[i] = 0.0;
455 for(
MInt j = 0; j < nDim; j++)
457 * m_bndNormals[
id][j];
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;
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]
473 m_log <<
" * scalar product with bndNormal: " << projections[0] <<
" "
474 << projections[1] << endl;
486 m_exDirs[
id][0] = -1;
487 m_exDirs[
id][1] = -1;
490 for(
MInt i = 0; i < pow(3.0, nDim) - 1; i++) {
494 for(
MInt j = 0; j < nDim; j++) {
496 * m_bndNormals[
id][j];
500 length = sqrt(length);
501 projection = projection / length;
503 if(projection > angle1) {
504 if(angle1 > angle2) {
506 m_exDirs[
id][1] = m_exDirs[
id][0];
511 if(projection > angle2) {
518 angle1 = abs(acos(angle1));
519 angle2 = abs(acos(angle2));
521 m_exWeights[
id][0] = angle2 / (angle1 + angle2);
522 m_exWeights[
id][1] = angle1 / (angle1 + angle2);
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;
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());
542 RECORD_TIMER_STOP(t_processAngles);
554 NEW_SUB_TIMER(t_printBndVelInfo,
"print boundary velcoity info", m_t_BCAll);
555 RECORD_TIMER_START(t_printBndVelInfo);
558 m_log <<
" + We have the following inflow / outflow boundary information: " << endl;
560 for(
MInt i = 0; i < (
MInt)(m_bndCndIds.size()); i++) {
561 MInt mapId = m_mapSegIdsInOutCnd[i];
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] <<
" ";
573 m_log <<
" * init vel: ";
574 for(
MInt j = 0; j < nDim; j++)
575 m_log << m_initialVelocityVecs[mapId][j] <<
" ";
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;
584 RECORD_TIMER_STOP(t_printBndVelInfo);
597 NEW_SUB_TIMER(t_initMembers,
"init members", m_t_BCAll);
598 RECORD_TIMER_START(t_initMembers);
600 m_log <<
" + Initializing some members..." << endl;
603 m_noSegments = m_solver->m_geometry->geometryContext().getNoSegments();
605 if(m_solver->m_geometry->geometryContext().propertyExists(
"inOutSegmentsIds", 0)) {
607 m_noInOutSegments = m_solver->m_geometry->geometryContext().getProperty(
"inOutSegmentsIds", 0)->count();
610 mAlloc(m_inOutSegmentsIds, m_noInOutSegments,
"m_inOutSegmentsIds", 0, AT_);
612 m_noInOutSegments = 0;
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_);
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_);
626 for(
MInt i = 0; i < m_noInOutSegments; i++) {
627 m_inOutSegmentsIds[i] = *m_solver->m_geometry->geometryContext().getProperty(
"inOutSegmentsIds", 0)->asInt(i);
642 m_bndNormalMethod =
"calcNormal";
643 m_bndNormalMethod = Context::getSolverProperty<MString>(
"bndNormalMethod", m_solverId, AT_, &m_bndNormalMethod);
658 m_initVelocityMethod =
"calcNormal";
659 m_initVelocityMethod =
660 Context::getSolverProperty<MString>(
"initVelocityMethod", m_solverId, AT_, &m_initVelocityMethod);
674 m_fastParallelGeomNormals = 0;
675 m_fastParallelGeomNormals =
676 Context::getSolverProperty<MInt>(
"fastParallelGeomNormals", m_solverId, AT_, &m_fastParallelGeomNormals);
680 RECORD_TIMER_STOP(t_initMembers);
694 if(m_noInOutSegments < 1)
return;
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);
700 m_log <<
" + Calculating vectors..." << endl;
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++) {
707 for(
MInt o = 0; o < (
MInt)m_bndCndSegIds.size(); o++) {
708 if(m_inOutSegmentsIds[i] == m_bndCndSegIds[o]) {
714 for(
MInt j = 0; j < nDim; j++) {
721 m_bndNormals[i][j] = Context::getSolverProperty<MFloat>(
"bndNormalVectors", m_solverId, AT_, k);
724 m_bndNormalDirection[i] = -1;
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;
740 if(m_bndNormalMethod ==
"calcNormal")
742 else if(m_bndNormalMethod ==
"fromSTL")
745 calculateBndNormals();
749 for(
MInt i = 0, k = 0; i < m_noInOutSegments; i++) {
750 for(
MInt j = 0; j < nDim; j++) {
752 if(m_initVelocityMethod ==
"read")
759 m_initialVelocityVecs[i][j] = Context::getSolverProperty<MFloat>(
"initialVelocityVectors", m_solverId, AT_, k);
762 else if(m_initVelocityMethod ==
"calcNormal")
763 m_initialVelocityVecs[i][j] = m_bndNormals[i][j];
766 else if(m_initVelocityMethod ==
"fromSTL")
767 m_initialVelocityVecs[i][j] = -1 * m_bndNormals[i][j];
773 MFloat normalLength = 0.0;
774 for(
MInt j = 0; j < nDim; j++) {
775 normalLength += m_initialVelocityVecs[i][j] * m_initialVelocityVecs[i][j];
777 normalLength = sqrt(normalLength);
778 for(
MInt j = 0; j < nDim; j++) {
779 m_initialVelocityVecs[i][j] = m_initialVelocityVecs[i][j] / normalLength;
785 RECORD_TIMER_STOP(t_calcVecs);
806 std::array<MFloat, nDim> edge1;
807 std::array<MFloat, nDim> edge2;
810 for(
MInt d = 0; d < nDim; d++) {
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];
823 normal_len = sqrt(normal_len);
825 for(
MInt d = 0; d < nDim; d++)
826 normal[d] /= normal_len;
828 if(
approx(normal_len, 0.0, MFloatEps)) {
855 for(
MInt d = 0; d < nDim; d++) {
857 normal_len += normal[d] * normal[d];
860 normal_len = sqrt(normal_len);
862 for(
MInt d = 0; d < nDim; d++)
863 normal[d] /= normal_len;
864 if(
approx(normal_len, 0.0, MFloatEps))
885 for(
MInt d = 0; d < nDim; d++) {
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];
897 offStart = m_solver->m_geometry->m_segmentOffsetsWithoutMB[segmentId];
898 offEnd = m_solver->m_geometry->m_segmentOffsetsWithoutMB[segmentId + 1];
902 for(
MInt e = offStart; e < offEnd; e++) {
904 std::array<MFloat, nDim> normal_t;
907 MBool is_valid = (this->*retrieveNormal)(triangle, normal_t.data());
911 std::array<MFloat, nDim> tmp;
912 for(
MInt d = 0; d < nDim; d++)
913 tmp[d] = normal[d] + normal_t[d];
917 for(
MInt d = 0; d < nDim; d++)
918 flip = flip &&
approx(tmp[d], 0.0, MFloatEps);
921 for(
MInt d = 0; d < nDim; d++)
924 for(
MInt d = 0; d < nDim; d++) {
925 normal[d] += normal_t[d];
926 for(
MInt v = 0; v < nDim; v++)
935 stringstream errorMsg;
936 errorMsg <<
"ERROR: no normal found for segment id " << segmentId << endl;
937 m_log << errorMsg.str();
938 TERMM(1, errorMsg.str());
942 MFloat avg_normal_len = sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]);
944 for(
MInt d = 0; d < nDim; d++) {
945 normal[d] /= avg_normal_len;
946 center[d] /= nDim * count;
967 for(
MInt d = 0; d < m_solver->noDomains(); d++)
969 numAllOwners[m_solver->domainId()] = own_segments.
size();
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()");
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];
984 for(
MInt i = 0; i < sumOwners * nDim; i++) {
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;
994 std::array<MFloat, nDim> normal;
995 std::array<MFloat, nDim> center;
996 calculateAveragedNormalAndCenter(segId, normal.data(), center.data());
998 MFloat max_diag = (m_solver->c_cellLengthAtLevel(m_solver->grid().maxUniformRefinementLevel())) * SQRT3;
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];
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;
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()");
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);
1026 for(
MInt d = 0; d < nDim; d++) {
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;
1032 doms_with_ints[m_solver->domainId()] = int_nodes[d].
size();
1036 m_solver->mpiComm(), AT_,
"MPI_IN_PLACE",
"doms_with_ints.getPointer()");
1038 MInt no_allCuts = 0;
1040 for(
MInt dom = 0; dom < m_solver->noDomains(); dom++)
1041 no_allCuts += doms_with_ints[dom];
1043 for(
MInt dom = 0; dom < m_solver->domainId(); dom++)
1044 myOff += doms_with_ints[dom];
1047 for(
MInt l = 0; l < no_allCuts; l++)
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;
1054 "MPI_IN_PLACE",
"origCmps.getPointer()");
1057 for(
MInt l = 0; l < no_allCuts; l++)
1058 uniques.insert(origCmps[l]);
1060 io[i * nDim + d] = uniques.
size();
1066 "MPI_IN_PLACE",
"io.getPointer()");
1068 for(
MInt s = 0; s < (
MInt)own_segments.size(); s++) {
1069 MInt p = own_segments[s].first;
1070 MInt posInTestPts = (myOffsetStart + s) * nDim;
1073 for(
MInt d = 0; d < nDim; d++)
1074 sum += io[posInTestPts + d];
1076 MBool is_inside = sum % 2;
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]
1104 for(
MInt i = 0; i < m_noInOutSegments; i++)
1105 for(
MInt d = 0; d < nDim; d++)
1106 test_pts(i, d) = 0.0;
1108 for(
MInt i = 0; i < m_noInOutSegments; i++)
1111 for(
MInt s = 0; s < (
MInt)own_segments.size(); s++)
1112 IDoOwn[own_segments[s].first] = 1;
1116 AT_,
"IDoOwn.getPointer()",
"allDoOwn.getPointer()");
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;
1123 std::array<MFloat, nDim> normal;
1124 std::array<MFloat, nDim> center;
1125 calculateAveragedNormalAndCenter(segId, normal.data(), center.data());
1127 MFloat max_diag = (m_solver->c_cellLengthAtLevel(m_solver->grid().maxUniformRefinementLevel())) * SQRT3;
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];
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)
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;
1156 owner_roots[m_solver->domainId()] = -1;
1158 if(allDoOwn[i] > 1) {
1159 posToComm.push_back(i);
1165 vector<MPI_Comm> comms;
1166 for(
MInt i = 0; i < numComm; i++) {
1167 MInt pos = posToComm[i];
1171 MInt firstOwner = -1;
1176 m_solver->m_geometry->determineSegmentOwnership(m_inOutSegmentsIds[pos], &IDoOwn[pos], &sumowners, &firstOwner,
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 <<
" ";
1189 m_solver->createMPIComm(owners.
getPointer(), sumowners, &tmpComm);
1190 comms.push_back(tmpComm);
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()");
1196 for(
MInt i = 0; i < numComm; i++) {
1197 MInt p = posToComm[i];
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);
1208 MPI_Allreduce(MPI_IN_PLACE, testenv.
getPointer(), 2 * nDim, MPI_DOUBLE, MPI_SUM, comms[i], AT_,
"MPI_IN_PLACE",
1209 "testenv.getPointer()");
1212 MPI_Comm_size(comms[i], &size);
1215 for(
MInt d = 0; d < 2 * nDim; d++)
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];
1233 for(
MInt i = 0; i < nDim * m_noInOutSegments; i++)
1234 rec_test_pts[i] = 0.0;
1236 for(
MInt d = 0; d < m_solver->noDomains(); d++) {
1237 MInt segInOut = owner_roots[m_solver->domainId()];
1239 MInt p = segInOut * nDim;
1240 for(
MInt k = 0; k < nDim; k++)
1241 rec_test_pts[p + k] = test_pts(segInOut, k);
1246 m_solver->mpiComm(), AT_,
"MPI_IN_PLACE",
"rec_test_pts.getPointer()");
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]);
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()");
1260 for(
MInt s = 0; s < (
MInt)own_segments.size(); s++) {
1261 MInt p = own_segments[s].first;
1262 MInt pos = p * nDim;
1265 for(
MInt d = 0; d < nDim; d++)
1266 sum += num_cuts[pos + d];
1268 MBool is_inside = sum % 2;
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]
1282 std::stringstream ss;
1283 ss <<
"Calculate boundary normal not implemented for " << nDim <<
"D, yet !";
1306 constexpr MInt nDim = 3;
1309 m_log <<
" - calculating normals in 3D (bndNormalMethod is set to " << m_bndNormalMethod <<
")" << endl;
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]));
1321 for(
MInt d = 0; d < nDim; d++)
1322 m_bndNormals[i][d] = 0.0;
1325 if(m_solver->m_geometry->m_parallelGeometry) {
1326 if(m_fastParallelGeomNormals)
1327 fastParallelGeomNormals3D(own_segments);
1329 normalParallelGeomNormals3D(own_segments);
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());
1338 MFloat max_diag = (m_solver->c_cellLengthAtLevel(m_solver->grid().maxUniformRefinementLevel())) * SQRT3;
1339 std::array<MFloat, nDim> test_pt;
1341 for(
MInt d = 0; d < nDim; d++)
1342 test_pt[d] = center[d] + normal[d] * max_diag;
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;
1366 m_bndNormalDirection[segId] = -1;
1370 for(
MInt d = 0; d < nDim; d++)
1371 m_bndNormals[segId][d] = avg_normal[d];
1375 for(
MInt d = 0; d < nDim; d++)
1376 m_bndNormals[segId][d] = -1.0 * avg_normal[d];
1392 for(
MInt i = 0; i < m_noInOutSegments; i++)
1393 if(m_bndCells[m_bndCndOffsets[index]].m_segmentId[0] == m_inOutSegmentsIds[i]) ind = i;
1406 m_bndCndData[index];
1410 for(
MInt i = m_bndCndOffsets[index]; i < m_bndCndOffsets[index + 1]; i++) {
1411 if(!m_solver->a_isHalo(m_bndCells[i].m_cellId)) {
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;
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) {
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);
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);
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) {
1480 const MInt noEntries = p.noBndCells * p.noVars;
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];
1493 parallelIo.setOffset(noEntries, p.globalOffset);
1494 parallelIo.writeArray(&tmp[0], name);
1497 const MFloat* dummyData =
nullptr;
1498 parallelIo.setOffset(0, 0);
1499 parallelIo.writeArray(&dummyData[0], name);
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) {
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);
1526 parallelIo.setOffset(noEntries, p.globalOffset);
1527 parallelIo.readArray(&tmp[0], name);
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];
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);
1567 if(m_initVelocityMethod !=
"read" && m_initVelocityMethod !=
"fromSTL") {
1568 MInt ind = m_mapSegIdsInOutCnd[index];
1571 if(m_bndNormalDirection[ind] == -1)
1572 for(
MInt i = 0; i < nDim; i++)
1573 m_initialVelocityVecs[ind][i] *= -1.0;
1591 if(m_initVelocityMethod !=
"read" && m_initVelocityMethod !=
"fromSTL") {
1592 MInt ind = m_mapSegIdsInOutCnd[index];
1595 if(m_bndNormalDirection[ind] == 1)
1596 for(
MInt i = 0; i < nDim; i++)
1597 m_initialVelocityVecs[ind][i] *= -1.0;
1617 MFloat minmax[2] = {10000000.0, -10000000.0};
1619 MInt x_pos = m_solver->m_referenceLength * m_solver->m_blasiusPos;
1626 MFloat fppwall = 0.332051914927913096446;
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);
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;
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));
1654 m_bndCells[i].m_eta = eta;
1658 list<MFloat> etas_sorted;
1659 for(set<MFloat>::iterator i = etas.begin(); i != etas.end(); i++)
1660 etas_sorted.push_back(*i);
1664 list<MFloat>::iterator it1 = etas_sorted.end();
1666 list<MFloat>::iterator it2 = etas_sorted.begin();
1672 it1 = etas_sorted.begin();
1674 steps = etamax / deta;
1677 m_blasius_delta = deta;
1679 mAlloc(m_blasius, steps + 1, 5,
"m_blasius", F0, AT_);
1680 m_blasius[0][3] = fppwall;
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;
1710 const MInt tmpCellSize = m_bndCells.size();
1712 m_log <<
" + Sorting boundary cells..." << endl;
1713 m_log <<
" - no. boundary cells: " << tmpCellSize << endl;
1716 stable_sort(m_bndCells.begin(), m_bndCells.end(),
1717 [](
auto&
a,
auto&
b) { return a.m_segmentId[0] < b.m_segmentId[0]; });
1719 MInt tmpSegmentId = -1;
1720 MInt tmpBndCndId = -1;
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);
1733 for(
MInt i = 0; i < tmpCellSize; i++) {
1734 if(tmpSegmentId != m_bndCells[i].m_segmentId[0]) {
1737 tmpSegmentId = m_bndCells[i].m_segmentId[0];
1738 tmpBndCndId = m_bndCells[i].m_bndCndId[0];
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;
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;
1753 m_bndCndOffsets.push_back(counter);
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];
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;
1767 for(
MInt j = 0; j < m_noInOutSegments; j++)
1768 if(seg_id == m_inOutSegmentsIds[j]) pos = j;
1770 m_mapSegIdsInOutCnd[i] = pos;
1772 m_log <<
" * mapping: " << m_mapSegIdsInOutCnd[i] <<
" "
1773 << ((m_mapSegIdsInOutCnd[i] < 0) ?
"(this is not an inflow / outflow BC)" :
"") << endl;
1788 if(!m_solver->isActive())
return;
1790 NEW_SUB_TIMER(t_setBCHandler,
"set BC handler", m_t_BCAll);
1791 RECORD_TIMER_START(t_setBCHandler);
1793 m_log <<
" + Setting the boundary condition handler..." << endl << endl;
1796 bndCndHandlerVariables.resize(m_bndCndIds.size());
1797 bndCndHandlerRHS.resize(m_bndCndIds.size());
1798 bndCndInitiator.resize(m_bndCndIds.size());
1800 m_segIdUseBcData.resize(m_noSegments, 0);
1803 for(
MInt i = 0; i < (
MInt)(m_bndCndIds.size()); i++) {
1804 switch(m_bndCndIds[i]) {
1809 DEBUG(
"ERROR: bndCndHandlers only point to a dummy function", MAIA_DEBUG_LEVEL1);
1816 applyDirectionChangeInflow(i);
1822 applyDirectionChangeInflow(i);
1828 applyDirectionChangeInflow(i);
1834 applyDirectionChangeInflow(i);
1840 applyDirectionChangeInflow(i);
1846 applyDirectionChangeInflow(i);
1852 applyDirectionChangeInflow(i);
1858 bcDataAllocate(i, nDim + 1);
1859 applyDirectionChangeInflow(i);
1865 bcDataAllocate(i, nDim + 1);
1866 applyDirectionChangeInflow(i);
1872 bcDataAllocate(i, nDim + 1);
1873 applyDirectionChangeInflow(i);
1879 bcDataAllocate(i, nDim + 1);
1880 applyDirectionChangeInflow(i);
1886 bcDataAllocate(i, nDim + 1);
1887 applyDirectionChangeInflow(i);
1893 bcDataAllocate(i, nDim + 1);
1894 applyDirectionChangeInflow(i);
1900 applyDirectionChangeInflow(i);
1906 applyDirectionChangeInflow(i);
1912 applyDirectionChangeInflow(i);
1918 applyDirectionChangeInflow(i);
1925 if(m_densityFluctuations) TERMM(1,
"BC 1070 not working for densityFluctuations");
1926 applyDirectionChangeInflow(i);
1933 applyDirectionChangeInflow(i);
1943 applyDirectionChangeInflow(i);
2276 bcDataAllocate(i, nDim + 1);
2282 bcDataAllocate(i, nDim + 1);
2288 bcDataAllocate(i, nDim + 1);
2294 bcDataAllocate(i, nDim + 1);
2300 bcDataAllocate(i, nDim + 1);
2306 bcDataAllocate(i, nDim + 1);
2383 stringstream errorMessage;
2384 errorMessage <<
" LbBncCndDxQy::setBndCndHandler : Unknown boundary condition " << m_bndCndIds[i]
2385 <<
" exiting program.";
2386 TERMM(1, errorMessage.str());
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()");
2394 RECORD_TIMER_STOP(t_setBCHandler);
2410 m_noAllBoundaryIds = 0;
2411 m_allBoundaryIds = m_solver->m_geometry->GetBoundaryIds(&m_noAllBoundaryIds);
2413 for(
MInt i = 0; i < m_noAllBoundaryIds; i++) {
2414 switch(m_allBoundaryIds[i]) {
2440 NEW_SUB_TIMER(t_setBCNC,
"set BC neighbor communicators", m_t_BCAll);
2441 RECORD_TIMER_START(t_setBCNC);
2444 m_hasCommForce = checkForCommForce();
2445 if(!m_hasCommForce) {
2446 RECORD_TIMER_STOP(t_setBCNC);
2450 m_log <<
" + Found a BC which requires communication:" << endl;
2453 for(
MInt i = 0; i < m_noAllBoundaryIds; i++) {
2454 MBool found =
false;
2455 switch(m_allBoundaryIds[i]) {
2469 RECORD_TIMER_STOP(t_setBCNC);
2489 if(!m_calcWallForces)
return;
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");
2495 m_mapWallForceContainer.clear();
2496 for(
MInt i = 0; i < m_noSegments; i++) {
2497 if(allBoundaryIds[i] == 2000) {
2498 m_mapWallForceContainer[i];
2502 for(
auto& mapWallForceIterator : m_mapWallForceContainer) {
2503 const MInt segId = mapWallForceIterator.first;
2504 const MInt index = m_mapBndCndSegId2Index[segId];
2505 auto& cwfc = mapWallForceIterator.second;
2507 const MInt noCalcForceCells = (index > -1) ? (m_bndCndOffsets[index + 1] - m_bndCndOffsets[index]) : 0;
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);
2520 cwfc.noComm = bcWallNeighbors.size();
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");
2530 cwfc.isRoot = (m_solver->domainId() == bcWallNeighbors[0]);
2532 if(m_mapWallForceContainer.size() > 1) {
2533 std::stringstream fileNameS;
2534 fileNameS << m_forceFile << m_bndCndSegIds[index];
2535 cwfc.fileName = fileNameS.str();
2537 cwfc.fileName = m_forceFile;
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");
2552 fprintf(forceFile,
"\n");
2572 if(m_solver->m_geometry->m_parallelGeometry) {
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_);
2579 for(set<MInt>::iterator it = tmplist.begin(); it != tmplist.end(); ++it, pos++)
2580 m_allBoundaryIds[pos] = *it;
2582 m_noAllBoundaryIds = 0;
2583 m_allBoundaryIds = m_solver->m_geometry->GetBoundaryIds(&m_noAllBoundaryIds);
2586 for(
MInt i = 0; i < m_noAllBoundaryIds; i++) {
2587 switch(m_allBoundaryIds[i]) {
2589 m_numberOfCommBCs++;
2593 m_numberOfCommBCs++;
2597 m_numberOfCommBCs++;
2601 m_numberOfCommBCs++;
2605 m_numberOfCommBCs++;
2609 m_numberOfCommBCs++;
2613 m_numberOfCommBCs++;
2617 m_numberOfCommBCs++;
2621 m_numberOfCommBCs++;
2625 m_numberOfCommBCs++;
2629 m_numberOfCommBCs++;
2633 m_numberOfCommBCs++;
2637 m_numberOfCommBCs++;
2641 m_numberOfCommBCs++;
2645 m_numberOfCommBCs++;
2652 return m_numberOfCommBCs;
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;
2680 m_allDomainsHaveBC[BCCounter][m_solver->domainId()] = 0;
2683 if(m_solver->noDomains() > 1) {
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");
2690 for(
MInt count = 0; count < m_solver->noDomains(); count++) {
2691 m_allDomainsHaveBC[BCCounter][count] = domainsHaveBC(count);
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];
2703 m_BCneighbors.push_back(BCneighborsPerSeg);
2705 m_noBCNeighbors[BCCounter] = (
MInt)m_BCneighbors[BCCounter].size();
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];
2712 MPI_Comm_group(m_solver->mpiComm(), &tmp_group[BCCounter], AT_,
"tmp_group");
2716 MPI_Comm_create(m_solver->mpiComm(), BCGroup[BCCounter], &m_BCComm[BCCounter], AT_,
"m_BCComm");
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;
2729 m_log <<
" - BC 4073" << endl;
2730 m_log <<
" * reading properties from file" << endl;
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());
2743 mAlloc(m_localReCutPoint, nDim,
"m_localReCutPoint", 0.0, AT_);
2744 mAlloc(m_localReCutNormal, nDim,
"m_localReCutNormal", 0.0, AT_);
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];
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());
2761 for(
MInt i = 0; i < nDim; i++)
2762 m_localReCutNormal[i] /= len;
2764 if(m_solver->m_geometry->geometryContext().propertyExists(
"localReCutDistance", 0))
2765 m_localReCutDistance = *m_solver->m_geometry->geometryContext().getProperty(
"localReCutDistance", 0)->asFloat();
2767 m_localReCutDistance = m_solver->c_cellLengthAtLevel(0);
2769 if(m_solver->m_geometry->geometryContext().propertyExists(
"localReCutInterval", 0))
2770 m_localReCutInterval = *m_solver->m_geometry->geometryContext().getProperty(
"localReCutInterval", 0)->asInt();
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());
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());
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();
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();
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();
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();
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();
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());
2813 if(m_solver->m_geometry->geometryContext().propertyExists(
"localReCut_lRho", 0))
2814 m_lRho = *m_solver->m_geometry->geometryContext().getProperty(
"localReCut_lRho", 0)->asFloat();
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());
2822 if(m_solver->m_geometry->geometryContext().propertyExists(
"localReCut_rhoLast", 0))
2823 m_rhoLast = *m_solver->m_geometry->geometryContext().getProperty(
"localReCut_rhoLast", 0)->asFloat();
2825 stringstream errorMsg;
2826 errorMsg <<
"ERROR: no geometry property 'localReCut_rhoLast' defined for BC 4073 (as required for restart)"
2828 m_log << errorMsg.str();
2829 TERMM(1, errorMsg.str());
2832 if(m_solver->m_geometry->geometryContext().propertyExists(
"localReCut_deltaRho", 0))
2833 m_deltaRho = *m_solver->m_geometry->geometryContext().getProperty(
"localReCut_deltaRho", 0)->asFloat();
2835 stringstream errorMsg;
2836 errorMsg <<
"ERROR: no geometry property 'localReCut_deltaRho' defined for BC 4073 (as required for restart)"
2838 m_log << errorMsg.str();
2839 TERMM(1, errorMsg.str());
2842 if(m_solver->m_geometry->geometryContext().propertyExists(
"localReCut_ReLast", 0))
2843 m_ReLast = *m_solver->m_geometry->geometryContext().getProperty(
"localReCut_ReLast", 0)->asFloat();
2845 stringstream errorMsg;
2846 errorMsg <<
"ERROR: no geometry property 'localReCut_ReLast' defined for BC 4073 (as required for restart)"
2848 m_log << errorMsg.str();
2849 TERMM(1, errorMsg.str());
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++) {
2857 if(m_solver->c_noChildren(i) > 0 || m_solver->a_isHalo(i))
continue;
2859 MFloat cellHalfLength = m_solver->c_cellLengthAtLevel(m_solver->a_level(i) + 1);
2860 const MFloat*
const coordinates = &(m_solver->a_coordinate(i, 0));
2862 std::array<MFloat, nDim> edge;
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];
2875 if(fabs(prodist) < cellHalfLength &&
dist <= m_localReCutDistance) m_localReCutCells.push_back(i);
2877 m_log <<
" = no of cells for this domain: " << m_localReCutCells.size() << endl;
2878 m_hasLocalReCut = (m_localReCutCells.size() > 0);
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) {
2888 m_allDomainsHaveBC[BCCounter][m_solver->domainId()] = m_hasLocalReCut ? m_localReCutCells.size() : -1;
2890 if(m_allDomainsHaveBC[BCCounter][m_solver->domainId()] == -1 && has_bc4073)
2891 m_allDomainsHaveBC[BCCounter][m_solver->domainId()] = 0;
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");
2898 std::vector<MInt> BCneighborsPerSeg;
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];
2911 m_BCneighbors.push_back(BCneighborsPerSeg);
2912 m_noBCNeighbors[BCCounter] = (
MInt)m_BCneighbors[BCCounter].size();
2914 m_firstBCinComm = 0;
2915 if(m_noBCNeighbors[BCCounter] > 0) m_firstBCinComm = m_BCneighbors[BCCounter][0];
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];
2922 m_log <<
" * building MPI communicator" << endl;
2923 if(m_noBCNeighbors[BCCounter] != 0 && m_solver->noDomains() > 1) {
2926 MPI_Comm_group(m_solver->mpiComm(), &tmp_group[BCCounter], AT_,
"tmp_group");
2930#ifdef MAIA_MPI_DEBUG
2931 MPI_Comm_create(m_solver->mpiComm(), BCGroup[BCCounter], &m_BCComm[BCCounter], AT_,
"m_BCComm");
2933 MPI_Comm_create(m_solver->mpiComm(), BCGroup[BCCounter], &m_BCComm[BCCounter], AT_,
"m_BCComm");
2936 if(m_calcBcResidual && m_solver->domainId() == m_firstBCinComm) {
2937 m_BCResidualStream[BCCounter].open(m_BCOutputFileName[BCCounter], ios_base::app);
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"
2945 <<
"# 4: m_ReLast\n"
2948 <<
"# 7: m_rhoLast\n"
2949 <<
"# 8: m_deltaRho\n"
2950 <<
"############################\n"
2955 m_log <<
" * updating boundary condition list" << endl;
2956 if(!has_bc4073 && m_hasLocalReCut) {
2958 m_bndCndIds.push_back(4073);
2959 m_bndCndOffsets.push_back(m_bndCndOffsets[m_bndCndOffsets.size() - 1]);
2961 m_bndCndSegIds.push_back(-1);
2962 m_mapSegIdsInOutCnd.push_back(-1);
2964 m_log <<
" + created new BC 4073" << endl;
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] <<
" ";
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] <<
" ";
2979 m_log <<
" * target Re: " << m_localReCutRe
2980 << (
approx(m_localReCutRe, m_solver->m_Re, MFloatEps) ?
" (same as global Re)" :
" (different than global Re)")
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)")
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] <<
" ";
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;
3023 NEW_SUB_TIMER(t_setBCNC,
"set BC neighbor communicators", m_t_BCAll);
3024 RECORD_TIMER_START(t_setBCNC);
3027 m_numberOfCommBCs = checkForCommBC();
3028 if(m_numberOfCommBCs == 0) {
3029 RECORD_TIMER_STOP(t_setBCNC);
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_);
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_);
3041 if(m_calcBcResidual)
mAlloc(m_BCResidualStream, m_numberOfCommBCs,
"m_BCResidualStream", AT_);
3042 mAlloc(m_BCOutputFileName, m_numberOfCommBCs,
"m_BCOutputFileName", AT_);
3044 if((
MInt)(m_bndCndIds.size()) > 0)
3045 mAlloc(m_mapBndCndIdSegId, (
MInt)(m_bndCndIds.size()),
"m_mapBndCndIdSegId", 0, AT_);
3047 m_log <<
" + Found a BC which requires communication:" << endl;
3049 MInt counterCommBC = 0;
3051 for(
MInt segId = 0; segId < m_noAllBoundaryIds; segId++) {
3053 MBool found =
false;
3054 switch(m_allBoundaryIds[segId]) {
3056 s <<
"Output_SegNo_" << segId <<
"_BC_" << 1000 <<
".dat";
3057 m_BCOutputFileName[counterCommBC] = s.str();
3058 prepareBC(1000, counterCommBC, segId);
3063 s <<
"Output_SegNo_" << segId <<
"_BC_" << 1022 <<
".dat";
3064 m_BCOutputFileName[counterCommBC] = s.str();
3065 prepareBC(1022, counterCommBC, segId);
3070 s <<
"Output_SegNo_" << segId <<
"_BC_" << 1060 <<
".dat";
3071 m_BCOutputFileName[counterCommBC] = s.str();
3072 prepareBC(1060, counterCommBC, segId);
3077 s <<
"Output_SegNo_" << segId <<
"_BC_" << 1080 <<
".dat";
3078 m_BCOutputFileName[counterCommBC] = s.str();
3079 prepareBC(1080, counterCommBC, segId);
3084 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4000 <<
".dat";
3085 m_BCOutputFileName[counterCommBC] = s.str();
3086 prepareBC(4000, counterCommBC, segId);
3091 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4030 <<
".dat";
3092 m_BCOutputFileName[counterCommBC] = s.str();
3093 prepareBC(4030, counterCommBC, segId);
3098 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4130 <<
".dat";
3099 m_BCOutputFileName[counterCommBC] = s.str();
3100 prepareBC(4130, counterCommBC, segId);
3105 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4070 <<
".dat";
3106 m_BCOutputFileName[counterCommBC] = s.str();
3107 prepareBC(4070, counterCommBC, segId);
3112 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4071 <<
".dat";
3113 m_BCOutputFileName[counterCommBC] = s.str();
3114 prepareBC(4071, counterCommBC, segId);
3119 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4072 <<
".dat";
3120 m_BCOutputFileName[counterCommBC] = s.str();
3121 prepareBC(4072, counterCommBC, segId);
3126 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4073 <<
".dat";
3127 m_BCOutputFileName[counterCommBC] = s.str();
3128 prepareBC4073(counterCommBC, segId);
3133 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4080 <<
".dat";
3134 m_BCOutputFileName[counterCommBC] = s.str();
3135 prepareBC(4080, counterCommBC, segId);
3140 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4081 <<
".dat";
3141 m_BCOutputFileName[counterCommBC] = s.str();
3142 prepareBC(4081, counterCommBC, segId);
3147 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4082 <<
".dat";
3148 m_BCOutputFileName[counterCommBC] = s.str();
3149 prepareBC(4082, counterCommBC, segId);
3154 s <<
"Output_SegNo_" << segId <<
"_BC_" << 4110 <<
".dat";
3155 m_BCOutputFileName[counterCommBC] = s.str();
3156 prepareBC(4110, counterCommBC, segId);
3169 RECORD_TIMER_STOP(t_setBCNC);
3177 for(
MInt i = 0; i < (
MInt)(m_bndCndIds.size()); i++) {
3178 (this->*bndCndHandlerVariables[i])(i);
3187 for(
MInt i = 0; i < (
MInt)(m_bndCndIds.size()); i++) {
3188 (this->*bndCndHandlerRHS[i])(i);
3210 NEW_SUB_TIMER(t_createBCCells,
"create boundary cells", m_t_BCAll);
3211 RECORD_TIMER_START(t_createBCCells);
3213 MInt bndCellsIt = 0, bndCellsIt2 = 0;
3214 MFloat cellHalfLength = 0.0;
3217 m_log <<
" + Creating boundary cells..." << endl;
3218 m_log <<
" - Multiple BC treatment: " << m_multiBCTreatment << endl;
3221 for(
MInt i = 0; i < m_solver->m_cells.size(); i++) {
3223 if(!m_solver->c_isLeafCell(i) && !m_solver->a_isInterfaceParent(i))
continue;
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;
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));
3238 m_solver->m_geometry->getIntersectionElements(targetPtr, nodeList);
3239 const MInt noNodes = nodeList.
size();
3242 m_solver->a_onlyBoundary(i) =
true;
3243 m_solver->a_isBndryCell(i) =
true;
3246 m_bndCells.emplace_back();
3248 bndCellsIt = m_bndCells.size() - 1;
3249 m_bndCells[bndCellsIt].m_cellId = i;
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) {
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);
3265 if(m_bndCells[bndCellsIt].m_segmentId.size() > 1) {
3267 MInt positions[3] = {-1, -1, -1};
3269 for(
MInt j = 0; j < (
MInt)(m_bndCells[bndCellsIt].m_segmentId.size()); j++) {
3270 MBool is_inout =
false;
3271 MBool is_periodic =
false;
3273 for(
MInt k = 0; k < m_noInOutSegments; k++)
3274 if(m_bndCells[bndCellsIt].m_segmentId[j] == m_inOutSegmentsIds[k]) {
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]) {
3286 else if(!is_inout && !is_periodic)
3288 else if(is_periodic)
3293 if(m_multiBCTreatment ==
"W-P-I") {
3295 if(positions[1] != -1) swap_pos = positions[1];
3297 else if(positions[2] != -1)
3298 swap_pos = positions[2];
3300 }
else if(m_multiBCTreatment ==
"W-I-P") {
3302 if(positions[1] != -1) swap_pos = positions[1];
3304 else if(positions[0] != -1)
3305 swap_pos = positions[0];
3306 }
else if(m_multiBCTreatment ==
"I-W-P") {
3308 if(positions[0] != -1) swap_pos = positions[0];
3310 else if(positions[1] != -1)
3311 swap_pos = positions[1];
3312 }
else if(m_multiBCTreatment ==
"I-P-W") {
3314 if(positions[0] != -1) swap_pos = positions[0];
3316 else if(positions[2] != -1)
3317 swap_pos = positions[2];
3318 }
else if(m_multiBCTreatment ==
"P-W-I") {
3320 if(positions[2] != -1) swap_pos = positions[2];
3322 else if(positions[1] != -1)
3323 swap_pos = positions[1];
3324 }
else if(m_multiBCTreatment ==
"P-I-W") {
3326 if(positions[2] != -1) swap_pos = positions[2];
3328 else if(positions[0] != -1)
3329 swap_pos = positions[0];
3336 else if(m_multiBCTreatment ==
"multiple") {
3340 bndCellsIt2 = bndCellsIt;
3341 for(
MInt j = 1; j < (
MInt)(m_bndCells[bndCellsIt].m_segmentId.size()); j++) {
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]) {
3353 m_bndCells.emplace_back();
3354 m_bndCells[bndCellsIt2].m_cellId = i;
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]);
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;
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;
3376 m_log <<
" - noBndCells: " << m_bndCells.size() << endl << endl;
3378 for(
auto& bndCell : m_bndCells) {
3379 bndCell.m_multiplier = 1.0;
3382 RECORD_TIMER_STOP(t_createBCCells);
3392 for(
MInt i = 0; i < (
MInt)(m_bndCndIds.size()); i++) {
3393 (this->*bndCndInitiator[i])(i);
3395 if(!m_solver->m_restartFile) {
3396 for(
auto p : m_bndCndData) {
3397 const MInt& p_index = p.first;
3399 const MInt bndCndOffset = m_bndCndOffsets[p_index];
3402 p_data.
data[i * p_data.
noVars + j] = m_solver->a_oldVariable(m_bndCells[i + bndCndOffset].m_cellId, j);
3419 if(!m_calcWallForces)
return;
3421 if(!m_solver->grid().isActive()) {
3425 if(m_solver->noDomains() > 1) {
3426 if( (m_BCWallMBComm != MPI_COMM_NULL)) {
3430 m_allDomainsCalcForceMB[m_solver->domainId()] = m_solver->m_currentNoG0Cells;
3432 if(!m_BCWallMBNeighbors.empty()) m_BCWallMBNeighbors.clear();
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");
3444 for(
MInt i = 0; i < m_solver->noDomains(); i++) {
3445 if(m_allDomainsCalcForceMB[i] > 0) {
3446 m_BCWallMBNeighbors.push_back(i);
3450 m_noBCWallMBNeighbors = (
MInt)m_BCWallMBNeighbors.size();
3452 MIntScratchSpace ptBCWallMBNeighbors(m_noBCWallMBNeighbors, AT_,
"ptBCWallMBNeighbors");
3453 for(
MInt i = 0; i < m_noBCWallMBNeighbors; i++)
3454 ptBCWallMBNeighbors[i] = m_BCWallMBNeighbors[i];
3457 if(m_noBCWallMBNeighbors != 0) {
3458 MPI_Group tmp_groupMB, BCGroupMB;
3459 MPI_Comm_group(m_solver->mpiComm(), &tmp_groupMB, AT_,
"tmp_groupMB");
3462 MPI_Comm_create(m_solver->mpiComm(), BCGroupMB, &m_BCWallMBComm, AT_,
"m_BCWallMBComm");
3465 if(m_solver->domainId() == m_BCWallMBNeighbors[0]) {
3466 m_forceFile =
"forcesMB.log";
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");
3478 fprintf(forceFile,
"%*s\t", columnLength,
"4:F_z");
3480 fprintf(forceFile,
"\n");
3486 m_noBCWallMBNeighbors = 1;
3487 m_BCWallMBNeighbors.push_back(m_solver->domainId());
3505 m_log <<
" + Setting the boundary condition handler for LB_LS..." << endl << endl;
3506 bndCndHandlerVariables_MB.resize(1);
3508 bndCndHandlerRHS_MB.resize(1);
3523 mAlloc(m_allDomainsCalcForceMB, m_solver->noDomains(),
"m_allDomainsCalcForceMB", 0, AT_);
3529 m_BCWallMBComm = MPI_COMM_NULL;
3539 if(!m_solver->grid().isActive()) {
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);
void mAlloc(T *&a, const MLong N, const MString &objectName, MString function)
allocates memory for one-dimensional array 'a' of size N
MBool mDeallocate(T *&a)
deallocates the memory previously allocated for element 'a'
virtual void bc20051(MInt)
virtual void initializeBndMovingBoundaries()
This function initializes the LbBndCnd for coupled simulations.
void calculateBndNormals()
virtual void updateVariables()
Dereferences bndCndHandlerVariables.
virtual void setBCWallNeighborCommunicator()
Sets up a neighbor-communicator for certain BCs.
MBool calculateNormalFromTriangle(GeometryElement< nDim > ge, MFloat *normal)
Calculate the normal based on a triangle.
virtual void bc30042(MInt)
virtual void bc20227(MInt)
virtual void createMBComm()
This function creates the communicator for calculating the wall forces of the level-set boundaries.
virtual void bc10041(MInt)
virtual void bc10002(MInt)
virtual MInt checkForCommBC()
Checks if a BC exists that requires communication.
virtual void bc40043(MInt)
virtual void bc30013(MInt)
virtual void bc10010(MInt)
virtual void bcIBBNeumannInit(MInt)
virtual void prepareBC2000()
Prepares the BC 4072.
virtual void bc40073(MInt)
virtual void normalParallelGeomNormals3D(std::vector< std::pair< MInt, MInt > > own_segments)
virtual void prepareBC4073(MInt BCCounter, MInt segId)
virtual void bc30023(MInt)
virtual void bc40046(MInt)
virtual void bc20228(MInt)
virtual void bc30012(MInt)
virtual void bc10022(MInt)
virtual void bc30024(MInt)
virtual void bc20002(MInt)
virtual ~LbBndCnd()
The destructor.
virtual void bc40072_40082_init(MInt)
virtual void bc20005(MInt)
virtual void bc10040(MInt)
virtual void bc20022(MInt)
virtual void bc20001(MInt)
virtual void bc20006(MInt)
virtual void setBCNeighborCommunicator()
Sets up a neighbor-communicator for certain BCs.
virtual void bc40040(MInt)
virtual void bc40042(MInt)
virtual void bc30014(MInt)
virtual void bc20226(MInt)
virtual void calculateAveragedNormalAndCenter(MInt segmentId, MFloat *const normal, MFloat *const center)
virtual void bc20501_init(MInt)
virtual void calculateVectors()
virtual void bc10000(MInt)
virtual void processAngles()
virtual void bc30030(MInt)
virtual void setBndCndHandler()
Sets the BndCndHandler objects at solver setup.
virtual void bc10044(MInt)
virtual void bc30022(MInt)
virtual void bc20010(MInt)
virtual void bc66666(MInt)
virtual void bc30043(MInt)
virtual void bc20220(MInt)
virtual void bc30000(MInt)
virtual void bc20000(MInt)
void bcDataReadRestartData(ParallelIo ¶llelIo)
Read bndCndData data in given ParallelIo file.
virtual void updateRHS()
Dereferences bndCndHandlerRHS.
virtual void bc30040(MInt)
virtual void bc10111(MInt)
virtual void bc40071(MInt)
virtual void bc10090(MInt)
virtual void createBoundaryCells()
Creates boundary cells according to the geometry information.
virtual void bc10060(MInt)
virtual void bc40072(MInt)
virtual void bc40030(MInt)
void bcDataAllocate(MInt index, MInt noVars)
Allocate data for given boundary index.
virtual void bc20024(MInt)
virtual void prepareBC(MInt index, MInt BCCounter, MInt segId)
Prepares the BC 4070, 4071, 4072, 4080, 4081, and 4082.
virtual void bc40120(MInt)
virtual void bc40110(MInt)
virtual void bc40070(MInt)
virtual void bc10004(MInt)
virtual MBool checkForCommForce()
Checks if a BC exists that requires communication.
virtual void bc40080(MInt)
virtual void bc20050(MInt)
virtual void bc40081(MInt)
void initializeBcData()
Initialize BC data variables.
virtual void printBndVelInfo()
This function prints the gathered information on the boundary vectors and the initial velocity vector...
void applyDirectionChangeInflow(MInt index)
This function checks if for an inflow boundary the normal points into the according direction and cha...
virtual void bc10001(MInt)
void sortBoundaryCells()
This function sorts the boundary cells according to the BC id.
virtual void bc30034(MInt)
virtual void fastParallelGeomNormals3D(std::vector< std::pair< MInt, MInt > > own_segments)
virtual void bc30041(MInt)
virtual void bc20023(MInt)
virtual void bc30050(MInt)
virtual void bc40020(MInt)
virtual void bc20025(MInt)
virtual void bc40044(MInt)
virtual void bc30031(MInt)
virtual void bc20055(MInt)
virtual void bc40010(MInt)
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.
virtual void bc30010(MInt)
virtual void bc20052(MInt)
virtual void bc30015(MInt)
virtual void bc30033(MInt)
virtual void bc20501(MInt)
virtual void bc40041(MInt)
virtual void bc20053(MInt)
virtual void bc40060(MInt)
MBool getNormalFromSTL(GeometryElement< nDim > ge, MFloat *normal)
Get the normal from the STL.
virtual void bc30025(MInt)
virtual void bc10020(MInt)
virtual void bc10050(MInt)
void bcDataWriteRestartHeader(ParallelIo ¶llelio)
Write bndCndData info in given ParallelIo file's header.
void applyDirectionChangeOutflow(MInt index)
This function checks if for an outflow boundary the normal points into the according direction and ch...
LbBndCnd(LbSolver< nDim > *solver)
virtual void bc30044(MInt)
virtual void bc40100(MInt)
virtual void bc30035(MInt)
virtual void bc10043(MInt)
virtual void bc30011(MInt)
virtual void bc40000(MInt)
virtual void bc20027(MInt)
virtual void bc10061(MInt)
virtual void bc20030(MInt)
virtual void bc30045(MInt)
virtual void bc40001(MInt)
virtual void bc20026(MInt)
virtual MInt findBndCnd(MInt index)
This function returns the index in the array of the boundary conditions that are inflow/outflow condi...
virtual void bc10042(MInt)
virtual void postCouple()
This function does the sub coupling step called from the coupling class.
virtual void bc10045(MInt)
virtual void bc20003(MInt)
void bcDataWriteRestartData(ParallelIo ¶llelIo)
Write bndCndData data in given ParallelIo file.
virtual void bc10046(MInt)
virtual void bc40082(MInt)
virtual void bc40130(MInt)
virtual void bc20054(MInt)
virtual void solveBlasiusZ(MInt index)
Solves the Blasius equation for f,f',f".
virtual void bc30032(MInt)
virtual void bc10070(MInt)
virtual void bc30021(MInt)
virtual void bc30020(MInt)
virtual void bc20020(MInt)
virtual void bc20230(MInt)
virtual void bc10080(MInt)
virtual void bc20004(MInt)
virtual void bc40045(MInt)
This class is a ScratchSpace.
T * getPointer() const
Deprecated: use begin() instead!
pointer p
Deprecated: use [] instead!
MBool approx(const T &, const U &, const T)
std::vector< std::pair< MString, MInt > > g_tc_geometry
std::basic_string< char > MString
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
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
MInt noBndCellsWithHalos
number of boundary cells represented in data
MInt noVars
number of variables that are stored for BC
MFloat * data
pointer the relevant data
LB lattice descriptor for arrays depending on D.
static constexpr MInt idFld(MInt i, MInt j)