Loading [MathJax]/extensions/tex2jax.js
MAIA bb96820c
Multiphysics at AIA
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
fvmbcartesiansolverxd.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
8
9#include <cmath>
10#include <cstring>
11#include <iomanip>
12#include <stack>
13#include "COMM/mpiexchange.h"
14#include "COMM/mpioverride.h"
16#include "IO/parallelio.h"
17#include "UTIL/functions.h"
19#include "fvcartesiansolverxd.h"
20#include "globals.h"
21
22
23//#define _MB_DEBUG_
24#define _ALE_FORM_
25#define GEOM_CONS_LAW
26//#define VISCOUS_FLUX_FREEZING
27
28
29using namespace std;
30
31
32template <MInt nDim, class SysEqn>
34
35
39template <MInt nDim, class SysEqn>
41 const MBool* propertiesGroups,
42 maia::grid::Proxy<nDim>& gridProxy_,
43 Geometry<nDim>& geometry_, const MPI_Comm comm)
44 : FvCartesianSolverXD<nDim, SysEqn>(solverId_, noSpecies, propertiesGroups, gridProxy_, geometry_, comm),
45 m_t0(clock()),
46 m_noCVars(CV->noVariables),
47 m_noFVars(FV->noVariables),
48 m_noPVars(PV->noVariables),
49 m_noSlopes(nDim * m_noPVars),
50 m_gammaMinusOne(m_gamma - F1) {
51 TRACE();
52
54 if(this->m_fvBndryCnd == nullptr) mTerm(1, AT_, "something went wrong with the boundary condition in MB...");
55
56 m_levelSetMb = propertiesGroups[LEVELSETMB];
57 ASSERT(m_levelSetMb, "Calling fvMb without levelSetMb");
58
61}
62
63
67template <MInt nDim, class SysEqn>
69 TRACE();
70
71 const clock_t t1 = clock();
72 const MFloat t = static_cast<MFloat>(t1 - m_t0) / CLOCKS_PER_SEC;
73 m_log << "========================================" << endl;
74 m_log << "Total execution time FvMbSolver3D: " << printTime(t) << " (" << setprecision(8) << t << ")" << endl;
75 m_log << "========================================" << endl;
76}
77
78
87template <MInt nDim, class SysEqn>
89 TRACE();
90
91#ifdef _MB_DEBUG_
92 if(domainId() == 0) {
93 char hostname[256];
94 char execname[1024];
95 memset(execname, 0, sizeof(execname));
96 readlink("/proc/self/exe", execname, sizeof(execname) - 1);
97 gethostname(hostname, sizeof(hostname));
98 cerr << endl << domainId() << ": PID " << getpid() << " on " << hostname << " ready for attach." << endl;
99 cerr << domainId() << ": ssh " << hostname << " \"gdb " << execname << " " << getpid()
100 << " -ex 'tbreak initializeMb()'\"" << endl;
101 }
102#endif
103
104#ifdef _LOCAL_TIME_STEPPING
105 if(domainId() == 0) {
106 cerr << endl << "Local time stepping active!" << endl << endl;
107 }
108#endif
109
110 const MLong oldAllocatedBytes = allocatedBytes();
111
112#if defined _MB_DEBUG_ || !defined NDEBUG
113 cerr0 << "DEBUG macro enabled." << endl;
114 m_log << "DEBUG macro enabled." << endl;
115#endif
116#ifdef GEOM_CONS_LAW
117 m_log << "Geometric conservation law enabled." << endl;
118#endif
119
120 // settings
121 m_constructGField = true;
122 m_constructGField = Context::getSolverProperty<MBool>("constructGField", m_solverId, AT_, &m_constructGField);
123
140 m_motionEquation = 0;
141 m_motionEquation = Context::getSolverProperty<MInt>("motionEquation", m_solverId, AT_, &m_motionEquation);
142 m_log << "motion equation: " << m_motionEquation << endl;
143
152 m_euler = 0;
153 m_euler = Context::getSolverProperty<MBool>("euler", m_solverId, AT_, &m_euler);
154
155 m_solverType = (SolverType)string2enum(Context::getSolverProperty<MString>("solvertype", m_solverId, AT_));
156 execRungeKuttaStep = nullptr;
157
165 m_generateOuterBndryCells = 1;
166 m_generateOuterBndryCells =
167 Context::getSolverProperty<MBool>("generateOuterBndryCells", m_solverId, AT_, &m_generateOuterBndryCells);
168
184 m_centralizeSurfaceVariables = 0;
185 m_centralizeSurfaceVariables =
186 Context::getSolverProperty<MInt>("centralizeSurfaceVariables", m_solverId, AT_, &m_centralizeSurfaceVariables);
187 m_log << "centralize surface vars: " << m_centralizeSurfaceVariables << endl;
188
199 m_levelSetAdaptationScheme = 0;
200 m_levelSetAdaptationScheme =
201 Context::getSolverProperty<MInt>("adaptLevelSetExtensionScheme", m_solverId, AT_, &m_levelSetAdaptationScheme);
202
203 // this sensorMethod does not lead to a stable grid!
204 if(!m_constructGField && m_levelSetAdaptationScheme != 2) m_singleAdaptation = true;
205
213 m_haloCellOutput = false;
214 m_haloCellOutput = Context::getSolverProperty<MBool>("haloCellOutput", m_solverId, AT_, &m_haloCellOutput);
215
216 m_solutionDiverged = false;
217
218 m_movingBndryCndId = m_euler ? 3007 : 3006;
219 m_movingBndryCndId = Context::getSolverProperty<MInt>("movingBndryCndId", m_solverId, AT_, &m_movingBndryCndId);
220
221 m_loggingInterval = 100;
222 m_loggingInterval = Context::getSolverProperty<MInt>("loggingInterval", m_solverId, AT_, &m_loggingInterval);
223
235 m_bodySamplingInterval = 0;
236 m_bodySamplingInterval =
237 Context::getSolverProperty<MInt>("bodySamplingInterval", m_solverId, AT_, &m_bodySamplingInterval);
238
250 m_particleSamplingInterval = 0;
251 m_particleSamplingInterval =
252 Context::getSolverProperty<MInt>("particleSamplingInterval", m_solverId, AT_, &m_particleSamplingInterval);
253
264 m_conservationCheck = false;
265 m_conservationCheck = Context::getSolverProperty<MBool>("conservationCheck", m_solverId, AT_, &m_conservationCheck);
266
278 m_writeCenterLineData = false;
279 m_writeCenterLineData =
280 Context::getSolverProperty<MBool>("writeCenterLineData", m_solverId, AT_, &m_writeCenterLineData);
281
295 m_trackMovingBndry = true;
296 m_trackMovingBndry = Context::getSolverProperty<MBool>("trackMovingBndry", m_solverId, AT_, &m_trackMovingBndry);
297
298 m_structureStep = 0;
299 m_maxStructureSteps = 1;
300 m_maxStructureSteps = Context::getSolverProperty<MInt>("maxIterations", m_solverId, AT_, &m_maxStructureSteps);
301
302 m_gclIntermediate = m_levelSetMb;
303
304 if((m_motionEquation > 0) && !m_constructGField) {
305 mTerm(1, AT_, "Please turn on 'constructGField'-property to start fluid structure interaction!");
306 }
307
320 m_trackMbStart = 0;
321 m_trackMbStart = Context::getSolverProperty<MInt>("trackMbStart", m_solverId, AT_, &m_trackMbStart);
322
335 m_FSIStart = m_trackMbStart;
336 m_FSIStart = Context::getSolverProperty<MInt>("FSIStart", m_solverId, AT_, &m_FSIStart);
337
338 m_FSIToleranceU = 1e-6;
339 m_FSIToleranceU = Context::getSolverProperty<MFloat>("FSIToleranceU", m_solverId, AT_, &m_FSIToleranceU);
340 m_FSIToleranceX = 1e-6;
341 m_FSIToleranceX = Context::getSolverProperty<MFloat>("FSIToleranceX", m_solverId, AT_, &m_FSIToleranceX);
342 m_FSIToleranceW = 1e-5;
343 m_FSIToleranceW = Context::getSolverProperty<MFloat>("FSIToleranceW", m_solverId, AT_, &m_FSIToleranceW);
344 m_FSIToleranceR = 1e-5;
345 m_FSIToleranceR = Context::getSolverProperty<MFloat>("FSIToleranceR", m_solverId, AT_, &m_FSIToleranceR);
346
359 m_trackMbEnd = numeric_limits<MInt>::max();
360 m_trackMbEnd = Context::getSolverProperty<MInt>("trackMbEnd", m_solverId, AT_, &m_trackMbEnd);
361
362 m_noLevelSetsUsedForMb = 1;
363 m_noLevelSetsUsedForMb = Context::getSolverProperty<MInt>("maxNoLevelSets", m_solverId, AT_, &m_noLevelSetsUsedForMb);
364
365 m_lsCutCellBaseLevel = -1;
366 m_lsCutCellMinLevel = 99;
367 mAlloc(m_lsCutCellLevel, m_noLevelSetsUsedForMb, "m_lsCutCellLevel", maxRefinementLevel(), AT_);
368
369 if(!Context::propertyExists("cutCellLevel", m_solverId)) {
370 m_lsCutCellBaseLevel = maxRefinementLevel();
371 m_lsCutCellMinLevel = maxRefinementLevel();
372 } else {
373 ASSERT(Context::propertyLength("cutCellLevel", m_solverId) == m_noLevelSetsUsedForMb, "");
374 m_lsCutCellBaseLevel = Context::getSolverProperty<MInt>("cutCellLevel", m_solverId, AT_, 0);
375
376 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
377 m_lsCutCellLevel[set] = Context::getSolverProperty<MInt>("cutCellLevel", m_solverId, AT_, set);
378 m_lsCutCellMinLevel = mMin(m_lsCutCellMinLevel, m_lsCutCellLevel[set]);
379 }
380 }
381
382 ASSERT(m_lsCutCellBaseLevel <= maxRefinementLevel() && m_lsCutCellBaseLevel >= maxUniformRefinementLevel()
383 && m_lsCutCellMinLevel <= maxRefinementLevel() && m_lsCutCellMinLevel >= maxUniformRefinementLevel(),
384 "");
385
386 MInt maxSensorLevel = 0;
387 for(MInt s = 0; s < this->m_noSensors; s++) {
388 maxSensorLevel = mMax(maxSensorLevel, this->m_maxSensorRefinementLevel[s]);
389 }
390
391
392 m_bndryLevelJumps = false;
393 if(maxRefinementLevel() != m_lsCutCellBaseLevel || maxRefinementLevel() != m_lsCutCellMinLevel) {
394 if(!m_multilevel) {
395 m_bndryLevelJumps = true;
396 cerr0 << "Warning: Using different levels for levelset bndryd: cutCellBaseLevel ( " << m_lsCutCellBaseLevel
397 << ") , maxRefinementLevel (" << maxRefinementLevel() << ") and cutCellMinLevel ( " << m_lsCutCellMinLevel
398 << " )" << endl;
399 } else {
400 cerr0 << "Solver " << m_solverId << " is multi-level secondary with maxLevel " << maxLevel()
401 << ", maxRefinementLevel " << maxRefinementLevel() << ", maxSensorLevel " << maxSensorLevel
402 << " and cutCellLevel " << m_lsCutCellBaseLevel << endl;
403 }
404
405 // update m_bandWidth:
406 MFloat distFac[2] = {18.0, 9.0};
407 for(MInt i = 0; i < 2; i++) {
408 distFac[i] = Context::getSolverProperty<MFloat>("mbBandWidth", m_solverId, AT_, &distFac[i], i);
409 }
410 m_bandWidth[m_lsCutCellBaseLevel - 1] = distFac[0];
411 for(MInt i = maxRefinementLevel() - 2; i >= 0; i--) {
412 m_bandWidth[i] = (m_bandWidth[i + 1] / 2) + 1 + distFac[1];
413 }
414 }
415
416 m_maxLevelChange = false;
417 if(globalTimeStep > 0 && isActive() && m_restartFile && maxLevel() != maxRefinementLevel() && !m_bndryLevelJumps
418 && !m_multilevel) {
419 cerr0 << "MaxLevel is " << maxLevel() << " and maxRefinementLevel is " << maxRefinementLevel()
420 << " => temporarily reduction of lsCutCellMinLevel to MaxLevel! " << endl;
421 m_maxLevelChange = true;
422 m_lsCutCellMinLevel = maxLevel();
423 m_bndryLevelJumps = true;
424 }
425
426
427 m_maxLevelDecrease = false;
428 if(globalTimeStep > 0 && m_restartFile && isActive() && this->m_adaptation && maxLevel() > maxSensorLevel) {
429 m_maxLevelDecrease = true;
430 cerr0 << "MaxLevel will be reduced from " << maxLevel() << " to " << maxSensorLevel << endl;
431 ASSERT(m_lsCutCellMinLevel <= maxSensorLevel, "");
432 }
433
452 m_bodyTypeMb = 1;
453 m_bodyTypeMb = Context::getSolverProperty<MInt>("bodyTypeMb", m_solverId, AT_, &m_bodyTypeMb);
454 if(m_bodyTypeMb < 0 || m_bodyTypeMb > 7) {
455 mTerm(1, AT_, "Unknown body type!");
456 }
457
469 m_logBoundaryData = false;
470 m_logBoundaryData = Context::getSolverProperty<MBool>("logBoundaryData", m_solverId, AT_, &m_logBoundaryData);
471
472 m_recordBodyData = true;
473
474 m_trackBodySurfaceData = true;
475 m_trackBodySurfaceData =
476 Context::getSolverProperty<MBool>("trackBodySurfaceData", m_solverId, AT_, &m_trackBodySurfaceData);
477
478 if(m_outputOffset > 0) m_solutionOffset = m_outputOffset;
479
480 // TODO labels:FVMB,DOC,toremove remove depricated version use balanceInterval instead!
481 m_onlineRestart = false;
482 m_onlineRestartInterval = 0;
483 m_onlineRestartInterval =
484 Context::getSolverProperty<MInt>("onlineRestartInterval", m_solverId, AT_, &m_onlineRestartInterval);
485
495 m_complexBoundary = false;
496 m_complexBoundary = Context::getSolverProperty<MBool>("complexBoundaryForMb", m_solverId, AT_, &m_complexBoundary);
497
498 m_physicalTime = F0;
499 m_physicalTimeDt1 = F0;
500
501 const MInt maxNoCells = maxNoGridCells();
502
503 // offsets & counters
504 m_noFlowCells = 0;
505 m_noSurfaces = 0;
506 m_noBndryCells = 0;
507 m_noOuterBndryCells = 0;
508 m_noLsMbBndryCells = 0;
509 m_deleteNeighbour = false;
510 m_noNearBndryCells = 0;
511 m_noEmergedCells = 0;
512 m_noEmergedWindowCells = 0;
513 m_reconstructionDataSize = 0;
514 m_bndryCellSurfacesOffset = 0;
515 m_bndrySurfacesOffset = 0;
516 m_totalnosplitchilds = 0;
517
518 mAlloc(m_gridCellArea, maxRefinementLevel() + 1, "m_gridCellArea", -F1, AT_);
519
520 for(MInt level = 0; level < maxRefinementLevel() + 1; level++) {
521 m_gridCellArea[level] = F1;
522 for(MInt spaceId = 1; spaceId < nDim; spaceId++) {
523 m_gridCellArea[level] *= c_cellLengthAtLevel(level);
524 }
525 }
526
527 mAlloc(m_gravity, 3, "m_gravity", F0, AT_);
528
529 cerr0 << "min/max cell length is " << setprecision(15) << c_cellLengthAtLevel(maxRefinementLevel()) << "/"
530 << c_cellLengthAtLevel(maxUniformRefinementLevel()) << setprecision(6) << endl;
531
532 MInt maxFacesXD = m_noDirs + FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces;
533 MInt maxPointsXD = 12;
534 IF_CONSTEXPR(nDim == 3) maxPointsXD = 12;
535 m_noSurfacePointSamples = 0;
536
547 m_maxNoSurfacePointSamples = m_fvBndryCnd->m_maxNoBndryCells;
548 m_maxNoSurfacePointSamples =
549 Context::getSolverProperty<MInt>("maxNoSurfacePointSamples", m_solverId, AT_, &m_maxNoSurfacePointSamples);
550
551 m_maxNoSampleNghbrs = 6;
552 m_stableVolumeFraction = m_fvBndryCnd->m_volumeLimitWall;
553
565 m_timeStepAdaptationStart = -1;
566 m_timeStepAdaptationStart =
567 Context::getSolverProperty<MInt>("timeStepAdaptationStart", m_solverId, AT_, &m_timeStepAdaptationStart);
568
580 m_timeStepAdaptationEnd = -1;
581 m_timeStepAdaptationEnd =
582 Context::getSolverProperty<MInt>("timeStepAdaptationEnd", m_solverId, AT_, &m_timeStepAdaptationEnd);
583
595 m_cflInitial = Context::getSolverProperty<MFloat>("cflInitial", m_solverId, AT_, &m_cfl);
596 m_cflTarget = m_cfl;
597
598 m_g = F0;
599 m_Fr = F1;
600
612 if(Context::propertyExists("Froude", m_solverId)) {
613 m_Fr = Context::getSolverProperty<MFloat>("Froude", m_solverId, AT_, &m_Fr);
614 m_g = POW2(m_Ma / m_Fr);
615 } else if(Context::propertyExists("gravitationalAcceleration", m_solverId)) {
627 m_g = Context::getSolverProperty<MFloat>("gravitationalAcceleration", m_solverId, AT_, &m_g);
628 m_Fr = m_Ma / sqrt(m_g);
629 }
630 if(Context::propertyExists("gravity", m_solverId)) {
639 for(MInt i = 0; i < nDim; i++)
640 m_gravity[i] = Context::getSolverProperty<MFloat>("gravity", m_solverId, AT_, i);
641 m_g = mMax(mMax(m_gravity[0], m_gravity[1]), m_gravity[2]);
642 m_log << "gravity: " << m_gravity[0] << " " << m_gravity[1] << " " << m_gravity[2] << ", Froude: " << F1 / sqrt(m_g)
643 << endl;
644 } else {
645 m_gravity[2] = -m_g;
646 }
647 m_log << "gravity: " << m_g << ", Froude: " << m_Fr << endl;
648
649 MInt noPeriodicDirs = 0;
650 for(MInt dir = 0; dir < nDim; dir++) {
651 if(grid().periodicCartesianDir(dir)) noPeriodicDirs++;
652 }
653
654 m_maxBndryLayerLevel = maxRefinementLevel();
655 m_maxBndryLayerWidth = 6;
656 m_outsideFactor = F2;
657
658 // body properties
659 // m_noEmbeddedBodies might already initialized in readLevelSetProperties() (called by constructor of base class
660 // fvsolverxd.cpp)
661 m_noEmbeddedBodies = 1;
662 if(!Context::propertyExists("bodyBndryCndIds", m_solverId) || !m_complexBoundary) {
663 m_noEmbeddedBodies = Context::getSolverProperty<MInt>("noEmbeddedBodies", m_solverId, AT_, &m_noEmbeddedBodies);
664 } else {
665 m_noEmbeddedBodies = Context::propertyLength("bodyBndryCndIds", m_solverId);
666 }
667 m_log << "noEmbeddedBodies " << m_noEmbeddedBodies << endl;
668 m_noPeriodicGhostBodies = 0;
669
670 m_maxNoEmbeddedBodiesPeriodic = (noPeriodicDirs > 0)
671 ? ((m_noEmbeddedBodies < 100) ? 12 * m_noEmbeddedBodies : 4 * m_noEmbeddedBodies)
672 : m_noEmbeddedBodies;
673 if(m_noEmbeddedBodies > 9999 && noPeriodicDirs > 0) {
674 m_maxNoEmbeddedBodiesPeriodic =
675 m_noEmbeddedBodies + m_noEmbeddedBodies / 2; // typical values are 25% periodic particles
676 }
677 m_log << "m_maxNoEmbeddedBodiesPeriodic"
678 << " " << m_maxNoEmbeddedBodiesPeriodic << endl;
679
680 // allocate body memory and fill with (mostly) zeroes
681 allocateBodyMemory(0);
682
683 mAlloc(m_levelSetValuesMb, m_noLevelSetsUsedForMb * maxNoCells, "m_levelSetValuesMb", F0, AT_);
684
685 m_bndryCandidateIds.reserve(maxNoCells);
686
687 m_maxNearestBodies = 20;
688 m_maxNearestBodies = Context::getSolverProperty<MInt>("maxNearestBodies", m_solverId, AT_, &m_maxNearestBodies);
689 MInt noParticles = 0;
690
691 if(isActive() && m_noEmbeddedBodies > 0) {
692 m_particleOffsets.push_back(0);
693 for(MLong dom = 0; dom < noDomains(); dom++) {
694 MLong tmpv = (((MLong)m_noEmbeddedBodies) * (dom + 1)) / ((MLong)noDomains());
695 if(tmpv > numeric_limits<MInt>::max()) mTerm(1, "int overflow");
696 m_particleOffsets.push_back((MInt)tmpv);
697 }
698 noParticles = m_particleOffsets[domainId() + 1] - m_particleOffsets[domainId()];
699 }
700 m_slipInterval = Context::propertyExists("slipInterval", 0)
701 ? Context::getSolverProperty<MInt>("slipInterval", m_solverId, AT_, &m_slipInterval)
702 : 0;
703 m_saveSlipInterval = 0;
704 if(m_noEmbeddedBodies > 0 && m_slipInterval > 0) {
705 // There are different possibilities for particle-fluid-interaction statistics
706 MInt noSetups = m_noAngleSetups * m_noDistSetups;
707 m_saveSlipInterval = Context::propertyExists("saveSlipInterval", 0)
708 ? Context::getSolverProperty("saveSlipInterval", m_solverId, AT_, &m_saveSlipInterval)
709 : 0;
710 // Allocate memory for particle-fluid-interaction statistics which will be stored every m_slipInterval and written
711 // to file every m_saveSlipInterval. This is only required for post-processing and eventually has to move to the
712 // post processing class
713 m_noSlipDataOutputs = m_saveSlipInterval / m_slipInterval;
714 if(m_noSlipDataOutputs < 1) {
715 mTerm(0, "Properties saveSlipInterval and slipInterval inconsistent.");
716 }
717 mAlloc(m_slipDataParticleCollision, mMax(1, noParticles) * m_noSlipDataOutputs * 1, "m_slipDataParticleCollision",
718 -5, AT_);
719 mAlloc(m_slipDataParticleQuaternion, mMax(1, noParticles) * m_noSlipDataOutputs * 4, "m_slipDataParticleQuaternion",
720 -F1, AT_);
721 mAlloc(m_slipDataParticleVel, mMax(1, noParticles) * m_noSlipDataOutputs * nDim, "m_slipDataParticleVel", -F1, AT_);
722 mAlloc(m_slipDataParticleAngularVel, mMax(1, noParticles) * m_noSlipDataOutputs * 3, "m_slipDataParticleAngularVel",
723 -F1, AT_);
724 mAlloc(m_slipDataParticleForce, mMax(1, noParticles) * m_noSlipDataOutputs * nDim, "m_slipDataParticleForce", -F1,
725 AT_);
726 mAlloc(m_slipDataParticleTorque, mMax(1, noParticles) * m_noSlipDataOutputs * 3, "m_slipDataParticleTorque", -F1,
727 AT_);
728 mAlloc(m_slipDataParticleFluidVel, mMax(1, noParticles) * m_noSlipDataOutputs * noSetups * nDim,
729 "m_slipDataParticleFluidVel", -F1, AT_);
730 mAlloc(m_slipDataParticleFluidVelGrad, mMax(1, noParticles) * m_noSlipDataOutputs * noSetups * POW2(nDim),
731 "m_slipDataParticleFluidVelGrad", -F1, AT_);
732 mAlloc(m_slipDataParticleFluidVelRot, mMax(1, noParticles) * m_noSlipDataOutputs * noSetups * 3,
733 "m_slipDataParticleFluidVelRot", -F1, AT_);
734 mAlloc(m_slipDataParticlePosition, mMax(1, noParticles) * m_noSlipDataOutputs * nDim, "m_slipDataParticlePosition",
735 -F1, AT_);
736 }
737
738 m_bndryLayerCells.reserve(m_fvBndryCnd->m_maxNoBndryCells);
739 mAlloc(m_volumeFraction, m_fvBndryCnd->m_maxNoBndryCells, "m_volumeFraction", -F1, AT_);
740 mAlloc(m_maxBndryLayerDistances, m_maxBndryLayerLevel + 1, 2, "m_maxBndryLayerDistances", F0, AT_);
741 mAlloc(m_associatedBodyIds, m_noLevelSetsUsedForMb * maxNoCells, "m_associatedBodyIds", -1, AT_);
742 mAlloc(m_stableCellVolume, m_maxBndryLayerLevel + 1, "m_stableCellVolume", F0, AT_);
743 mAlloc(m_cellVolumesDt1, maxNoCells, "m_cellVolumesDt1", F0, AT_);
744 if(m_dualTimeStepping) {
745 mAlloc(m_cellVolumesDt2, maxNoCells, "m_cellVolumesDt2", F0, AT_);
746 }
747 mAlloc(m_sweptVolume, m_fvBndryCnd->m_maxNoBndryCells, "m_sweptVolume", F0, AT_);
748 mAlloc(m_sweptVolumeDt1, m_fvBndryCnd->m_maxNoBndryCells, "m_sweptVolumeDt1", F0, AT_);
749 mAlloc(m_rhs0, maxNoCells, m_noFVars, "m_rhs0", F0, AT_);
750
751#ifdef VISCOUS_FLUX_FREEZING
752 mAlloc(m_rhsViscous, maxNoCells, m_noFVars, "m_rhsViscous", F0, AT_);
753#else
754 m_rhsViscous = nullptr;
755#endif
756
757 mAlloc(m_noCutCellFaces, m_fvBndryCnd->m_maxNoBndryCells, "m_noCutCellFaces", 0, AT_);
758 mAlloc(m_cutFacePointIds, m_fvBndryCnd->m_maxNoBndryCells, maxFacesXD * maxPointsXD, "m_cutFacePointIds", -1, AT_);
759 mAlloc(m_noCutFacePoints, m_fvBndryCnd->m_maxNoBndryCells, maxFacesXD, "m_noCutFacePoints", 0, AT_);
760 mAlloc(m_cutFaceArea, m_fvBndryCnd->m_maxNoBndryCells, m_noDirs, "m_cutFaceArea", F0, AT_);
761 mAlloc(m_pointIsInside, m_fvBndryCnd->m_maxNoBndryCells, m_noLevelSetsUsedForMb * m_noCellNodes, "m_pointIsInside",
762 false, AT_);
763 mAlloc(m_bbox, 2 * nDim, "m_bbox", F0, AT_);
764 mAlloc(m_bboxLocal, 2 * nDim, "m_bboxLocal", F0, AT_);
765 mAlloc(m_nghbrList, 27 * m_noCellNodes, "m_nghbrList", -1, AT_);
766 mAlloc(m_sendBufferSize, mMax(1, noNeighborDomains()), "m_sendBufferSize", 0, AT_);
767 mAlloc(m_receiveBufferSize, mMax(1, noNeighborDomains()), "m_receiveBufferSize", 0, AT_);
768 mAlloc(g_mpiRequestMb, mMax(1, noNeighborDomains()), "g_mpiRequestMb", MPI_REQ_NULL, AT_);
769 mAlloc(m_cellSurfaceMapping, maxNoCells, m_noDirs, "m_cellSurfaceMapping", -1, AT_);
770
782 m_noPointParticles = 0;
783 m_noPointParticles = Context::getSolverProperty<MInt>("noPointParticles", m_solverId, AT_, &m_noPointParticles);
784 m_noPointParticlesLocal = 0;
785
800 m_pointParticleType = 1;
801 m_pointParticleType = Context::getSolverProperty<MInt>("pointParticleType", m_solverId, AT_, &m_pointParticleType);
802
815 m_pointParticleTwoWayCoupling = 0;
816 m_pointParticleTwoWayCoupling =
817 Context::getSolverProperty<MInt>("pointParticleTwoWayCoupling", m_solverId, AT_, &m_pointParticleTwoWayCoupling);
818
830 mAlloc(m_particleTerminalVelocity, nDim, "m_particleTerminalVelocity", F0, AT_);
831 if(Context::propertyExists("particleTerminalVelocity", m_solverId)) {
832 for(MInt dir = 0; dir < nDim; dir++) {
833 m_particleTerminalVelocity[dir] = Context::getSolverProperty<MFloat>("particleTerminalVelocity", m_solverId, AT_,
834 &m_particleTerminalVelocity[dir], dir);
835 }
836 }
837 if(m_pointParticleTwoWayCoupling == 1 && m_noPointParticles > 0) {
838 mAlloc(m_coupling, maxNoGridCells(), nDim, "m_coupling", F0, AT_);
839 }
840
841 m_couplingRate = F0;
842 m_particleCoords.clear();
843 m_particleCoordsDt1.clear();
844 m_particleVelocity.clear();
845 m_particleTemperature.clear();
846 m_particleTemperatureDt1.clear();
847 m_particleHeatFlux.clear();
848 m_particleVelocityDt1.clear();
849 m_particleVelocityFluid.clear();
850 m_particleFluidTemperature.clear();
851 m_particleAcceleration.clear();
852 m_particleAccelerationDt1.clear();
853 m_particleQuaternions.clear();
854 m_particleQuaternionsDt1.clear();
855 m_particleAngularVelocity.clear();
856 m_particleAngularVelocityDt1.clear();
857 m_particleVelocityGradientFluid.clear();
858 m_particleAngularAcceleration.clear();
859 m_particleAngularAccelerationDt1.clear();
860 m_particleShapeParams.clear();
861 m_particleRadii.clear();
862 m_particleCellLink.clear();
863
864 m_linkedWindowCells = nullptr;
865 m_linkedHaloCells = nullptr;
866
867 mAlloc(m_linkedWindowCells, mMax(1, noNeighborDomains()), "m_linkedWindowCells", AT_);
868 mAlloc(m_linkedHaloCells, mMax(1, noNeighborDomains()), "m_linkedHaloCells", AT_);
869
870 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
871 m_internalBodyId[b] = b;
872 }
873
874 std::vector<MInt>().swap(m_bndryLayerCells);
875
876 for(MInt i = 0; i <= m_maxBndryLayerLevel; i++) {
877 m_maxBndryLayerDistances[i][0] = -c_cellLengthAtLevel(i) * F3;
878 m_maxBndryLayerDistances[i][1] = c_cellLengthAtLevel(i) * (MFloat)m_maxBndryLayerWidth;
879 m_log << "bndry layer width level " << i << ": " << m_maxBndryLayerDistances[i][0] << " "
880 << m_maxBndryLayerDistances[i][1] << endl;
881 }
882
883 if(m_adaptation) {
884 m_bodyDistThreshold = 1.1
885 * (mMax(m_outerBandWidth[mMin(maxUniformRefinementLevel(), maxRefinementLevel() - 1)],
886 m_maxBndryLayerDistances[maxRefinementLevel()][1])
887 + c_cellLengthAtLevel(minLevel()));
888 m_periodicGhostBodyDist = 1.1
889 * (m_outerBandWidth[mMin(maxUniformRefinementLevel(), maxRefinementLevel() - 1)]
890 + ((MFloat)noHaloLayers()) * c_cellLengthAtLevel(minLevel()));
891 } else {
892 m_bodyDistThreshold = 1.1 * m_maxBndryLayerDistances[maxRefinementLevel()][1] + c_cellLengthAtLevel(minLevel());
893 m_periodicGhostBodyDist = 1.1 * ((MFloat)noHaloLayers()) * c_cellLengthAtLevel(minLevel());
894 }
895 m_log << "body dist threshold " << m_bodyDistThreshold << " " << m_periodicGhostBodyDist << endl;
896
897 for(MInt i = 0; i <= m_maxBndryLayerLevel; i++) {
898 m_stableCellVolume[i] = grid().gridCellVolume(i) * m_stableVolumeFraction;
899 }
900
901 // collision triggers
902 m_applyCollisionModel = (m_initialCondition == 15 || m_initialCondition == 16);
903 m_applyCollisionModel =
904 Context::getSolverProperty<MBool>("applyCollisionModel", m_solverId, AT_, &m_applyCollisionModel);
905
906 m_massRedistributionIds.clear();
907 m_massRedistributionVariables.clear();
908 m_massRedistributionRhs.clear();
909 m_massRedistributionVolume.clear();
910 m_massRedistributionSweptVol.clear();
911 m_temporarilyLinkedCells.clear();
912
913 m_splitCells.clear();
914 m_splitChilds.clear();
915 m_splitChildToSplitCell.clear();
916
917 m_gapOpened = false;
918
919 m_fvBndryCnd->m_noBoundarySurfaces = 0;
920
921 if(domainId() == 0) {
922 if(fileExists("Residual")) {
923 remove("Residual");
924 }
925 }
926
927 computeLocalBoundingBox();
928 for(MInt i = 0; i < 2 * nDim; i++) {
929 m_bbox[i] = m_bboxLocal[i];
930 }
931
932 if(isActive()) {
933 MPI_Allreduce(MPI_IN_PLACE, &m_bbox[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "m_bbox[0]");
934 MPI_Allreduce(MPI_IN_PLACE, &m_bbox[nDim], nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
935 "m_bbox[nDim]");
936 }
937
938 if(domainId() == 0) {
939 cerr << "bounding box: " << setprecision(15);
940 for(MInt i = 0; i < nDim; i++)
941 cerr << m_bbox[i] << ":" << m_bbox[nDim + i] << " ";
942 cerr << setprecision(6) << endl;
943 m_log << "bounding box: ";
944 for(MInt i = 0; i < nDim; i++)
945 m_log << m_bbox[i] << ":" << m_bbox[nDim + i] << " ";
946 m_log << endl;
947 }
948
949 stringstream solver_data;
950 solver_data.str("");
951 solver_data << m_solutionOutput;
952 solver_data << "/solver_data";
953 struct stat s0 {};
954 if(stat((solver_data.str()).c_str(), &s0) < 0) {
955#if defined(MAIA_MS_COMPILER)
956#pragma message("WARNING: Not compatible")
957 mTerm(0, "ERROR: Not implemented!");
958#else
959 mkdir((solver_data.str()).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
960#endif
961 }
962
963 m_log << "eps is " << m_eps << endl;
964
965 m_geometryIntersection = new GeometryIntersection<nDim>(&grid(), m_geometry);
966
967 m_closeGaps = Context::getSolverProperty<MBool>("closeGaps", m_solverId, AT_, &m_closeGaps);
968 m_gapInitMethod = 2;
969 m_noGapRegions = 0;
970
971 if(m_closeGaps) {
972 // Gap-Properties and Settings:
985 m_gapInitMethod = Context::getSolverProperty<MInt>("gapInitMethod", 0, AT_, &m_gapInitMethod);
986 m_noGapRegions = Context::getSolverProperty<MInt>("noGapRegions", 0, AT_, &m_noGapRegions);
987
988 mAlloc(m_gapState, m_noGapRegions, "m_gapState", 0, AT_);
989
990 m_gapCells.clear();
991
992 m_gapWindowCells = nullptr;
993 m_gapHaloCells = nullptr;
994 mAlloc(m_gapWindowCells, noNeighborDomains(), "m_gapWindowCells", AT_);
995 mAlloc(m_gapHaloCells, noNeighborDomains(), "m_gapHaloCells", AT_);
996 }
997
998 m_LsMovement = false;
999 m_LsMovement = Context::getSolverProperty<MBool>("LsMovement", m_solverId, AT_, &m_LsMovement);
1000
1007 m_LsRotate = false;
1008 m_LsRotate = Context::getSolverProperty<MBool>("LsRotate", m_solverId, AT_, &m_LsRotate);
1009 if(m_LsRotate) {
1010 m_refineDiagonals = false;
1011 }
1012
1013 m_alwaysResetCutOff = false;
1014 m_alwaysResetCutOff = Context::getSolverProperty<MBool>("resetCutOff", m_solverId, AT_, &m_alwaysResetCutOff);
1015
1016 m_maxIterations = 1;
1017 m_maxIterations = Context::getSolverProperty<MInt>("maxIterations", m_solverId, AT_, &m_maxIterations);
1018
1019 if(!Context::propertyExists("bodyIdOutput", m_solverId)) {
1020 m_bodyIdOutput = m_bodyIdOutput || !m_constructGField;
1021 }
1022 if(!Context::propertyExists("levelSetOutput", m_solverId)) {
1023 m_levelSetOutput = m_levelSetOutput || !m_constructGField;
1024 }
1025
1026 if(m_constructGField) initAnalyticalLevelSet();
1027
1028 m_reConstSVDWeightMode = 1;
1029 if(m_bndryLevelJumps) m_reConstSVDWeightMode = 0;
1030
1045 m_reConstSVDWeightMode =
1046 Context::getSolverProperty<MInt>("reConstSVDWeightMode", m_solverId, AT_, &m_reConstSVDWeightMode);
1047
1048 if(m_bndryLevelJumps) {
1049 ASSERT(m_reConstSVDWeightMode != 1, "Mode not working for bndry-level-jumps!");
1050 }
1051
1059 m_engineSetup = Context::getSolverProperty<MBool>("engineSetup", m_solverId, AT_, &m_engineSetup);
1060
1068 m_linerLvlJump = Context::getSolverProperty<MBool>("linerLevelJump", m_solverId, AT_, &m_linerLvlJump);
1069
1070 if(domainId() == 0 && m_engineSetup) {
1071 cerr << "Applying engine setup with " << m_linerLvlJump << "liner level Jumps!" << endl;
1072 }
1073
1074 if(m_linerLvlJump) ASSERT(m_engineSetup, "");
1075
1076 if(m_engineSetup) {
1089 m_forceNoGaps = 0;
1090 m_forceNoGaps = Context::getSolverProperty<MInt>("forceNoGaps", m_solverId, AT_, &m_forceNoGaps);
1091
1092 MInt noGapRegions = 0;
1093 noGapRegions = Context::getSolverProperty<MInt>("noGapRegions", m_solverId, AT_, &noGapRegions);
1094
1095 if(m_forceNoGaps == 1) { // surpress gap cells for multi-valve engine
1096
1097 mAlloc(m_gapAngleClose, noGapRegions, "m_gapAngleClose", F0, AT_);
1098 mAlloc(m_gapAngleOpen, noGapRegions, "m_gapAngleOpen", F0, AT_);
1099 mAlloc(m_gapSign, noGapRegions, "m_gapSign", F1, AT_);
1100
1101 for(MInt i = 0; i < noGapRegions; i++) {
1102 m_gapAngleClose[i] =
1103 Context::getSolverProperty<MFloat>("gapAngleClose", m_solverId, AT_, &m_gapAngleClose[i], i);
1104 m_gapAngleOpen[i] = Context::getSolverProperty<MFloat>("gapAngleOpen", m_solverId, AT_, &m_gapAngleClose[i], i);
1105 if(m_gapAngleClose[i] < 0.0) {
1106 m_gapAngleClose[i] = 720 + m_gapAngleClose[i];
1107 }
1108 if(m_gapAngleOpen[i] < 0.0) {
1109 m_gapAngleOpen[i] = 720 + m_gapAngleOpen[i];
1110 }
1111 if(m_gapAngleOpen[i] > m_gapAngleClose[i]) {
1112 m_gapSign[i] = -1;
1113 }
1114 }
1115 } else if(m_forceNoGaps == 2) { // surpress gap cells for single-valve engine
1116
1117 ASSERT(noGapRegions == 1, "Mode only intended for 1 gap-region!");
1118
1119 mAlloc(m_gapAngleClose, noGapRegions + 1, "m_gapAngleClose", F0, AT_);
1120 mAlloc(m_gapAngleOpen, noGapRegions + 1, "m_gapAngleOpen", F0, AT_);
1121 mAlloc(m_gapSign, noGapRegions + 1, "m_gapSign", F1, AT_);
1122
1123 ASSERT(noGapRegions + 1 == Context::propertyLength("gapAngleOpen", m_solverId), "");
1124
1125 for(MInt i = 0; i < noGapRegions + 1; i++) {
1126 m_gapAngleClose[i] =
1127 Context::getSolverProperty<MFloat>("gapAngleClose", m_solverId, AT_, &m_gapAngleClose[i], i);
1128 m_gapAngleOpen[i] = Context::getSolverProperty<MFloat>("gapAngleOpen", m_solverId, AT_, &m_gapAngleClose[i], i);
1129 if(m_gapAngleClose[i] < 0.0) {
1130 m_gapAngleClose[i] = 720 + m_gapAngleClose[i];
1131 }
1132 if(m_gapAngleOpen[i] < 0.0) {
1133 m_gapAngleOpen[i] = 720 + m_gapAngleOpen[i];
1134 }
1135 if(m_gapAngleOpen[i] > m_gapAngleClose[i]) {
1136 m_gapSign[i] = -1;
1137 }
1138 }
1139 }
1140 }
1141
1142 if(Context::propertyExists("LsGeometryChange", m_solverId)) {
1143 mAlloc(m_geometryChange, m_noLevelSetsUsedForMb, "geometryChange", false, AT_);
1144
1145 MBool anychange = false;
1146 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
1147 m_geometryChange[set] =
1148 Context::getSolverProperty<MBool>("LsGeometryChange", m_solverId, AT_, &m_geometryChange[set], set);
1149 if(m_geometryChange[set]) anychange = true;
1150 }
1151
1152 if(!anychange) {
1153 mDeallocate(m_geometryChange);
1154 ASSERT(m_geometryChange == nullptr, "");
1155 }
1156 }
1157
1158 m_dynamicStencil = false;
1159 m_dynamicStencil = Context::getSolverProperty<MBool>("dynamicStencil", m_solverId, AT_, &m_dynamicStencil);
1160
1161 m_reComputedBndry = true;
1162
1163 if(isActive()) printAllocatedMemory(oldAllocatedBytes, "FvMbSolver", mpiComm());
1164
1165 if(m_hasExternalSource /*&& g_splitMpiComm*/) {
1166 mAlloc(m_externalSourceDt1, maxNoGridCells(), CV->noVariables, "m_externalForces", 0.0, AT_);
1167 m_log << "Allocated memory for old external sources." << endl;
1168 }
1169
1170 if(grid().azimuthalPeriodicity()) {
1171 m_noFloatDataBalance = 3 + CV->noVariables; // cellVol, cellVollDt1, sweptVol, vars
1172 m_noFloatDataAdaptation = 3; // cellVol, cellVollDt1, sweptVol
1173 m_noLongData = 2; // m_oldBndryCells.count(), cell properties
1174 m_noLongDataBalance = 3; // globalId, m_oldBndryCells.count(), cell properties
1175 }
1176
1177 if(calcSlopesAfterStep()) mTerm(1, AT_, "calcSlopesAfterStep not implemented for FvMb");
1178}
1179
1180
1185template <MInt nDim, class SysEqn>
1187 if(mode == 1) {
1188 mDeallocate(m_bodyTerminalVelocity);
1189 mDeallocate(m_bodyCenter);
1190 mDeallocate(m_projectedArea);
1191 mDeallocate(m_bodyRadii);
1192 mDeallocate(m_bodyRadius);
1193 mDeallocate(m_bodyDiameter);
1194 mDeallocate(m_bodyVelocity);
1195 mDeallocate(m_bodyAcceleration);
1196 mDeallocate(m_bodyAngularVelocity);
1197 mDeallocate(m_bodyAngularVelocityDt1);
1198 mDeallocate(m_bodyTorque);
1199 mDeallocate(m_bodyTorqueDt1);
1200 mDeallocate(m_bodyQuaternion);
1201 mDeallocate(m_bodyQuaternionDt1);
1202 mDeallocate(m_bodyAngularAcceleration);
1203 mDeallocate(m_bodyAngularAccelerationDt1);
1204 mDeallocate(m_bodyDensity);
1205 mDeallocate(m_bodyMomentOfInertia);
1206 mDeallocate(m_bodyAccelerationDt1);
1207 mDeallocate(m_bodyVelocityDt1);
1208 mDeallocate(m_bodyCenterDt1);
1209
1210 if(m_motionEquation > 1) {
1211 mDeallocate(m_bodyCenterDt2);
1212 mDeallocate(m_bodyVelocityDt2);
1213 mDeallocate(m_bodyAccelerationDt2);
1214 mDeallocate(m_bodyAccelerationDt3);
1215
1216 mDeallocate(m_bodyReducedVelocity);
1217 mDeallocate(m_bodyReducedFrequency);
1218 mDeallocate(m_bodyReducedMass);
1219 mDeallocate(m_bodyDampingCoefficient);
1220
1221 mDeallocate(m_bodyNeutralCenter);
1222 }
1223
1224 mDeallocate(m_bodyForce);
1225 mDeallocate(m_bodyHeatFlux);
1226 mDeallocate(m_bodyForceDt1);
1227 mDeallocate(m_hydroForce);
1228
1229 mDeallocate(m_bodyTemperature);
1230 mDeallocate(m_bodyTemperatureDt1);
1231 mDeallocate(m_bodyEquation);
1232 mDeallocate(m_bodyInCollision);
1233 mDeallocate(m_periodicGhostBodies);
1234 mDeallocate(m_internalBodyId);
1235 mDeallocate(m_bodyNearDomain);
1236
1237 mDeallocate(m_fixedBodyComponents);
1238 mDeallocate(m_fixedBodyComponentsRotation);
1239 }
1240
1241 mAlloc(m_bodyTerminalVelocity, nDim, "m_bodyTerminalVelocity", F0, AT_);
1242
1243 mAlloc(m_bodyCenter, nDim * m_maxNoEmbeddedBodiesPeriodic, "m_bodyCenter", F0, AT_);
1244 mAlloc(m_bodyVolume, m_noEmbeddedBodies, "m_bodyVolume", F0, AT_);
1245 mAlloc(m_bodyMass, m_noEmbeddedBodies, "m_bodyMass", F0, AT_);
1246 mAlloc(m_projectedArea, m_noEmbeddedBodies, "m_projectedArea", F0, AT_);
1247 mAlloc(m_bodyRadii, 3 * m_maxNoEmbeddedBodiesPeriodic, "m_bodyRadii", F0, AT_);
1248 mAlloc(m_bodyRadius, m_maxNoEmbeddedBodiesPeriodic, "m_bodyRadius", F0, AT_);
1249 mAlloc(m_bodyDiameter, m_maxNoEmbeddedBodiesPeriodic, "m_bodyDiameter", F0, AT_);
1250 mAlloc(m_bodyVelocity, nDim * m_maxNoEmbeddedBodiesPeriodic, "m_bodyVelocity", F0, AT_);
1251 mAlloc(m_bodyAcceleration, nDim * m_maxNoEmbeddedBodiesPeriodic, "m_bodyAcceleration", F0, AT_);
1252 mAlloc(m_bodyAngularVelocity, 3 * m_maxNoEmbeddedBodiesPeriodic, "m_bodyAngularVelocity", F0, AT_);
1253 mAlloc(m_bodyAngularVelocityDt1, 3 * m_noEmbeddedBodies, "m_bodyAngularVelocityDt1", F0, AT_);
1254 mAlloc(m_bodyTorque, 3 * m_noEmbeddedBodies, " m_bodyTorque", F0, AT_);
1255 mAlloc(m_bodyTorqueDt1, 3 * m_noEmbeddedBodies, "m_bodyTorqueDt1", F0, AT_);
1256 mAlloc(m_bodyQuaternion, 4 * m_maxNoEmbeddedBodiesPeriodic, "m_bodyQuaternion", F0, AT_);
1257 mAlloc(m_bodyQuaternionDt1, 4 * m_noEmbeddedBodies, "m_bodyQuaternionDt1", F0, AT_);
1258 mAlloc(m_bodyAngularAcceleration, 3 * m_maxNoEmbeddedBodiesPeriodic, "m_bodyAngularAcceleration", F0, AT_);
1259 mAlloc(m_bodyAngularAccelerationDt1, 3 * m_noEmbeddedBodies, "m_bodyAngularAccelerationDt1", F0, AT_);
1260 mAlloc(m_bodyDensity, m_noEmbeddedBodies, "m_bodyDensity", F0, AT_);
1261 mAlloc(m_bodyMomentOfInertia, 3 * m_noEmbeddedBodies, "m_bodyMomentOfInertia", F0, AT_);
1262 mAlloc(m_bodyAccelerationDt1, nDim * m_noEmbeddedBodies, "m_bodyAccelerationDt1", F0, AT_);
1263 mAlloc(m_bodyVelocityDt1, nDim * m_noEmbeddedBodies, "m_bodyVelocityDt1", F0, AT_);
1264 mAlloc(m_bodyCenterDt1, nDim * m_noEmbeddedBodies, "m_bodyCenterDt1", F0, AT_);
1265
1266 if(m_motionEquation > 1) {
1267 mAlloc(m_bodyAccelerationDt2, nDim * m_noEmbeddedBodies, "m_bodyAccelerationDt2", F0, AT_);
1268 mAlloc(m_bodyAccelerationDt3, nDim * m_noEmbeddedBodies, "m_bodyAccelerationDt3", F0, AT_);
1269 mAlloc(m_bodyVelocityDt2, nDim * m_noEmbeddedBodies, "m_bodyVelocityDt2", F0, AT_);
1270 mAlloc(m_bodyCenterDt2, nDim * m_noEmbeddedBodies, "m_bodyCenterDt2", F0, AT_);
1271 mAlloc(m_bodyReducedVelocity, m_noEmbeddedBodies, "m_bodyReducedVelocity", F0, AT_);
1272 mAlloc(m_bodyReducedFrequency, m_noEmbeddedBodies, "m_bodyReducedFrequency", F0, AT_);
1273 mAlloc(m_bodyReducedMass, m_noEmbeddedBodies, "m_bodyReducedMass", F0, AT_);
1274 mAlloc(m_bodyDampingCoefficient, m_noEmbeddedBodies, "m_bodyDampingCoefficient", F0, AT_);
1275 mAlloc(m_bodyNeutralCenter, nDim * m_noEmbeddedBodies, "m_bodyNeutralCenter", F0, AT_);
1276 }
1277
1278 mAlloc(m_bodyTemperature, m_noEmbeddedBodies, "m_bodyTemperature", F1, AT_);
1279 mAlloc(m_bodyTemperatureDt1, m_noEmbeddedBodies, "m_bodyTemperatureDt1", F1, AT_);
1280 mAlloc(m_bodyEquation, m_noEmbeddedBodies, "m_bodyEquation", -1, AT_);
1281 mAlloc(m_bodyInCollision, m_noEmbeddedBodies, "m_bodyInCollision", 0, AT_);
1282 mAlloc(m_periodicGhostBodies, m_noEmbeddedBodies, "m_periodicGhostBodies", AT_);
1283 mAlloc(m_internalBodyId, m_maxNoEmbeddedBodiesPeriodic, "m_internalBodyId", -1, AT_);
1284 mAlloc(m_bodyNearDomain, m_maxNoEmbeddedBodiesPeriodic, "m_bodyNearDomain", true, AT_);
1285 mAlloc(m_fixedBodyComponents, nDim, "m_fixedBodyComponents", 0, AT_);
1286 mAlloc(m_fixedBodyComponentsRotation, 3, "m_fixedBodyComponentsRotation", 0, AT_);
1287
1288 mAlloc(m_bodyForce, nDim * m_noEmbeddedBodies, "m_bodyForce", F0, AT_);
1289 mAlloc(m_bodyForceDt1, nDim * m_noEmbeddedBodies, "m_bodyForceDt1", F0, AT_);
1290 mAlloc(m_bodyHeatFlux, m_noEmbeddedBodies, "m_bodyHeatFlux", F0, AT_);
1291 mAlloc(m_hydroForce, nDim * m_noEmbeddedBodies, "m_hydroForce", F0, AT_);
1292}
1293
1294
1299template <MInt nDim, class SysEqn>
1301 TRACE();
1302
1303 constructGField(false);
1304
1305 std::vector<MInt>().swap(m_bndryLayerCells);
1306 set<MInt> rebuildCells;
1307 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
1308 if(a_bndryId(cellId) < -1) continue;
1309
1310 ASSERT(!a_isBndryGhostCell(cellId), "");
1311
1312 if(c_noChildren(cellId) > 0) {
1313 ASSERT(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel), "Non leaf cell is on current mg level!");
1314 a_hasProperty(cellId, SolverCell::NearWall) = false;
1315 }
1316
1317 MBool oldStatus = a_hasProperty(cellId, SolverCell::NearWall);
1318
1319 ASSERT(a_level(cellId) > -1 && a_level(cellId) <= maxRefinementLevel(),
1320 "unexpected cell level " << a_level(cellId) << " for cell " << cellId << endl);
1321
1322 if((a_level(cellId) >= m_lsCutCellMinLevel)
1323 && a_levelSetValuesMb(cellId, 0) > m_maxBndryLayerDistances[a_level(cellId)][0]
1324 && a_levelSetValuesMb(cellId, 0) < m_maxBndryLayerDistances[a_level(cellId)][1] && c_isLeafCell(cellId)) {
1325 m_bndryLayerCells.push_back(cellId);
1326 a_hasProperty(cellId, SolverCell::NearWall) = true;
1327 } else {
1328 a_hasProperty(cellId, SolverCell::NearWall) = false;
1329 }
1330 if(a_levelSetValuesMb(cellId, 0) < F0) {
1331 a_hasProperty(cellId, SolverCell::IsInactive) = true;
1332 a_hasProperty(cellId, SolverCell::IsActive) = false; // change_1a
1333 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false; // change_1a
1334 } else {
1335 a_hasProperty(cellId, SolverCell::IsInactive) = false;
1336 if(c_isLeafCell(cellId)) {
1337 a_hasProperty(cellId, SolverCell::IsActive) = true;
1338 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = true;
1339 }
1340 if(oldStatus && (!a_hasProperty(cellId, SolverCell::NearWall))
1341 && !a_hasProperty(cellId, SolverCell::IsNotGradient)) {
1342 a_hasProperty(cellId, SolverCell::IsFlux) = true;
1343 rebuildCells.insert(cellId);
1344 // rebuildReconstructionConstants( cellId );
1345 }
1346 }
1347 }
1348
1349 m_fvBndryCnd->correctCellCoordinates();
1350 for(auto it = rebuildCells.begin(); it != rebuildCells.end(); ++it) {
1351 rebuildReconstructionConstants(*it);
1352 }
1353 rebuildCells.clear();
1354 m_fvBndryCnd->recorrectCellCoordinates();
1355
1356 // TODO labels:FVMB update IsInactive on cells at a Leveljump!
1357 // the coarser cell needs to have a neighbor in the direction of the finer cell
1358 // if any of the neighboring fine cells is !IsInactive.
1359 // => IsInactive of the parent must be set to false, but the cell must not be
1360 // IsOnCurrentMGLevel!
1361}
1362
1363
1368template <MInt nDim, class SysEqn>
1370 const MInt bodyCnt) {
1371 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
1372 a_associatedBodyIds(cellId, set) = -1;
1373 a_levelSetValuesMb(cellId, set) = m_bodyDistThreshold + 1e-14;
1374 }
1375
1376 for(MInt b = 0; b < bodyCnt; b++) {
1377 const MInt k = bodyIds[b];
1378 const MInt set = m_bodyToSetTable[k];
1379 MFloat dist = getDistance(cellId, k);
1380
1381 if(fabs(dist) < fabs(a_levelSetValuesMb(cellId, set)) || (dist < F0)) {
1382 a_levelSetValuesMb(cellId, set) = dist;
1383 a_associatedBodyIds(cellId, set) = k;
1384 }
1385 }
1386
1387 if(m_startSet > 0) {
1388 a_levelSetValuesMb(cellId, 0) = a_levelSetValuesMb(cellId, m_startSet);
1389 a_associatedBodyIds(cellId, 0) = a_associatedBodyIds(cellId, m_startSet);
1390 for(MInt i = (m_startSet + 1); i < m_noSets; i++) {
1391 if(a_levelSetValuesMb(cellId, i) < a_levelSetValuesMb(
1392 cellId, 0)) { // a distinction between concave and convex boundaries has to be made here!!!!!
1393 a_levelSetValuesMb(cellId, 0) = a_levelSetValuesMb(cellId, i);
1394 a_associatedBodyIds(cellId, 0) = a_associatedBodyIds(cellId, i);
1395 }
1396 }
1397 }
1398
1399 for(MInt child = 0; child < m_noCellNodes; child++) {
1400 if(c_childId(cellId, child) < 0) continue;
1401 descendLevelSetValue(c_childId(cellId, child), bodyIds, bodyCnt);
1402 }
1403}
1404
1405
1410template <MInt nDim, class SysEqn>
1412 const MInt bodyCnt, MIntScratchSpace& nearestBodies,
1413 MFloatScratchSpace& nearestDist) {
1414 MInt* const nearBodies = &nearestBodies[cellId * m_maxNearestBodies];
1415 MFloat* const nearDist = &nearestDist[cellId * m_maxNearestBodies];
1416
1417 for(MInt b = 0; b < bodyCnt; b++) {
1418 const MInt k = bodyIds[b];
1419 MFloat dist = getDistance(cellId, k);
1420
1421 for(MInt n = 0; n < m_maxNearestBodies; n++) {
1422 if(fabs(dist) < fabs(nearDist[n])) {
1423 if(n < m_maxNearestBodies - 1) {
1424 std::rotate(nearBodies + n, nearBodies + m_maxNearestBodies - 1, nearBodies + m_maxNearestBodies);
1425 std::rotate(nearDist + n, nearDist + m_maxNearestBodies - 1, nearDist + m_maxNearestBodies);
1426 }
1427 nearDist[n] = dist;
1428 nearBodies[n] = k;
1429 break;
1430 }
1431 }
1432 }
1433
1434 for(MInt child = 0; child < m_noCellNodes; child++) {
1435 if(c_childId(cellId, child) < 0) continue;
1436 descendDistance(c_childId(cellId, child), bodyIds, bodyCnt, nearestBodies, nearestDist);
1437 }
1438}
1439
1440
1445template <MInt nDim, class SysEqn>
1447 TRACE();
1448
1449 // 1. update collector sizes
1450 m_noFlowCells = a_noCells();
1451 m_noSurfaces = a_noSurfaces();
1452 m_noBndryCells = m_fvBndryCnd->m_bndryCells->size();
1453
1454 // 2. set active cells
1455 const MInt noAllCells = a_noCells();
1456
1457 m_noActiveCells = 0;
1458 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
1459 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
1460 m_activeCellIds[m_noActiveCells] = cellId;
1461 m_noActiveCells++;
1462 }
1463 }
1464
1465 m_noActiveHaloCellOffset = m_noActiveCells;
1466 for(MInt cellId = noInternalCells(); cellId < noAllCells; cellId++) {
1467 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
1468 m_activeCellIds[m_noActiveCells] = cellId;
1469 m_noActiveCells++;
1470 }
1471 }
1472
1473 // 3. log statistics
1474 logOutput();
1475}
1476
1477
1482template <MInt nDim, class SysEqn>
1484 TRACE();
1485
1486 MInt noCells_solver = m_cells.size();
1487 MInt noCells_grid = c_noCells();
1488 MInt nosplitchilds = m_totalnosplitchilds;
1489 MInt nosurfaces = m_noSurfaces;
1490 MInt noboundarycells = m_noBndryCells;
1491 MInt nolsmbcells = m_noLsMbBndryCells;
1492
1493 if(globalTimeStep % m_loggingInterval == 0) {
1494 MPI_Allreduce(MPI_IN_PLACE, &noCells_solver, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE ",
1495 "noCells_solver");
1496 MPI_Allreduce(MPI_IN_PLACE, &noCells_grid, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE ", "noCells_grid");
1497 MPI_Allreduce(MPI_IN_PLACE, &nosplitchilds, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE ", "nosplitchilds");
1498 MPI_Allreduce(MPI_IN_PLACE, &nosurfaces, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE ", "nosurfaces");
1499 MPI_Allreduce(MPI_IN_PLACE, &noboundarycells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE ",
1500 "noboundarycells");
1501 MPI_Allreduce(MPI_IN_PLACE, &nolsmbcells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE ", "nolsmbcells");
1502
1503 m_log << "======================================================" << endl << endl;
1504 m_log << "Grid summary at time step " << globalTimeStep << endl << endl;
1505 m_log << setfill(' ');
1506 m_log << "number of grid-cells " << setw(7) << noCells_grid << endl;
1507 m_log << "number of fv-cells " << setw(7) << noCells_solver << endl;
1508 m_log << "number of splitchilds " << setw(7) << nosplitchilds << endl;
1509 m_log << "number of surfaces " << setw(7) << nosurfaces << endl;
1510 m_log << "number of boundary cells " << setw(7) << noboundarycells << endl;
1511 m_log << "number of moving boundary cells " << setw(7) << nolsmbcells << endl;
1512 m_log << "======================================================" << endl << endl;
1513 }
1514}
1515
1516
1521template <MInt nDim, class SysEqn>
1523 TRACE();
1524
1525 if(m_initialCondition == 465 && m_constructGField) setInfinityState();
1527 updateInfinityVariables();
1528}
1529
1530
1535template <MInt nDim, class SysEqn>
1537 TRACE();
1538
1539 ASSERT(m_constructGField, "");
1540
1541 if(m_constructGField && m_bodyTypeMb > 0) {
1542 initBodyProperties();
1543 constructGField();
1544 } else if(m_bodyTypeMb != 0) {
1545 mTerm(1, AT_, "Unknown body type.");
1546 }
1547}
1548
1549
1554template <MInt nDim, class SysEqn>
1556 TRACE();
1557
1558 std::vector<MInt>().swap(m_bndryLayerCells);
1559 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
1560 a_hasProperty(cellId, SolverCell::NearWall) = false;
1561
1562 if(a_bndryId(cellId) < -1) continue;
1563
1564 a_hasProperty(cellId, SolverCell::IsInactive) = false;
1565 a_hasProperty(cellId, SolverCell::WasInactive) = false;
1566
1567 if(c_noChildren(cellId) > 0) {
1568 a_hasProperty(cellId, SolverCell::IsInactive) = true;
1569 a_hasProperty(cellId, SolverCell::WasInactive) = true;
1570 continue;
1571 }
1572
1573 if(a_levelSetValuesMb(cellId, 0) > m_maxBndryLayerDistances[a_level(cellId)][0]
1574 && a_levelSetValuesMb(cellId, 0) < m_maxBndryLayerDistances[a_level(cellId)][1] && c_isLeafCell(cellId)) {
1575 m_bndryLayerCells.push_back(cellId);
1576 a_hasProperty(cellId, SolverCell::NearWall) = true;
1577 }
1578
1579 if(a_levelSetValuesMb(cellId, 0) < F0 || !c_isLeafCell(cellId)) {
1580 a_hasProperty(cellId, SolverCell::IsInactive) = true;
1581 a_hasProperty(cellId, SolverCell::WasInactive) = true;
1582 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
1583 }
1584 }
1585}
1586
1587
1596template <MInt nDim, class SysEqn>
1598 TRACE();
1599
1600 if((mode < 0) && (!m_trackMovingBndry || globalTimeStep < m_trackMbStart || globalTimeStep > m_trackMbEnd)) {
1601 return;
1602 }
1603
1604 NEW_TIMER_GROUP_STATIC(t_initTimer, "reInitSolutionStep");
1605 NEW_TIMER_STATIC(t_timertotal, "reInitSolutionStep", t_initTimer);
1606 NEW_SUB_TIMER_STATIC(t_resetSolverMb, "resetSolverMb", t_timertotal);
1607 NEW_SUB_TIMER_STATIC(t_trackBoundaryLayer, "trackBoundaryLayer", t_timertotal);
1608 NEW_SUB_TIMER_STATIC(t_generateBndryCellsMb, "generateBndryCellsMb", t_timertotal);
1609 NEW_SUB_TIMER_STATIC(t_imagePointRec, "imagePointRec", t_timertotal);
1610 NEW_SUB_TIMER_STATIC(t_initBndEx, "initBndEx", t_timertotal);
1611 NEW_SUB_TIMER_STATIC(t_massRedist, "massRedist", t_timertotal);
1612 NEW_SUB_TIMER_STATIC(t_initSmallCells, "initSmallCells", t_timertotal);
1613 NEW_SUB_TIMER_STATIC(t_generateSurfaces, "generateSurfaces", t_timertotal);
1614 NEW_SUB_TIMER_STATIC(t_buildLeastSquaresStencil, "buildLeastSquaresStencil", t_timertotal);
1615 NEW_SUB_TIMER_STATIC(t_finalize, "finalize", t_timertotal);
1616 m_tCutGroupTotal = t_timertotal;
1617 m_tCutGroup = t_generateBndryCellsMb;
1618 RECORD_TIMER_START(t_timertotal);
1619
1620 RECORD_TIMER_START(m_timers[Timers::ReinitSolu]);
1621
1622 // update cfl-number and change timeStep
1623 if(m_timeStepAdaptationStart > -1 && m_structureStep == 0) {
1624 setTimeStep();
1625 }
1626
1627 m_reComputedBndry = true;
1628 RECORD_TIMER_START(t_resetSolverMb);
1629 if(mode != 0) {
1630 resetSolverMb();
1631 }
1632 RECORD_TIMER_STOP(t_resetSolverMb);
1633
1634 RECORD_TIMER_START(t_trackBoundaryLayer);
1635 setLevelSetMbCellProperties();
1636#if defined _MB_DEBUG_ || !defined NDEBUG
1637 checkHaloCells();
1638#endif
1639 RECORD_TIMER_STOP(t_trackBoundaryLayer);
1640
1641 RECORD_TIMER_START(m_timers[Timers::BndryMb]);
1642 RECORD_TIMER_START(t_generateBndryCellsMb);
1643 generateBndryCellsMb(mode);
1644 RECORD_TIMER_STOP(t_generateBndryCellsMb);
1645 RECORD_TIMER_STOP(m_timers[Timers::BndryMb]);
1646
1647 if(m_wmLES) {
1648 m_fvBndryCnd->initWMSurfaces();
1649 Base::initWMExchange();
1650 Base::exchangeWMVars();
1651 }
1652
1653#if defined _MB_DEBUG_ || !defined NDEBUG
1654 // In debug mode exhange() calls maxResidual(), which fails if RHS
1655 // is not set to 0 during init call (contains nans otherwise)
1656 resetRHS();
1657#endif
1658
1659 m_bndryGhostCellsOffset = a_noCells();
1660 m_initialSurfacesOffset = a_noSurfaces();
1661
1662 // possibility for bndryCell distribution over all ranks!
1663 // This is useful to check the balance/distribution
1664 //=> keep the commented code below!
1665 /*
1666 if(mode != -1 || globalTimeStep % 10 == 0) {
1667 MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
1668 MInt maxBndryCells = 0;
1669 MInt minBndryCells = -1;
1670 MInt sumBndryCells = 0;
1671
1672 MPI_Allreduce(&noBndryCells, &maxBndryCells, 1, MPI_INT, MPI_MAX, mpiComm(),
1673 AT_, "maxBndryCells","noBndryCells" );
1674
1675 MPI_Allreduce(&noBndryCells, &minBndryCells, 1, MPI_INT, MPI_MIN, mpiComm(),
1676 AT_, "maxBndryCells","noBndryCells" );
1677 MPI_Allreduce(&noBndryCells, &sumBndryCells, 1, MPI_INT, MPI_SUM, mpiComm(),
1678 AT_, "maxBndryCells","noBndryCells" );
1679
1680
1681 if(domainId() == 0) {
1682 cerr << "Min/Max/Avg Bndry-Cell-Count: " << minBndryCells << " "
1683 << maxBndryCells << " " << sumBndryCells/noDomains() << endl;
1684 }
1685
1686 if(noBndryCells == maxBndryCells) {
1687 cerr << "Rank with max-BndryCells has " << a_noCells() << " cells and "
1688 << m_initialSurfacesOffset << " surfaces!" << endl;
1689 }
1690 }
1691 */
1692
1693 m_fvBndryCnd->correctCellCoordinates();
1694
1695 if((!m_levelSetMb || m_gapOpened) && mode < 1 && m_gapInitMethod == 0) {
1696 initializeEmergedCells();
1697 }
1698
1699#ifdef _MB_DEBUG_XXX
1700 for(MInt i = 0; i < a_noCells(); i++) {
1701 if((a_levelSetValuesMb(i, 0) > F0 || a_bndryId(i) > -1) && (c_noChildren(i) == 0)
1702 && ((!a_hasProperty(i, SolverCell::IsActive) && !a_isHalo(i))
1703 || ((!a_hasProperty(i, SolverCell::IsOnCurrentMGLevel) || a_hasProperty(i, SolverCell::IsInactive))
1704 && !a_hasProperty(i, SolverCell::IsNotGradient)))) {
1705 cerr << domainId() << ": " << i << " " << c_globalId(i) << " /b " << a_bndryId(i) << " /l "
1706 << a_levelSetValuesMb(i, 0) << " /i " << a_hasProperty(i, SolverCell::IsInactive) << " /p15 " << a_isHalo(i)
1707 << " /p7 " << a_hasProperty(i, SolverCell::IsNotGradient) << " /p10 " << a_hasProperty(i, SolverCell::IsFlux)
1708 << " /p11 " << a_hasProperty(i, SolverCell::IsActive) << " /p13 "
1709 << a_hasProperty(i, SolverCell::IsOnCurrentMGLevel) << endl;
1710 mTerm(1, AT_, "Invalid cell flag.");
1711 }
1712 }
1713#endif
1714
1715 if(m_fvBndryCnd->m_cellMerging) {
1716 findNghbrIds();
1717 if(m_fvBndryCnd->m_multipleGhostCells) {
1718 m_fvBndryCnd->detectSmallBndryCellsMGC();
1719 } else {
1720 m_fvBndryCnd->detectSmallBndryCells();
1721 }
1722 if(m_fvBndryCnd->m_multipleGhostCells) {
1723 m_fvBndryCnd->mergeCellsMGC();
1724 } else {
1725 m_fvBndryCnd->mergeCells();
1726 }
1727 mDeallocate(m_storeNghbrIds);
1728 mDeallocate(m_identNghbrIds);
1729 m_log << " found " << m_fvBndryCnd->m_smallBndryCells->size() << "small cells." << endl;
1730 } else {
1731 RECORD_TIMER_START(m_timers[Timers::NearBndry]);
1732 RECORD_TIMER_START(t_initBndEx);
1733 m_fvBndryCnd->setNearBoundaryRecNghbrs(m_movingBndryCndId);
1734 if(grid().azimuthalPeriodicity()) {
1735 updateAzimuthalMaxLevelRecCoords();
1736 updateAzimuthalNearBoundaryExchange();
1737 buildAdditionalAzimuthalReconstructionStencil(1);
1738 if(mode == 0) initAzimuthalCartesianHaloInterpolation();
1739 }
1740 initNearBoundaryExchange(1, m_noOuterBndryCells);
1741
1742 RECORD_TIMER_STOP(m_timers[Timers::NearBndry]);
1743 RECORD_TIMER_STOP(t_initBndEx);
1744 RECORD_TIMER_START(t_massRedist);
1745#ifdef _ALE_FORM_
1746 if(mode > 0) {
1747 std::vector<MInt>().swap(m_massRedistributionIds);
1748 std::vector<MFloat>().swap(m_massRedistributionVariables);
1749 std::vector<MFloat>().swap(m_massRedistributionRhs);
1750 std::vector<MFloat>().swap(m_massRedistributionVolume);
1751 std::vector<MFloat>().swap(m_massRedistributionSweptVol);
1752 std::vector<std::tuple<MInt, MInt, MInt>>().swap(m_temporarilyLinkedCells);
1753 }
1754 redistributeMass();
1755 // call before initSmallCellCorrection
1756 // but after correctCellCoordinates and initNearBoundaryExchange !!
1757#endif
1758 RECORD_TIMER_STOP(t_massRedist);
1759
1760 RECORD_TIMER_START(t_imagePointRec);
1761 m_fvBndryCnd->computeImagePointRecConst(m_movingBndryCndId);
1762 RECORD_TIMER_STOP(t_imagePointRec);
1763
1764 RECORD_TIMER_START(m_timers[Timers::InitSmallCorr]);
1765 RECORD_TIMER_START(t_initSmallCells);
1766 if(m_fvBndryCnd->m_smallCellRHSCorrection) {
1767 m_fvBndryCnd->initSmallCellRHSCorrection(m_movingBndryCndId);
1768 } else {
1769 m_fvBndryCnd->initSmallCellCorrection(m_movingBndryCndId);
1770 }
1771 RECORD_TIMER_STOP(t_initSmallCells);
1772 RECORD_TIMER_STOP(m_timers[Timers::InitSmallCorr]);
1773 }
1774
1775 // check surfaces for gapClosing
1776 if(m_levelSet && m_closeGaps) {
1777 for(MInt region = 0; region < m_noGapRegions; region++) {
1778 if(m_gapState[region] != -2) continue;
1779 for(MInt srfcId = 0; srfcId < a_noSurfaces(); srfcId++) {
1780 MInt nghbrId0 = a_surfaceNghbrCellId(srfcId, 0);
1781 MInt nghbrId1 = a_surfaceNghbrCellId(srfcId, 1);
1782 if(nghbrId0 <= 0 || nghbrId1 <= 0) continue;
1783 if(a_isGapCell(nghbrId0) && a_isGapCell(nghbrId1) && a_hasProperty(nghbrId0, SolverCell::IsInactive)
1784 && a_hasProperty(nghbrId1, SolverCell::IsInactive)) {
1785 ASSERT(!a_hasProperty(nghbrId0, SolverCell::WasInactive) && !a_hasProperty(nghbrId1, SolverCell::WasInactive),
1786 "");
1787
1788 ASSERT(a_levelSetValuesMb(nghbrId0, 0) < 0 && a_levelSetValuesMb(nghbrId1, 0) < 0, "");
1789
1790 ASSERT(m_gapInitMethod == 0, "This should have already been done in gapHandling! ");
1791 deleteSurface(srfcId);
1792
1793 cerr << "Deleting Gap-shadowed surfaces in region " << region << " due to Gap-Closure at timestep "
1794 << globalTimeStep << endl;
1795 cerr << " Of Cells: " << c_globalId(nghbrId0) << " and " << c_globalId(nghbrId1) << endl;
1796 }
1797 }
1798 }
1799 }
1800
1801 RECORD_TIMER_START(m_timers[Timers::GhostCells]);
1802 RECORD_TIMER_START(t_generateSurfaces);
1803 correctSrfcsMb();
1804 compactSurfaces();
1805
1806#if defined _MB_DEBUG_ || !defined NDEBUG
1807 for(MInt srfcId = 0; srfcId < a_noSurfaces(); srfcId++) {
1808 MInt nghbrId0 = a_surfaceNghbrCellId(srfcId, 0);
1809 MInt nghbrId1 = a_surfaceNghbrCellId(srfcId, 1);
1810 ASSERT(nghbrId0 > -1 && nghbrId1 > -1, "");
1811 if(a_hasProperty(nghbrId0, SolverCell::IsInactive) || a_hasProperty(nghbrId1, SolverCell::IsInactive)) {
1812 cerr << "p15/p7: " << a_isHalo(nghbrId0) << " " << a_isHalo(nghbrId1) << " / " << nghbrId0 << " " << nghbrId1
1813 << " / " << c_globalId(nghbrId0) << " " << c_globalId(nghbrId1) << " / "
1814 << a_hasProperty(nghbrId0, SolverCell::IsNotGradient) << " "
1815 << a_hasProperty(nghbrId1, SolverCell::IsNotGradient) << " / " << a_isGapCell(nghbrId0) << " "
1816 << a_isGapCell(nghbrId1) << " / " << a_hasProperty(nghbrId0, SolverCell::IsInactive) << " "
1817 << a_hasProperty(nghbrId1, SolverCell::IsInactive) << endl;
1818 cerr << "ls: " << a_levelSetValuesMb(nghbrId0, 0) << " " << a_levelSetValuesMb(nghbrId1, 0) << endl;
1819 cerr << "coord " << a_coordinate(nghbrId0, 0) << " " << a_coordinate(nghbrId0, 1) << " "
1820 << a_coordinate(nghbrId0, 2) << endl;
1821 }
1822 ASSERT(!a_hasProperty(nghbrId0, SolverCell::IsInactive) && !a_hasProperty(nghbrId1, SolverCell::IsInactive),
1823 to_string(srfcId) << " " << to_string(nghbrId0) << " " << to_string(nghbrId1) << " "
1824 << to_string(a_noCells()) << " " << to_string(c_globalId(nghbrId0)) << " "
1825 << to_string(c_globalId(nghbrId1)));
1826 }
1827#endif
1828
1829
1830 // restore outer boundary ghost cells and outer bounday surfaces
1831 const MInt noBnd = m_fvBndryCnd->m_bndryCells->size();
1832 m_fvBndryCnd->m_bndryCells->resetSize(m_noOuterBndryCells);
1833 m_initialSurfacesOffset = a_noSurfaces();
1834 setOuterBoundaryGhostCells();
1835 setOuterBoundarySurfaces();
1836 m_fvBndryCnd->m_bndryCells->resetSize(noBnd);
1837
1838 // add Mb ghost cells and surfaces
1839 computeGhostCellsMb();
1840 addBoundarySurfacesMb();
1841 RECORD_TIMER_STOP(t_generateSurfaces);
1842 RECORD_TIMER_STOP(m_timers[Timers::GhostCells]);
1843
1844 RECORD_TIMER_START(t_buildLeastSquaresStencil);
1845 buildAdditionalReconstructionStencil();
1846 RECORD_TIMER_STOP(t_buildLeastSquaresStencil);
1847
1848 if(grid().azimuthalPeriodicity()) {
1849 buildAdditionalAzimuthalReconstructionStencil(0);
1850 initAzimuthalLinkedHaloExc();
1851 if(mode == 0 || m_wasBalanced) {
1852 m_wasBalanced = false;
1853 }
1854 }
1855
1856 // possibility for surface distribution over all ranks!
1857 // This is useful to check the balance/distribution
1858 //=> keep the commented code below!
1859 /*
1860 if(mode != -1 || globalTimeStep % 10 == 0) {
1861 MInt initalSurf = m_initialSurfacesOffset;
1862
1863 MInt maxInital = 0;
1864 MInt minInitial = 0;
1865 MInt sumInitial = 0;
1866
1867 MPI_Allreduce(&initalSurf, &maxInital, 1,MPI_INT, MPI_MAX, mpiComm(),
1868 AT_, "maxInitial","initialSurf" );
1869
1870 MPI_Allreduce(&initalSurf, &minInitial, 1, MPI_INT, MPI_MIN, mpiComm(),
1871 AT_, "minTotal","minInitial" );
1872
1873 MPI_Allreduce(&initalSurf, &sumInitial, 1, MPI_INT, MPI_SUM, mpiComm(),
1874 AT_, "minTotal","totalSurf" );
1875
1876 if(domainId() == 0 ) {
1877 cerr << "Min/Max/Avg inital-Surface-Count: " << minInitial << " " << maxInital << " " << sumInitial/noDomains() <<
1878 endl;
1879 }
1880
1881 if(maxInital == initalSurf) {
1882 cerr << "Rank with max-Surfaces has " << a_noCells() << " cells and "
1883 << m_fvBndryCnd->m_bndryCells->size() << "bndry-Cells" << endl;
1884 }
1885 }
1886 */
1887
1888 RECORD_TIMER_START(t_finalize);
1889 if(m_fvBndryCnd->m_cellMerging) {
1890 m_fvBndryCnd->computePlaneVectors();
1891 }
1892
1893#ifdef SAFOKSAJFKO
1894 const MFloat EPS = 1e-6;
1895 const MInt xdim = a_noCells();
1896 MFloat area[m_noDirs];
1897 MInt errorFlag = false;
1898 for(MInt cellId = xdim; cellId--;) {
1899 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
1900 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
1901 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
1902 if(a_isPeriodic(cellId)) continue;
1903 if(a_isBndryGhostCell(cellId)) continue;
1904 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
1905 if(a_isHalo(cellId) && a_level(cellId) < maxRefinementLevel()) continue;
1906 if(a_isHalo(cellId)) continue;
1907 if(a_isHalo(cellId) && a_bndryId(cellId) > -1 && a_bndryId(cellId) < m_noOuterBndryCells) continue;
1908 MBool skip = false;
1909 if(a_isHalo(cellId) && a_level(cellId) == maxRefinementLevel()) {
1910 for(MInt dir = 0; dir < m_noDirs; dir++) {
1911 if(a_hasNeighbor(cellId, dir) > 0) {
1912 MInt nghbrId = c_neighborId(cellId, dir);
1913 if(a_hasProperty(nghbrId, SolverCell::IsNotGradient)) skip = true;
1914 } else {
1915 skip = true;
1916 }
1917 }
1918 }
1919 if(skip) continue;
1920 // if ( c_noChildren( cellId ) > 0 ) continue;
1921 MFloat test[nDim];
1922 const MFloat sign[2] = {-F1, F1};
1923 for(MInt k = 0; k < nDim; k++)
1924 test[k] = F0;
1925 MBool hasBndrySurface = false;
1926 for(MInt dir = 0; dir < m_noDirs; dir++) {
1927 area[dir] = F0;
1928 if(m_cellSurfaceMapping[cellId][dir] > -1) {
1929 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
1930 // if ( m_isActiveSurface[ srfcId ] ) {
1931 {
1932 MInt id = -1;
1933 if(a_surfaceNghbrCellId(srfcId, 0) == cellId)
1934 id = 1;
1935 else if(a_surfaceNghbrCellId(srfcId, 1) == cellId)
1936 id = 0;
1937 if(id < 0) continue;
1938 test[a_surfaceOrientation(srfcId)] += sign[id] * a_surfaceArea(srfcId);
1939 area[dir] = a_surfaceArea(srfcId);
1940 }
1941 } else if(a_hasNeighbor(cellId, dir) > 0) {
1942 MInt nghbrId = c_neighborId(cellId, dir);
1943 if(c_noChildren(nghbrId) > 0) {
1944 for(MInt child = 0; child < m_noCellNodes; child++) {
1945 if(!childCode[dir][child]) continue;
1946 MInt childId = c_childId(nghbrId, child);
1947 if(childId < 0) continue;
1948 if(m_cellSurfaceMapping[childId][m_revDir[dir]] > -1) {
1949 if(a_surfaceNghbrCellId(m_cellSurfaceMapping[childId][m_revDir[dir]], m_nghbrCellIds[m_revDir[dir] % 2) == cellId) {
1950 MInt srfcId = m_cellSurfaceMapping[childId][m_revDir[dir]];
1951 // if ( m_isActiveSurface[ srfcId ] ) {
1952 {
1953 MInt id = -1;
1954 if(a_surfaceNghbrCellId(srfcId, 0) == cellId)
1955 id = 1;
1956 else if(a_surfaceNghbrCellId(srfcId, 1) == cellId)
1957 id = 0;
1958 if(id < 0) continue;
1959 test[a_surfaceOrientation(srfcId)] += sign[id] * a_surfaceArea(srfcId);
1960 area[dir] = a_surfaceArea(srfcId);
1961 }
1962 }
1963 }
1964 }
1965 } else if(a_hasProperty(cellId, SolverCell::HasSplitFace)) {
1966 for(MInt srfcId = a_noSurfaces(); srfcId--;) {
1967 // if ( !m_isActiveSurface[ srfcId ] ) continue;
1968 if(a_surfaceBndryCndId(srfcId) > -1) continue;
1969 MInt id = -1;
1970 if(a_surfaceNghbrCellId(srfcId, 0) == cellId && dir == 2 * a_surfaceOrientation(srfcId) + 1)
1971 id = 1;
1972 else if(a_surfaceNghbrCellId(srfcId, 1) == cellId && dir == 2 * a_surfaceOrientation(srfcId))
1973 id = 0;
1974 if(id > -1) {
1975 test[a_surfaceOrientation(srfcId)] += sign[id] * a_surfaceArea(srfcId);
1976 area[dir] = a_surfaceArea(srfcId);
1977 }
1978 }
1979 }
1980 }
1981 }
1982 if(a_bndryId(cellId) > -1) {
1983 for(MInt bs = 0; bs < m_fvBndryCnd->m_noBoundarySurfaces; bs++) {
1984 MInt srfcId = m_fvBndryCnd->m_boundarySurfaces[bs];
1985 // if ( m_isActiveSurface[ srfcId ] ) {
1986 {
1987 MInt id = -1;
1988 if(a_surfaceNghbrCellId(srfcId, 0) == cellId)
1989 id = 1;
1990 else if(a_surfaceNghbrCellId(srfcId, 1) == cellId)
1991 id = 0;
1992 if(id < 0) continue;
1993 hasBndrySurface = true;
1994 test[a_surfaceOrientation(srfcId)] += sign[id] * a_surfaceArea(srfcId);
1995 }
1996 }
1997 }
1998 MBool testPassed = true;
1999 for(MInt k = 0; k < nDim; k++) {
2000 if(fabs(test[k]) > EPS * m_gridCellArea[a_level(cellId)]) {
2001 testPassed = false;
2002 }
2003 }
2004
2005 if(!testPassed) {
2006 for(MInt k = 0; k < nDim; k++) {
2007 cerr << domainId() << " " << nDim << ": cell " << cellId << " " << a_bndryId(cellId) << " "
2008 << a_hasProperty(cellId, SolverCell::IsInactive) << " " << (a_bndryId(cellId) < m_noOuterBndryCells)
2009 << " / " << hasBndrySurface << " " << a_isHalo(cellId) << " "
2010 << a_hasProperty(cellId, SolverCell::IsNotGradient) << " / " << k << " " << fabs(test[k]) << endl;
2011 }
2012 cerr << "Cell surface is not closed. Check the surfaces! " << domainId() << " " << cellId << " "
2013 << a_bndryId(cellId) << " " << a_isHalo(cellId) << " " << a_level(cellId) << " "
2014 << a_hasProperty(cellId, SolverCell::IsInactive) << " " << a_hasProperty(cellId, SolverCell::IsSplitCell)
2015 << " " << a_hasProperty(cellId, SolverCell::IsSplitChild) << " "
2016 << a_hasProperty(cellId, SolverCell::HasSplitFace) << endl;
2017 m_log << "Cell surface is not closed. Check the surfaces! " << domainId() << " " << cellId << " "
2018 << a_bndryId(cellId) << " " << a_isHalo(cellId) << " " << a_level(cellId) << endl;
2019 for(MInt dir2 = 0; dir2 < m_noDirs; dir2++) {
2020 cerr << m_cellSurfaceMapping[cellId][dir2] << "(";
2021 MInt nghbrId = (a_hasNeighbor(cellId, dir2) > 0) ? c_neighborId(cellId, dir2) : -1;
2022 MInt state = (nghbrId > -1) ? a_hasProperty(nghbrId, SolverCell::IsInactive) : -1;
2023 cerr << nghbrId << "/" << state << ") ";
2024 }
2025 cerr << endl;
2026 errorFlag = true;
2027 }
2028 }
2029
2030 const MInt xdim0 = a_noCells();
2031 for(MInt i = xdim0; i--;) {
2032 if(a_hasProperty(i, SolverCell::IsCutOff)) continue;
2033 if(a_hasProperty(i, SolverCell::IsNotGradient)) continue;
2034 if(a_isBndryGhostCell(i)) continue;
2035 if(a_hasProperty(i, SolverCell::IsInactive)) continue;
2036 ASSERT((a_noReconstructionNeighbors(i) == 0 || c_noChildren(i) == 0), "No reconstruction nghbrs expected");
2037 if(c_noChildren(i) > 0) continue;
2038 MBool localError = false;
2039 for(MInt n = a_noReconstructionNeighbors(i); n--;) {
2040 if((a_bndryId(a_reconstructionNeighborId(i, n)) > -2)
2041 && (a_isBndryGhostCell(a_reconstructionNeighborId(i, n))
2042 || a_hasProperty(a_reconstructionNeighborId(i, n), SolverCell::IsInactive)
2043 || !a_hasProperty(a_reconstructionNeighborId(i, n), SolverCell::IsOnCurrentMGLevel))) {
2044 cerr << domainId() << ": Inactive cell used in least squares reconstruction!!!!" << i << " " << n << "/"
2045 << a_noReconstructionNeighbors(i) << " / " << a_reconstructionNeighborId(i, n) << " " << a_isHalo(i) << " "
2046 << a_isBndryGhostCell(i) << " /l " << a_level(i) << " " << a_level(a_reconstructionNeighborId(i, n))
2047 << " / " << a_hasProperty(i, SolverCell::IsInactive) << " " << a_bndryId(i) << " /c "
2048 << a_coordinate(a_reconstructionNeighborId(i, n), 0) << " "
2049 << a_coordinate(a_reconstructionNeighborId(i, n), 1) << " " << a_coordinate(i, 0) << " "
2050 << a_coordinate(i, 1) << " / "
2051 << a_hasProperty(a_reconstructionNeighborId(i, n), SolverCell::IsOnCurrentMGLevel) << " "
2052 << a_isHalo(a_reconstructionNeighborId(i, n)) << " "
2053 << a_hasProperty(a_reconstructionNeighborId(i, n), SolverCell::IsNotGradient) << " "
2054 << a_isBndryGhostCell(a_reconstructionNeighborId(i, n)) << " "
2055 << a_hasProperty(a_reconstructionNeighborId(i, n), SolverCell::IsInactive) << " "
2056 << a_bndryId(a_reconstructionNeighborId(i, n)) << endl;
2057 // writeVtkErrorFile();
2058 localError = true;
2059 }
2060 }
2061 if(localError) {
2062 for(MInt n = 0; n < a_noReconstructionNeighbors(i); n++) {
2063 m_log << a_reconstructionNeighborId(i, n) << " ";
2064 }
2065 m_log << endl;
2066 errorFlag = true;
2067 }
2068 }
2069 if(errorFlag) {
2070 cerr << domainId() << ": Error in reInitSolutionStep" << endl;
2071 m_log << "Error in reInitSolutionStep" << endl;
2072 }
2073
2074 MPI_Allreduce(MPI_IN_PLACE, &errorFlag, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "errorFlag");
2075
2076 if(errorFlag) {
2077 cerr << "Error in reInitSolutionStep" << endl;
2078 m_log << "Error in reInitSolutionStep" << endl;
2079 writeVtkErrorFile();
2080 MPI_Barrier(mpiComm(), AT_);
2081 mTerm(1, AT_, ".");
2082 }
2083#endif
2084
2085 if((mode == 1)) {
2086 MFloat* RESTRICT slope = (MFloat*)(&(a_slope(0, 0, 0)));
2087 const MInt size = a_noCells() * m_slopeMemory * sizeof(MFloat);
2088 memset(&(slope[0]), 0, size);
2089 applyBoundaryConditionMb();
2090 leastSquaresReconstruction();
2091 applyBoundaryConditionMb();
2092 if(m_trackBodySurfaceData) computeBodySurfaceData();
2093 if(m_initialCondition == 15 || m_initialCondition == 16) {
2094 if(globalTimeStep == 0 && mode == 1) computeFlowStatistics(true);
2095 }
2096 }
2097
2098 if(m_restart) m_restart = false;
2099
2100#ifdef _MB_DEBUG_
2101 MFloatScratchSpace rhsTest(a_noCells(), AT_, "rhsTest");
2102 rhsTest.fill(F0);
2103 for(MInt srfcId = a_noSurfaces(); srfcId--;) {
2104 rhsTest[a_surfaceNghbrCellId(srfcId, 0)] += a_surfaceArea(srfcId);
2105 rhsTest[a_surfaceNghbrCellId(srfcId, 1)] -= a_surfaceArea(srfcId);
2106 }
2107
2108 for(MInt i = a_noCells(); i--;) {
2109 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
2110 if(!a_hasProperty(i, SolverCell::IsOnCurrentMGLevel)) continue;
2111 if(a_isHalo(i)) continue;
2112 if(a_isBndryGhostCell(i)) continue;
2113 if(a_hasProperty(i, SolverCell::IsInactive)) continue;
2114 if(fabs(rhsTest[i]) > 1e-10) {
2115 cerr << domainId() << " Warning: cell may not be water tight " << i << " " << rhsTest[i] << " "
2116 << a_coordinate(i, 0) << " " << a_coordinate(i, 1) << " " << a_coordinate(i, mMin(nDim - 1, 2)) << endl;
2117 }
2118 }
2119#endif
2120
2121 // memory statistics:
2122 /*
2123 MLong noBndryCells = (MLong)m_fvBndryCnd->m_bndryCells->size();
2124 MLong noSurfaces = (MLong)a_noSurfaces();
2125 MLong noCells = (MLong)a_noCells();
2126
2127 m_log << "Maximum memory-values: " << endl;
2128 m_log << "Cells : " << noCells << endl;
2129 m_log << "Bndry-Cells: " << noBndryCells << endl;
2130 m_log << "Surfaces : " << noSurfaces << endl;
2131
2132 MPI_Allreduce(MPI_IN_PLACE, &noBndryCells, 1, MPI_LONG, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "noBndryCells");
2133 MPI_Allreduce(MPI_IN_PLACE, &noSurfaces, 1, MPI_LONG, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "noSurfaces");
2134 MPI_Allreduce(MPI_IN_PLACE, &noCells, 1, MPI_LONG, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "noCells");
2135
2136 cerr0 << "Maximum memory-values: " << endl;
2137 cerr0 << "Cells : " << noCells << endl;
2138 cerr0 << "Bndry-Cells: " << noBndryCells << endl;
2139 cerr0 << "Surfaces : " << noSurfaces << endl;
2140 */
2141
2142 RECORD_TIMER_STOP(m_timers[Timers::ReinitSolu]);
2143 RECORD_TIMER_STOP(t_finalize);
2144 RECORD_TIMER_STOP(t_timertotal);
2145 DISPLAY_TIMER_OFFSET(t_timertotal, m_restartInterval);
2146}
2147
2148
2153template <MInt nDim, class SysEqn>
2155 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
2156 const MInt cellId = m_splitCells[sc];
2157 MFloat volCnt = F0;
2158
2159 for(MInt v = 0; v < m_noCVars; v++) {
2160 a_variable(cellId, v) = F0;
2161 }
2162
2163 for(MInt v = 0; v < m_noFVars; v++) {
2164 a_rightHandSide(cellId, v) = F0;
2165 m_rhs0[cellId][v] = F0;
2166 }
2167
2168 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
2169 const MInt splitChildId = m_splitChilds[sc][ssc];
2170 for(MInt v = 0; v < m_noCVars; v++) {
2171 a_variable(cellId, v) += a_cellVolume(splitChildId) * a_variable(splitChildId, v);
2172 }
2173
2174 for(MInt v = 0; v < m_noFVars; v++) {
2175 a_rightHandSide(cellId, v) += a_rightHandSide(splitChildId, v);
2176 m_rhs0[cellId][v] += m_rhs0[splitChildId][v];
2177 }
2178 volCnt += a_cellVolume(splitChildId);
2179 }
2180 volCnt = mMax(volCnt, m_eps);
2181
2182 for(MInt v = 0; v < m_noCVars; v++) {
2183 a_variable(cellId, v) /= volCnt;
2184 }
2185 }
2186
2187 if(m_useCentralDifferencingSlopes) {
2188 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
2189 if(a_bndryId(cellId) != -1) continue;
2190 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
2191 if(c_isLeafCell(cellId)) continue;
2192
2193 if(a_level(cellId) == minLevel()) {
2194 reduceData(cellId, &a_pvariable(0, 0), m_noPVars);
2195 reduceData(cellId, &a_variable(0, 0), m_noCVars);
2196 }
2197 }
2198 }
2199}
2200
2201
2206template <MInt nDim, class SysEqn>
2208 TRACE();
2209
2210 applyBoundaryConditionMb();
2211
2212 RECORD_TIMER_START(m_timers[Timers::MusclReconst]);
2213 leastSquaresReconstruction();
2214 RECORD_TIMER_STOP(m_timers[Timers::MusclReconst]);
2215
2216 RECORD_TIMER_START(m_timers[Timers::MusclCopy]);
2217 m_fvBndryCnd->copySlopesToSmallCells();
2218 RECORD_TIMER_STOP(m_timers[Timers::MusclCopy]);
2219
2220 RECORD_TIMER_START(m_timers[Timers::MusclGhostSlopes]);
2221 updateGhostCellSlopesInviscid();
2222 RECORD_TIMER_STOP(m_timers[Timers::MusclGhostSlopes]);
2223
2224 RECORD_TIMER_START(m_timers[Timers::MusclCutSlopes]);
2225 m_fvBndryCnd->updateCutOffSlopesInviscid();
2226 RECORD_TIMER_STOP(m_timers[Timers::MusclCutSlopes]);
2227
2228 RECORD_TIMER_START(m_timers[Timers::MusclReconstSrfc]);
2229 (this->*m_reconstructSurfaceData)(-1);
2230 RECORD_TIMER_STOP(m_timers[Timers::MusclReconstSrfc]);
2231
2232#ifdef _MB_DEBUG_
2233 m_solutionDiverged = false;
2234 for(MInt srfcId = a_noSurfaces(); srfcId--;) {
2235 {
2236 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
2237 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
2238 MInt ghost =
2239 (a_bndryId(mMin(nghbr0, nghbr1)) > -1)
2240 ? m_fvBndryCnd->m_bndryCells->a[a_bndryId(mMin(nghbr0, nghbr1))].m_srfcVariables[0]->m_ghostCellId
2241 : -2;
2242 MBool divd = false;
2243 for(MInt v = 0; v < m_noCVars; v++) {
2244 if(std::isnan(a_surfaceVariable(srfcId, 0, v)) || std::isnan(a_surfaceVariable(srfcId, 1, v))) divd = true;
2245 }
2246 if(a_surfaceVariable(srfcId, 0, PV->P) < F0 || a_surfaceVariable(srfcId, 1, PV->P) < F0
2247 || a_surfaceVariable(srfcId, 0, PV->RHO) < F0 || a_surfaceVariable(srfcId, 1, PV->RHO) < F0)
2248 divd = true;
2249 if(divd) {
2250 cerr << domainId() << ": surf var " << globalTimeStep << " " << srfcId << " " << c_globalId(nghbr0) << " "
2251 << c_globalId(nghbr1) << " /g " << ghost << " " << a_bndryId(nghbr0) << " " << a_bndryId(nghbr1) << " /bc "
2252 << a_surfaceBndryCndId(srfcId) << " /sp " << a_surfaceVariable(srfcId, 0, PV->P) << " "
2253 << a_surfaceVariable(srfcId, 1, PV->P) << " /vf "
2254 << a_cellVolume(nghbr0) / grid().gridCellVolume(a_level(nghbr0)) << " "
2255 << a_cellVolume(nghbr1) / grid().gridCellVolume(a_level(nghbr1)) << " /l " << a_level(nghbr0) << " "
2256 << a_level(nghbr1) << " /p15 " << a_isHalo(nghbr0) << " " << a_isHalo(nghbr1) << " /p7 "
2257 << a_hasProperty(nghbr0, SolverCell::IsNotGradient) << " "
2258 << a_hasProperty(nghbr1, SolverCell::IsNotGradient) << " /c " << a_surfaceCoordinate(srfcId, 0) << " "
2259 << a_surfaceCoordinate(srfcId, 1) << " " << a_surfaceCoordinate(srfcId, mMin(nDim - 1, 2)) << " /pc "
2260 << a_pvariable(nghbr0, PV->P) << " " << a_pvariable(nghbr1, PV->P) << " /p "
2261 << a_surfaceVariable(srfcId, 0, PV->P) << " " << a_surfaceVariable(srfcId, 1, PV->P) << " /rho "
2262 << a_surfaceVariable(srfcId, 0, PV->RHO) << " " << a_surfaceVariable(srfcId, 1, PV->RHO) << " /sl "
2263 << a_slope(nghbr0, PV->U, a_surfaceOrientation(srfcId)) << " "
2264 << a_slope(nghbr1, PV->U, a_surfaceOrientation(srfcId)) << " /ls " << a_levelSetValuesMb(nghbr0, 0) << " "
2265 << a_levelSetValuesMb(nghbr1, 0) << endl;
2266 m_solutionDiverged = true;
2267 }
2268 }
2269 }
2270 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
2271 "m_solutionDiverged");
2272 if(m_solutionDiverged) {
2273 writeVtkXmlFiles("QOUT", "GEOM", false, true);
2274 MPI_Barrier(mpiComm(), AT_);
2275 mTerm(1, AT_,
2276 "Solution diverged after surface value computation @ " + to_string(m_RKStep) + "/"
2277 + to_string(globalTimeStep));
2278 }
2279#endif
2280
2281
2282 RECORD_TIMER_START(m_timers[Timers::MusclGhostSlopes]);
2283 updateGhostCellSlopesViscous();
2284 m_fvBndryCnd->updateCutOffSlopesViscous();
2285 RECORD_TIMER_STOP(m_timers[Timers::MusclGhostSlopes]);
2286
2287 correctBoundarySurfaceVariablesMb();
2288}
2289
2290
2295template <MInt nDim, class SysEqn>
2297 for(MInt i = 0; i < nDim; i++) {
2298 m_bboxLocal[i] = std::numeric_limits<MFloat>::max();
2299 m_bboxLocal[nDim + i] = std::numeric_limits<MFloat>::lowest();
2300 }
2301
2302 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
2303 if(a_isPeriodic(cellId)) continue;
2304
2305 for(MInt i = 0; i < nDim; i++) {
2306 m_bboxLocal[i] = mMin(m_bboxLocal[i], a_coordinate(cellId, i) - F1B2 * c_cellLengthAtCell(cellId));
2307 m_bboxLocal[nDim + i] = mMax(m_bboxLocal[nDim + i], a_coordinate(cellId, i) + F1B2 * c_cellLengthAtCell(cellId));
2308 }
2309 }
2310}
2311
2312
2317template <MInt nDim, class SysEqn>
2319 IF_CONSTEXPR(nDim == 3) {
2320 if(m_bodyTree != nullptr) {
2321 delete m_bodyTree;
2322 m_bodyTree = nullptr;
2323 }
2324 m_bodyCenters.clear();
2325
2326 for(MInt k = 0; k < (m_noEmbeddedBodies + m_noPeriodicGhostBodies); k++) {
2327 Point<3> a(m_bodyCenter[k * nDim], m_bodyCenter[k * nDim + 1], m_bodyCenter[k * nDim + 2], k);
2328 if(std::isnan(a.x[0]) || std::isnan(a.x[1]) || std::isnan(a.x[2]) || std::isinf(a.x[0]) || std::isinf(a.x[1])
2329 || std::isinf(a.x[2])) {
2330 mTerm(1, "ERROR body center is NAN " + to_string(k) + " " + to_string(a.x[0]) + " " + to_string(a.x[1]) + " "
2331 + to_string(a.x[2]));
2332 }
2333 m_bodyCenters.push_back(a);
2334 }
2335
2336 if(m_bodyCenters.size() > 0) {
2337 m_bodyTree = new KDtree<3>(m_bodyCenters);
2338 }
2339 }
2340}
2341
2342
2347template <MInt nDim, class SysEqn>
2349 IF_CONSTEXPR(nDim == 3) {
2350 if(m_bodyTreeLocal != nullptr) {
2351 delete m_bodyTreeLocal;
2352 m_bodyTreeLocal = nullptr;
2353 }
2354 m_bodyCentersLocal.clear();
2355
2356 for(MInt k = 0; k < (m_noEmbeddedBodies + m_noPeriodicGhostBodies); k++) {
2357 if(!m_bodyNearDomain[k]) continue;
2358 Point<nDim> a(m_bodyCenter[k * nDim + 0], m_bodyCenter[k * nDim + 1], m_bodyCenter[k * nDim + 2], k);
2359 if(std::isnan(a.x[0]) || std::isnan(a.x[1]) || std::isnan(a.x[2]) || std::isinf(a.x[0]) || std::isinf(a.x[1])
2360 || std::isinf(a.x[2])) {
2361 mTerm(1, "ERROR body center is NAN " + to_string(k) + " " + to_string(a.x[0]) + " " + to_string(a.x[1]) + " "
2362 + to_string(a.x[2]));
2363 }
2364 m_bodyCentersLocal.push_back(a);
2365 }
2366 m_bodyTreeLocal = new KDtree<nDim>(m_bodyCentersLocal);
2367 }
2368}
2369
2370
2375template <MInt nDim, class SysEqn>
2377 TRACE();
2378
2379 if(m_noEmbeddedBodies == 0) {
2380 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
2381 a_levelSetValuesMb(cellId, 0) = c_cellLengthAtLevel(0);
2382 a_hasProperty(cellId, SolverCell::IsInactive) = false;
2383 }
2384 return;
2385 }
2386
2387 if(m_motionEquation == 0) {
2388 if(updateBody) {
2389 updateBodyProperties();
2390 }
2391 createPeriodicGhostBodies();
2392 createBodyTree();
2393 }
2394
2395 const MInt noBodies = m_noEmbeddedBodies + m_noPeriodicGhostBodies;
2396 if(m_noLevelSetsUsedForMb == 1) {
2397 for(MInt k = 0; k < noBodies; k++) {
2398 m_bodyNearDomain[k] = true;
2399 for(MInt i = 0; i < nDim; i++) {
2400 if(m_bodyCenter[k * nDim + i] < m_bboxLocal[i] - (m_bodyDistThreshold + m_bodyRadius[k])) {
2401 m_bodyNearDomain[k] = false;
2402 }
2403 if(m_bodyCenter[k * nDim + i] > m_bboxLocal[nDim + i] + (m_bodyDistThreshold + m_bodyRadius[k])) {
2404 m_bodyNearDomain[k] = false;
2405 }
2406 }
2407 }
2408 }
2409
2410 if(!m_constructGField) {
2411 return;
2412 }
2413
2414 rebuildKDTreeLocal();
2415
2416 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
2417 a_levelSetValuesMb(cellId, 0) = c_cellLengthAtLevel(0);
2418 }
2419
2420 constexpr MFloat safetyFac = 1.1;
2421 const MFloat uncertaintyAngle = sqrt(FD) * c_cellLengthAtLevel(minLevel());
2422 const MFloat uncertaintyRotation = m_maxBodyRadius;
2423 const MFloat minWallDist = F3 * c_cellLengthAtLevel(maxLevel());
2424 const MFloat delta1 = safetyFac * (uncertaintyAngle + uncertaintyRotation);
2425 const MFloat delta0 = delta1 + safetyFac * minWallDist;
2426
2427 MFloatScratchSpace bodyDist(noBodies, AT_, "bodyDist");
2428 MIntScratchSpace bodyIds(noBodies, AT_, "bodyIds");
2429 MFloat deltaMax = m_bodyDistThreshold + m_maxBodyRadius;
2430 bodyDist.fill(deltaMax);
2431 bodyIds.fill(-1);
2432
2433 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
2434 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
2435 a_associatedBodyIds(cellId, set) = -1;
2436 a_levelSetValuesMb(cellId, set) = m_bodyDistThreshold + 1e-14;
2437 }
2438 }
2439
2440 for(MInt i = 0; i < noMinCells(); i++) {
2441 MInt cellId = minCell(i);
2442 MFloat minDist = c_cellLengthAtLevel(0);
2443 MInt bodyCnt = noBodies;
2444
2445 IF_CONSTEXPR(nDim == 3) {
2446 if(m_bodyTypeMb == 1 || m_bodyTypeMb == 3) {
2447 MBool overflow = false;
2448 Point<nDim> pt(a_coordinate(cellId, 0), a_coordinate(cellId, 1), a_coordinate(cellId, 2));
2449 bodyCnt = m_bodyTreeLocal->locatenearest(pt, deltaMax, &bodyIds[0], &bodyDist[0], noBodies, overflow);
2450 } else {
2451 for(MInt k = 0; k < noBodies; k++) {
2452 bodyIds[k] = k;
2453 }
2454 }
2455 }
2456 else {
2457 for(MInt k = 0; k < noBodies; k++) {
2458 bodyIds[k] = k;
2459 }
2460 }
2461
2462 // first check to improve performance: remove bodies which are too far away to be relevant
2463 for(MInt k = 0; k < bodyCnt; k++) {
2464 MFloat dist = F0;
2465 IF_CONSTEXPR(nDim == 2) {
2466 dist = sqrt(POW2(a_coordinate(cellId, 0) - m_bodyCenter[bodyIds[k] * nDim + 0])
2467 + POW2(a_coordinate(cellId, 1) - m_bodyCenter[bodyIds[k] * nDim + 1]));
2468 }
2469 IF_CONSTEXPR(nDim == 3) {
2470 dist = sqrt(POW2(a_coordinate(cellId, 0) - m_bodyCenter[bodyIds[k] * nDim + 0])
2471 + POW2(a_coordinate(cellId, 1) - m_bodyCenter[bodyIds[k] * nDim + 1])
2472 + POW2(a_coordinate(cellId, 2) - m_bodyCenter[bodyIds[k] * nDim + 2]));
2473 }
2474 if(dist > delta0 && dist > minDist + delta1) {
2475 if(k < bodyCnt - 1) {
2476 bodyIds[k] = bodyIds[bodyCnt - 1];
2477 bodyDist[k] = bodyDist[bodyCnt - 1];
2478 k--;
2479 }
2480 bodyCnt--;
2481 }
2482 minDist = mMin(minDist, dist);
2483 }
2484
2485 if(bodyCnt > 0) descendLevelSetValue(cellId, &bodyIds[0], bodyCnt);
2486
2487 MInt parentId = c_parentId(cellId);
2488 while(parentId > -1) {
2489 for(MInt set = 0; set < m_noSets; set++) {
2490 a_levelSetValuesMb(c_parentId(cellId), set) = a_levelSetValuesMb(cellId, set);
2491 a_associatedBodyIds(parentId, set) = a_associatedBodyIds(cellId, set);
2492 }
2493 parentId = c_parentId(parentId);
2494 }
2495 }
2496}
2497
2498
2503template <MInt nDim, class SysEqn>
2505 MFloatScratchSpace& nearestDist) {
2506 TRACE();
2507
2508 if(!m_constructGField) mTerm(1, AT_, "m_constructGField not set.");
2509 if(m_noEmbeddedBodies == 0) {
2510 return 0;
2511 }
2512
2513 if(m_bodyTypeMb) {
2514 const MInt noBodies = m_noEmbeddedBodies + m_noPeriodicGhostBodies;
2515
2516 MFloatScratchSpace bodyDist(noBodies, AT_, "bodyDist");
2517 MIntScratchSpace bodyIds(noBodies, AT_, "bodyIds");
2518
2519 constexpr MFloat safetyFac = 1.1;
2520 const MFloat deltaMax1 = safetyFac * (deltaMax + c_cellLengthAtLevel(minLevel()) + m_maxBodyRadius);
2521 bodyDist.fill(deltaMax1);
2522 bodyIds.fill(-1);
2523
2524 MInt maxBodyCnt = 0;
2525 for(MInt i = 0; i < noMinCells(); i++) {
2526 MInt cellId = minCell(i);
2527 MInt bodyCnt = noBodies;
2528 IF_CONSTEXPR(nDim == 3) {
2529 if(m_bodyTypeMb == 1 || m_bodyTypeMb == 3) {
2530 MBool overflow = false;
2531 Point<nDim> pt(a_coordinate(cellId, 0), a_coordinate(cellId, 1), a_coordinate(cellId, 2));
2532 if(deltaMax1 < m_bodyDistThreshold) {
2533 bodyCnt = m_bodyTreeLocal->locatenearest(pt, deltaMax1, &bodyIds[0], &bodyDist[0], noBodies, overflow);
2534 } else {
2535 bodyCnt = m_bodyTree->locatenearest(pt, deltaMax1, &bodyIds[0], &bodyDist[0], noBodies, overflow);
2536 }
2537 } else {
2538 for(MInt k = 0; k < noBodies; k++) {
2539 bodyIds[k] = k;
2540 }
2541 }
2542 }
2543 else {
2544 for(MInt k = 0; k < noBodies; k++) {
2545 bodyIds[k] = k;
2546 }
2547 }
2548 if(bodyCnt > 0) descendDistance(cellId, &bodyIds[0], bodyCnt, nearestBodies, nearestDist);
2549 maxBodyCnt = mMax(maxBodyCnt, bodyCnt);
2550 }
2551 MPI_Allreduce(MPI_IN_PLACE, &maxBodyCnt, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "maxBodyCnt");
2552 return maxBodyCnt;
2553 }
2554 return 0;
2555}
2556
2557
2562template <MInt nDim, class SysEqn>
2563void FvMbCartesianSolverXD<nDim, SysEqn>::getNormal(const MInt cellId, const MInt set, MFloat normal[]) {
2564 const MFloat FcellLength = F1 / c_cellLengthAtCell(cellId);
2565 normal[0] = numeric_limits<MFloat>::max();
2566 normal[1] = numeric_limits<MFloat>::max();
2567 IF_CONSTEXPR(nDim == 3) { normal[2] = numeric_limits<MFloat>::max(); }
2568
2569 if(m_bodyTypeMb == 1) {
2570 getNormalSphere(cellId, set, normal);
2571 } else if(m_bodyTypeMb == 3) {
2572 getNormalEllipsoid(cellId, set, normal);
2573 } else {
2574 MInt cndId = (a_hasProperty(cellId, SolverCell::IsSplitChild))
2575 ? m_bndryCandidateIds[getAssociatedInternalCell(cellId)]
2576 : m_bndryCandidateIds[cellId];
2577 if(cndId < 0) mTerm(1, AT_, "candidate not found");
2578 for(MInt node = 0; node < m_noCellNodes; node++) {
2579 if(!m_candidateNodeSet[cndId * m_noCellNodes + node]) mTerm(1, AT_, "candidate node not set");
2580 }
2581 IF_CONSTEXPR(nDim == 3) {
2582 normal[0] = F1B4 * FcellLength
2583 * (-m_candidateNodeValues[IDX_LSSETNODES(cndId, 0, set)]
2584 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 1, set)]
2585 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 2, set)]
2586 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 3, set)]
2587 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 4, set)]
2588 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 5, set)]
2589 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 6, set)]
2590 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 7, set)]);
2591 normal[1] = F1B4 * FcellLength
2592 * (-m_candidateNodeValues[IDX_LSSETNODES(cndId, 0, set)]
2593 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 1, set)]
2594 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 2, set)]
2595 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 3, set)]
2596 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 4, set)]
2597 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 5, set)]
2598 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 6, set)]
2599 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 7, set)]);
2600 normal[2] = F1B4 * FcellLength
2601 * (-m_candidateNodeValues[IDX_LSSETNODES(cndId, 0, set)]
2602 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 1, set)]
2603 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 2, set)]
2604 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 3, set)]
2605 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 4, set)]
2606 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 5, set)]
2607 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 6, set)]
2608 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 7, set)]);
2609 }
2610 else {
2611 normal[0] = F1B4 * FcellLength
2612 * (-m_candidateNodeValues[IDX_LSSETNODES(cndId, 0, set)]
2613 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 1, set)]
2614 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 2, set)]
2615 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 3, set)]);
2616 normal[1] = F1B4 * FcellLength
2617 * (-m_candidateNodeValues[IDX_LSSETNODES(cndId, 0, set)]
2618 - m_candidateNodeValues[IDX_LSSETNODES(cndId, 1, set)]
2619 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 2, set)]
2620 + m_candidateNodeValues[IDX_LSSETNODES(cndId, 3, set)]);
2621 }
2622 MFloat sum = F0;
2623 for(MInt i = 0; i < nDim; i++) {
2624 sum += POW2(normal[i]);
2625 }
2626 sum = sqrt(sum);
2627 for(MInt i = 0; i < nDim; i++) {
2628 normal[i] /= sum;
2629 }
2630 }
2631}
2632
2633
2638template <MInt nDim, class SysEqn>
2640 const MInt bodyId = a_associatedBodyIds(cellId, set);
2641 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
2642
2643 for(MInt i = 0; i < nDim; i++) {
2644 normal[i] = F0;
2645 }
2646 MFloat cnt = F0;
2647 for(MInt i = 0; i < nDim; i++) {
2648 normal[i] = a_coordinate(cellId, i) - m_bodyCenter[nDim * bodyId + i];
2649 cnt += POW2(normal[i]);
2650 }
2651 cnt = sqrt(cnt);
2652 for(MInt i = 0; i < nDim; i++) {
2653 normal[i] /= cnt;
2654 }
2655}
2656
2657
2662template <MInt nDim, class SysEqn>
2664 const MInt bodyId = a_associatedBodyIds(cellId, set);
2665 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
2666
2667 MFloatScratchSpace R(3, 3, AT_, "R");
2668 computeRotationMatrix(R, &(m_bodyQuaternion[4 * bodyId]));
2669
2670 // shift centroid to body center
2671 MFloat x = a_coordinate(cellId, 0) - m_bodyCenter[bodyId * nDim + 0];
2672 MFloat y = a_coordinate(cellId, 1) - m_bodyCenter[bodyId * nDim + 1];
2673 MFloat z = a_coordinate(cellId, 2) - m_bodyCenter[bodyId * nDim + 2];
2674
2675 MFloat xw[3];
2676 MFloat xb[3];
2677 xw[0] = x;
2678 xw[1] = y;
2679 xw[2] = z;
2680 matrixVectorProduct(xb, R, xw); // rotate to body principal axes
2681 x = xb[0];
2682 y = xb[1];
2683 z = xb[2];
2684
2685 MFloat a = m_bodyRadii[bodyId * nDim + 0];
2686 MFloat b = m_bodyRadii[bodyId * nDim + 1];
2687 MFloat c = m_bodyRadii[bodyId * nDim + 2];
2688
2689 MFloat ee[3] = {a, b, c};
2690 MFloat yy[3] = {x, y, z};
2691 MFloat xx[3] = {F0, F0, F0};
2692
2693 // query nearest surface point
2694 distancePointEllipsoid(ee, yy, xx);
2695
2696 MFloat norm2[3];
2697 MFloat n2sum = F0;
2698 for(MInt i = 0; i < nDim; i++) {
2699 norm2[i] = F2 * xx[i] / POW2(m_bodyRadii[bodyId * nDim + i]);
2700 n2sum += POW2(norm2[i]);
2701 }
2702 n2sum = sqrt(n2sum);
2703 for(MInt i = 0; i < nDim; i++) {
2704 norm2[i] /= n2sum;
2705 }
2706
2707 matrixVectorProductTranspose(normal, R, norm2); // rotate back
2708}
2709
2710
2715template <MInt nDim, class SysEqn>
2717 MFloat dist = c_cellLengthAtLevel(0);
2718
2719 if(m_bodyTypeMb == 1) {
2720 dist = getDistanceSphere(coordinates, bodyId);
2721 } else if(m_bodyTypeMb == 2) {
2722 dist = getDistancePiston(coordinates, bodyId);
2723 } else if(m_bodyTypeMb == 3) {
2724 dist = getDistanceEllipsoid(coordinates, bodyId);
2725 } else if(m_bodyTypeMb == 7) {
2726 dist = getDistanceTetrahedron(coordinates, bodyId);
2727 } else {
2728 mTerm(1, AT_, "generalize here");
2729 }
2730
2731 return dist;
2732}
2733
2734
2739template <MInt nDim, class SysEqn>
2741 return getDistance(&a_coordinate(cellId, 0), bodyId);
2742}
2743
2744
2749template <MInt nDim, class SysEqn>
2751 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
2752 MFloat dist = F0;
2753 IF_CONSTEXPR(nDim == 2) {
2754 dist = sqrt(POW2(coordinates[0] - m_bodyCenter[bodyId * nDim])
2755 + POW2(coordinates[1] - m_bodyCenter[bodyId * nDim + 1]))
2756 - (m_bodyRadius[bodyId]);
2757 }
2758 else IF_CONSTEXPR(nDim == 3) {
2759 dist =
2760 sqrt(POW2(coordinates[0] - m_bodyCenter[bodyId * nDim]) + POW2(coordinates[1] - m_bodyCenter[bodyId * nDim + 1])
2761 + POW2(coordinates[2] - m_bodyCenter[bodyId * nDim + 2]))
2762 - (m_bodyRadius[bodyId]);
2763 }
2764 return dist;
2765}
2766
2767
2772template <MInt nDim, class SysEqn>
2774 return getDistanceSphere(&a_coordinate(cellId, 0), bodyId);
2775}
2776
2777
2784template <MInt nDim, class SysEqn>
2786 MFloat& h = m_static_getDistanceSplitSphere_h;
2787 MBool& first = m_static_getDistanceSplitSphere_first;
2788 if(first) {
2789 MFloat h_default = m_bodyRadius[0] / 100;
2801 h = Context::getSolverProperty<MFloat>("splitSphereSlitHeight", m_solverId, AT_, &h_default);
2802 first = false;
2803 }
2804 MFloat dist = 123456.789;
2805 if(m_noEmbeddedBodies > 2) mTerm(1, AT_, "splitSphere does only work for one or two bodies");
2806 MFloat signCode[2] = {-F1, F1};
2807
2808 MFloat x = a_coordinate(cellId, 0);
2809 MFloat y = a_coordinate(cellId, 1);
2810 MFloat r = sqrt(POW2(a_coordinate(cellId, 0) - m_bodyCenter[0 * nDim])
2811 + POW2(a_coordinate(cellId, 1) - m_bodyCenter[0 * nDim + 1]));
2812 MFloat yIS = h / 2;
2813 const MInt k = bodyId;
2814 MFloat xIS = sqrt(m_bodyRadius[k] * m_bodyRadius[k] - yIS * yIS);
2815 MFloat phi1 = r - m_bodyRadius[k];
2816 MFloat phi2 = -signCode[k] * (y - signCode[k] * yIS - m_bodyCenter[0 * nDim + 1]);
2817 MFloat phi3 =
2818 sqrt((y - signCode[k] * yIS - m_bodyCenter[0 * nDim + 1]) * (y - signCode[k] * yIS - m_bodyCenter[0 * nDim + 1])
2819 + (x - xIS) * (x - xIS));
2820 MFloat phi4 =
2821 sqrt((y - signCode[k] * yIS - m_bodyCenter[0 * nDim + 1]) * (y - signCode[k] * yIS - m_bodyCenter[0 * nDim + 1])
2822 + (x + xIS) * (x + xIS));
2823
2824 if(x < -xIS && phi2 > F0)
2825 dist = phi4;
2826 else if(x > xIS && phi2 > F0)
2827 dist = phi3;
2828 else if(phi2 > F0)
2829 dist = phi2;
2830 else if(phi1 > F0)
2831 dist = phi1;
2832 else
2833 dist = mMax(phi1, phi2);
2834
2835 return dist;
2836}
2837
2838
2839template <MInt nDim, class SysEqn>
2841 const MFloat sign) {
2842 // static constexpr MFloat XXTMP = 12.0;
2843 MFloat XXTMP = 12.0;
2844
2845 ASSERT(nDim == 2, "Untested for 3D");
2846
2855 const MFloat XX = Context::getSolverProperty<MFloat>("NACA00XX", m_solverId, AT_, &XXTMP);
2856 const MFloat b = 0.05 * XX;
2857 const MFloat eps = 1e-10;
2858 const MInt maxIter = 1000;
2859 const MFloat p0 = coordinate[0];
2860 const MFloat q0 = coordinate[1];
2861 MFloat bodyRotation[3] = {0};
2862 getBodyRotation(0, bodyRotation);
2863 const MFloat p = cos(-bodyRotation[2]) * p0 - sin(-bodyRotation[2]) * q0 + F1B4;
2864 const MFloat q = sin(-bodyRotation[2]) * p0 + cos(-bodyRotation[2]) * q0;
2865 // const MFloat sign = ( q < F0 ) ? -F1 : F1;
2866
2867 if(fabs(q) < m_eps) {
2868 if(p < F0)
2869 return (-p);
2870 else if(p > F1)
2871 return (p - F1);
2872 }
2873
2874 // MFloat Y097 = b * ( (0.2969*sqrt(0.97)) - (0.126*0.97) - (0.3516*0.97*0.97) + (0.2843*0.97*0.97*0.97) -
2875 // (0.1036*0.97*0.97*0.97*0.97) );
2876 //-> y(x>=0.97) = Y097-(Y097*(x-0.97)/(F1-0.97))
2877
2878 MFloat x = 1e-12;
2879 // MFloat y = sign * b * ( (0.2969*sqrt(x)) - (0.126*x) - (0.3516*x*x) + (0.2843*x*x*x) - (0.1015*x*x*x*x) );
2880 MFloat y = sign * b
2881 * ((0.2969 * sqrt(x)) - (0.126 * x) - (0.3516 * x * x) + (0.2843 * x * x * x) - (0.1036 * x * x * x * x));
2882 // MFloat yp = sign * b * ( (F1B2*0.2969/sqrt(x)) - (0.126) - (F2*0.3516*x) + (F3*0.2843*x*x) - (F4*0.1015*x*x*x) );
2883 MFloat yp =
2884 sign * b
2885 * ((F1B2 * 0.2969 / sqrt(x)) - (0.126) - (F2 * 0.3516 * x) + (F3 * 0.2843 * x * x) - (F4 * 0.1036 * x * x * x));
2886 MFloat f = (p - x) + yp * (q - y);
2887 MFloat xa = x;
2888 MFloat ya = y;
2889 MFloat fa = f;
2890
2891 x = F1;
2892 // y = sign * b * ( (0.2969*sqrt(x)) - (0.126*x) - (0.3516*x*x) + (0.2843*x*x*x) - (0.1015*x*x*x*x) );
2893 y = sign * b
2894 * ((0.2969 * sqrt(x)) - (0.126 * x) - (0.3516 * x * x) + (0.2843 * x * x * x) - (0.1036 * x * x * x * x));
2895 // yp = sign * b * ( (F1B2*0.2969/sqrt(x)) - (0.126) - (F2*0.3516*x) + (F3*0.2843*x*x) - (F4*0.1015*x*x*x) );
2896 yp = sign * b
2897 * ((F1B2 * 0.2969 / sqrt(x)) - (0.126) - (F2 * 0.3516 * x) + (F3 * 0.2843 * x * x) - (F4 * 0.1036 * x * x * x));
2898 f = (p - x) + yp * (q - y);
2899 MFloat xb = x;
2900 MFloat yb = y;
2901 MFloat fb = f;
2902
2903 if(fa * fb > F0) {
2904 if(p < F0) {
2905 // cerr << "Bisection warning " << p << " " << q << endl;
2906 x = xa;
2907 y = ya;
2908
2909 /*
2910 // NEWTON
2911 MFloat res = F1;
2912 MInt iter = 0;
2913 xb = 0.2;
2914 x = F1B2*(xa+xb);
2915 //x = mMin(xb-m_eps,mMax(xa+m_eps,p));
2916 while ( ( res > eps ) && ( iter < maxIter ) && ( x > xa ) && ( x < xb ) ) {
2917 y = sign * b * ( (0.2969*sqrt(x)) - (0.126*x) - (0.3516*x*x) + (0.2843*x*x*x) - (0.1036*x*x*x*x) );
2918 yp = sign * b * ( (F1B2*0.2969/sqrt(x)) - (0.126) - (F2*0.3516*x) + (F3*0.2843*x*x) - (F4*0.1036*x*x*x) );
2919 MFloat ypp = sign * b * ( (-F1B4*0.2969/(x*sqrt(x))) - (F2*0.3516) + (6.0*0.2843*x) - (12.0*0.1036*x*x)
2920 ); f = (p-x) + yp*(q-y); MFloat fp = -F1 + ypp*(y-q) - POW2(yp); MFloat dx = - f/fp; x += dx; res =
2921 fabs(dx); iter++;
2922 }
2923 */
2924
2925 } else if(p > F1) {
2926 x = xb;
2927 y = yb;
2928 } else {
2929 // cerr << cellId << " p/q=" << p << "/" << q << " " << sign << endl;
2930 // mTerm(1,AT_, "Bisection failed.");
2931 // cin.get();
2932
2933
2934 // NEWTON
2935 MFloat res = F1;
2936 MInt iter = 0;
2937 // x = F1B2*(xa+xb);
2938 x = mMin(xb - m_eps, mMax(xa + m_eps, p));
2939 while((res > eps) && (iter < maxIter) && (x > xa) && (x < xb)) {
2940 y = sign * b
2941 * ((0.2969 * sqrt(x)) - (0.126 * x) - (0.3516 * x * x) + (0.2843 * x * x * x) - (0.1036 * x * x * x * x));
2942 yp = sign * b
2943 * ((F1B2 * 0.2969 / sqrt(x)) - (0.126) - (F2 * 0.3516 * x) + (F3 * 0.2843 * x * x)
2944 - (F4 * 0.1036 * x * x * x));
2945 MFloat ypp =
2946 sign * b
2947 * ((-F1B4 * 0.2969 / (x * sqrt(x))) - (F2 * 0.3516) + (6.0 * 0.2843 * x) - (12.0 * 0.1036 * x * x));
2948 f = (p - x) + yp * (q - y);
2949 MFloat fp = -F1 + ypp * (y - q) - POW2(yp);
2950 MFloat dx = -f / fp;
2951 x += dx;
2952 res = fabs(dx);
2953 iter++;
2954 }
2955 }
2956 } else {
2957 // BISECTION
2958 MFloat res = F1;
2959 MInt iter = 0;
2960 while((res > eps) && (iter < maxIter)) {
2961 x = F1B2 * (xa + xb);
2962 // y = sign * b * ( (0.2969*sqrt(x)) - (0.126*x) - (0.3516*x*x) + (0.2843*x*x*x) - (0.1015*x*x*x*x) );
2963 y = sign * b
2964 * ((0.2969 * sqrt(x)) - (0.126 * x) - (0.3516 * x * x) + (0.2843 * x * x * x) - (0.1036 * x * x * x * x));
2965 // yp = sign * b * ( (F1B2*0.2969/sqrt(x)) - (0.126) - (F2*0.3516*x) + (F3*0.2843*x*x) - (F4*0.1015*x*x*x) );
2966 yp = sign * b
2967 * ((F1B2 * 0.2969 / sqrt(x)) - (0.126) - (F2 * 0.3516 * x) + (F3 * 0.2843 * x * x)
2968 - (F4 * 0.1036 * x * x * x));
2969 f = (p - x) + yp * (q - y);
2970 if(fa * f < F0) {
2971 xb = x;
2972 yb = y;
2973 fb = f;
2974 } else {
2975 xa = x;
2976 ya = y;
2977 fa = f;
2978 }
2979 // res = fabs(xb-xa);
2980 // res = fabs(f);
2981 res = mMax(fabs(f), fabs(xb - xa));
2982 iter++;
2983 }
2984 if(iter >= maxIter) {
2985 cerr << "Warning: max iterations exceeded in bisection" << endl;
2986 }
2987 }
2988
2989
2990 /*
2991 while ( ( fabs(dpx) > eps ) && ( iter < maxIter ) ) {
2992
2993 MFloat fx = x - px + ( y - py ) * pyp;
2994 MFloat fxp = -F1 + pypp * ( y - py ) - POW2(pyp);
2995 dpx = - fx/fxp;
2996 px += dpx;
2997 py = sign * b * ( (0.2969*sqrt(px)) - (0.126*px) - (0.3516*px*px) + (0.2843*px*px*px) - (0.1015*px*px*px*px) );
2998 pyp = sign * b * ( (F1B2*0.2969/sqrt(px)) - (0.126) - (F2*0.3516*px) + (F3*0.2843*px*px) - (F4*0.1015*px*px*px) );
2999 pypp = sign * b * ( (-F1B4*0.2969/(px*sqrt(px))) - (F2*0.3516) + (6.0*0.2843*px) - (12.0*0.1015*px*px) );
3000 iter++;
3001
3002 }
3003 */
3004
3005 MFloat dist = sqrt(POW2(p - x) + POW2(q - y));
3006 // if ( (p > F0) && (p < F1) && ( sign*q < sign*y ) ) dist *= -F1;
3007 if((p > F0) && (p < F1) && (sign * q < sign * y)) dist *= -F1;
3008 // if ( sign*q < sign*y ) dist *= -F1;
3009 // if ( y*q < F0 ) dist = -F1*fabs(dist);
3010
3011
3012#ifndef NACA0012SPLIT
3013 // rounded traling edge !!!
3014 // const MFloat xr = 0.988; // -> -1%
3015 // const MFloat xr = 0.982; // -> -1.5%
3016 const MFloat xr = 0.994; // -> -0.5%
3017 const MFloat yr = b
3018 * ((0.2969 * sqrt(xr)) - (0.126 * xr) - (0.3516 * xr * xr) + (0.2843 * xr * xr * xr)
3019 - (0.1036 * xr * xr * xr * xr));
3020 if(p > xr) {
3021 dist = sqrt(POW2(p - xr) + POW2(q)) - yr;
3022 }
3023#endif
3024
3025 return dist;
3026}
3027
3028
3032template <MInt nDim, class SysEqn>
3034 TRACE();
3035
3036
3037 MIntScratchSpace flag(a_noCells(), AT_, "flag");
3038 multimap<MFloat, MInt> approximateLSV;
3039 multimap<MFloat, MInt> initLSV;
3040 MFloat eps = 1.0e-10;
3041 const MInt _far = 2;
3042 const MInt band = 1;
3043 const MInt accepted = 0;
3044
3045 findNghbrIds();
3046
3047 // find first layer of halo cells:
3048 MBoolScratchSpace isFirstLayerHalo(a_noCells(), AT_, "isFirstLayerHalo");
3049 MIntScratchSpace firstLayerHalos(a_noCells(), AT_, "firstLayerHalos");
3050 MBoolScratchSpace isFarHalo(a_noCells(), AT_, "isFarHalo");
3051 MInt firstLayerHaloCount = 0;
3052 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
3053 isFirstLayerHalo[cellId] = false;
3054 isFarHalo[cellId] = false;
3055 if(!a_isHalo(cellId)) continue;
3056 isFarHalo[cellId] = true;
3057 for(MInt direction = 0; direction < (2 * nDim); direction++) {
3058 for(MInt j = m_identNghbrIds[2 * cellId * nDim + direction];
3059 j < m_identNghbrIds[2 * cellId * nDim + direction + 1];
3060 j++) {
3061 MInt nghbrId = m_storeNghbrIds[j];
3062 if(a_isWindow(nghbrId)) {
3063 isFirstLayerHalo[cellId] = true;
3064 isFarHalo[cellId] = false;
3065 firstLayerHalos[firstLayerHaloCount++] = cellId;
3066 break;
3067 }
3068 }
3069 }
3070 }
3071
3072 // initialize flag:
3073 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
3074 flag[cellId] = _far;
3075 }
3076
3077 // Initialize: Search calculated Points , create NarrowBand with approximated levelSetValues
3078 MBoolScratchSpace isStartCell(a_noCells(), AT_, "isStartCell");
3079 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
3080 isStartCell[cellId] = false;
3081 if(c_noChildren(cellId)) {
3082 a_levelSetValuesMb(cellId, 0) = c_cellLengthAtLevel(0);
3083 continue;
3084 }
3085 if(isFarHalo[cellId] || isFirstLayerHalo[cellId]) {
3086 a_levelSetValuesMb(cellId, 0) = c_cellLengthAtLevel(0);
3087 continue;
3088 }
3089 MFloat limitValue = c_cellLengthAtLevel(a_level(cellId)) * sqrt(nDim);
3090 if(a_levelSetValuesMb(cellId, 0) < 0 || (false && a_levelSetValuesMb(cellId, 0) < limitValue)) {
3091 flag[cellId] = accepted;
3092 initLSV.insert(make_pair(a_levelSetValuesMb(cellId, 0), cellId));
3093 isStartCell[cellId] = true;
3094 } else {
3095 a_levelSetValuesMb(cellId, 0) = c_cellLengthAtLevel(0);
3096 }
3097 }
3098
3099 while(!initLSV.empty()) {
3100 multimap<MFloat, MInt>::iterator it = initLSV.begin();
3101 MInt cellId = it->second;
3102 initLSV.erase(it);
3103 for(MInt direction = 0; direction < (2 * nDim); direction++) {
3104 for(MInt j = m_identNghbrIds[2 * cellId * nDim + direction];
3105 j < m_identNghbrIds[2 * cellId * nDim + direction + 1];
3106 j++) {
3107 MInt nghbrId = m_storeNghbrIds[j];
3108 if(isFarHalo[nghbrId]) continue;
3109 if(flag[nghbrId] == accepted) continue;
3110 if(!isFirstLayerHalo[nghbrId] && !isStartCell[nghbrId]) { // for halos a new value can't be computed!
3111 a_levelSetValuesMb(nghbrId, 0) = CalculateLSV(nghbrId, flag);
3112 }
3113 approximateLSV.insert(make_pair(a_levelSetValuesMb(nghbrId, 0), nghbrId));
3114 flag[nghbrId] = band; // halo cells may be included in the narrow band!
3115 }
3116 }
3117 }
3118
3119 MBool somethingOnBoundaryChanged = true;
3120 MInt count = 0;
3121 while(somethingOnBoundaryChanged) {
3122 count++;
3123 somethingOnBoundaryChanged = false;
3124 MFloatScratchSpace oldLVS(a_noCells(), AT_, "oldLVS");
3125 for(MInt cellId = 0; cellId < a_noCells(); cellId++)
3126 oldLVS[cellId] = a_levelSetValuesMb(cellId, 0);
3127
3128 // main loop of the algorithm: take the cell with the smallest approximate value out of the band, update its
3129 // neighbors and put them into the band if necessary
3130 while(!approximateLSV.empty()) {
3131 multimap<MFloat, MInt>::iterator it = approximateLSV.begin();
3132 MInt cellId = it->second;
3133 approximateLSV.erase(it);
3134 if(flag[cellId] == accepted) continue;
3135 flag[cellId] = accepted;
3136 for(MInt direction = 0; direction < (m_noDirs); direction++) {
3137 for(MInt j = m_identNghbrIds[2 * cellId * nDim + direction];
3138 j < m_identNghbrIds[2 * cellId * nDim + direction + 1];
3139 j++) {
3140 MInt nghbrId = m_storeNghbrIds[j];
3141 if(isFarHalo[nghbrId]) continue;
3142 if(flag[nghbrId] == accepted) continue;
3143 if(!isFirstLayerHalo[nghbrId]
3144 && !isStartCell[nghbrId]) { // for halos and start cells a new value can't be computed!
3145 a_levelSetValuesMb(nghbrId, 0) = CalculateLSV(nghbrId, flag);
3146 }
3147 approximateLSV.insert(make_pair(a_levelSetValuesMb(nghbrId, 0), nghbrId));
3148 flag[nghbrId] = band; // halo cells may be included in the narrow band!
3149 }
3150 }
3151 }
3152
3153 // compute changes in the field after main loop
3154 MFloat change = F0;
3155 MInt noCells = 0;
3156 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
3157 if(isFirstLayerHalo[cellId] || isFarHalo[cellId]) continue;
3158 if(c_noChildren(cellId) > 0) continue;
3159 MFloat tmpChange =
3160 (a_levelSetValuesMb(cellId, 0) - oldLVS[cellId]) * (a_levelSetValuesMb(cellId, 0) - oldLVS[cellId]);
3161 if(tmpChange > F0) {
3162 change += tmpChange;
3163 noCells++;
3164 }
3165 }
3166 if(noCells > 0) change = sqrt(change) / noCells;
3167
3168 // special part for parallel execution
3169 if(noNeighborDomains() > 0) {
3170 // exchange values of halo cells
3171 MBoolScratchSpace valueChanged(a_noCells(), AT_, "valueChanged");
3172 MInt sendCount = 0;
3173 MInt receiveCount = 0;
3174 for(MInt i = 0; i < noNeighborDomains(); i++) {
3175 sendCount += (signed)noWindowCells(i);
3176 receiveCount += (signed)noHaloCells(i);
3177 }
3178 ScratchSpace<MFloat> sendBuffer(sendCount, AT_, "sendBuffer");
3179 ScratchSpace<MFloat> receiveBuffer(receiveCount, AT_, "receiveBuffer");
3180
3181 // 1. gather
3182 sendCount = 0;
3183 for(MInt i = 0; i < noNeighborDomains(); i++) {
3184 for(MInt j = 0; j < (signed)noWindowCells(i); j++) {
3185 sendBuffer.p[sendCount] = a_levelSetValuesMb(windowCellId(i, j), 0);
3186 sendCount++;
3187 }
3188 }
3189 // 2. send
3190 sendCount = 0;
3191 for(MInt i = 0; i < noNeighborDomains(); i++) {
3192 MInt bufSize = (signed)noWindowCells(i);
3193 MPI_Issend(&(sendBuffer.p[sendCount]), bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i],
3194 AT_, "(sendBuffer.p[sendCount])");
3195 sendCount += noWindowCells(i);
3196 }
3197 // 3. receive
3198 MPI_Status status;
3199 receiveCount = 0;
3200 for(MInt i = 0; i < noNeighborDomains(); i++) {
3201 MInt bufSize = (signed)noHaloCells(i);
3202 MPI_Recv(&(receiveBuffer.p[receiveCount]), bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &status, AT_,
3203 "(receiveBuffer.p[ receiveCount ])");
3204 receiveCount += noHaloCells(i);
3205 }
3206 for(MInt i = 0; i < noNeighborDomains(); i++) {
3207 MPI_Wait(&g_mpiRequestMb[i], &status, AT_);
3208 }
3209
3210 // 4. scatter
3211 receiveCount = 0;
3212 for(MInt i = 0; i < noNeighborDomains(); i++) {
3213 for(MInt j = 0; j < (signed)noHaloCells(i); j++) {
3214 MInt cellId = haloCellId(i, j);
3215 valueChanged[cellId] = false;
3216 if(abs(a_levelSetValuesMb(cellId, 0) - receiveBuffer.p[receiveCount]) > eps) {
3217 valueChanged[cellId] = true;
3218 }
3219 a_levelSetValuesMb(cellId, 0) = receiveBuffer.p[receiveCount];
3220 receiveCount++;
3221 }
3222 }
3223
3224 // check if halo acts as a source for at least one close halo cell
3225 MBoolScratchSpace isSource(firstLayerHaloCount, AT_, "isSource");
3226 for(MInt hc = 0; hc < firstLayerHaloCount; hc++) {
3227 isSource[hc] = false;
3228 MInt haloId = firstLayerHalos[hc];
3229 for(MInt direction = 0; direction < (2 * nDim); direction++) {
3230 for(MInt j = m_identNghbrIds[2 * haloId * nDim + direction];
3231 j < m_identNghbrIds[2 * haloId * nDim + direction + 1];
3232 j++) {
3233 MInt nghbrId = m_storeNghbrIds[j];
3234 if(!isFarHalo[nghbrId] && !isFirstLayerHalo[nghbrId]
3235 && !isStartCell[nghbrId]) { // nghbr is internal cell and not start cell
3236 if(a_levelSetValuesMb(haloId, 0) < a_levelSetValuesMb(nghbrId, 0)) {
3237 isSource[hc] = true;
3238 }
3239 }
3240 }
3241 }
3242 }
3243
3244 // compute min val of source halos that changed their value
3245 MFloat minHaloVal = c_cellLengthAtLevel(0);
3246 for(MInt hc = 0; hc < firstLayerHaloCount; hc++) {
3247 MInt haloId = firstLayerHalos[hc];
3248 if(isSource[hc] && valueChanged[haloId]) {
3249 minHaloVal = mMin(minHaloVal, a_levelSetValuesMb(haloId, 0));
3250 somethingOnBoundaryChanged = true;
3251 }
3252 if(isSource[hc]) {
3253 flag[haloId] = band;
3254 approximateLSV.insert(make_pair(a_levelSetValuesMb(haloId, 0), haloId));
3255 } else {
3256 flag[haloId] = _far;
3257 }
3258 }
3259
3260 // exchange somethingChanged globally
3261 MIntScratchSpace globalSomethingChanged(1, AT_, "globalSomethingChanged");
3262 MIntScratchSpace somethingChangedExchange(1, AT_, "somethingChangedExchange");
3263 somethingChangedExchange[0] = somethingOnBoundaryChanged;
3264 MPI_Allreduce(somethingChangedExchange.getPointer(), globalSomethingChanged.getPointer(), 1, MPI_INT, MPI_MAX,
3265 mpiComm(), AT_, "somethingChangedExchange.getPointer()", "globalSomethingChanged.getPointer()");
3266 somethingOnBoundaryChanged = globalSomethingChanged[0];
3267
3268 // reassign flags for all cells and reset their value if necessary
3269 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
3270 if(isFarHalo[cellId] || isFirstLayerHalo[cellId]) continue;
3271 if(c_noChildren(cellId) > 0) continue;
3272 if(isStartCell[cellId]) {
3273 flag[cellId] = accepted;
3274 } else if(abs(a_levelSetValuesMb(cellId, 0) - minHaloVal) < eps) {
3275 flag[cellId] = band;
3276 approximateLSV.insert(make_pair(a_levelSetValuesMb(cellId, 0), cellId));
3277 } else if(a_levelSetValuesMb(cellId, 0) < minHaloVal) {
3278 flag[cellId] = accepted;
3279 } else {
3280 flag[cellId] = _far;
3281 }
3282 }
3283 // set all neighbors of accepted cells (that are not accepted themselves) in band
3284 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
3285 if(flag[cellId] != accepted) continue;
3286 for(MInt direction = 0; direction < (2 * nDim); direction++) {
3287 for(MInt j = m_identNghbrIds[2 * cellId * nDim + direction];
3288 j < m_identNghbrIds[2 * cellId * nDim + direction + 1];
3289 j++) {
3290 MInt nghbrId = m_storeNghbrIds[j];
3291 if(isFarHalo[nghbrId]) continue;
3292 if(flag[nghbrId] == _far) {
3293 flag[nghbrId] = band;
3294 approximateLSV.insert(make_pair(a_levelSetValuesMb(nghbrId, 0), nghbrId));
3295 }
3296 }
3297 }
3298 }
3299 // reset the value of all far cells to c_cellLengthAtLevel(0)
3300 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
3301 if(flag[cellId] != _far) continue;
3302 if(isFarHalo[cellId] || isFirstLayerHalo[cellId]) continue;
3303 a_levelSetValuesMb(cellId, 0) = c_cellLengthAtLevel(0);
3304 }
3305 }
3306 }
3307
3308 // make sure, parent cells have a meaningful value:
3309 for(MInt level = maxRefinementLevel() - 1; level >= maxUniformRefinementLevel(); level--) {
3310 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
3311 if(a_level(cellId) != level) continue;
3312 if(c_isLeafCell(cellId)) continue;
3313 a_levelSetValuesMb(cellId, 0) = F0;
3314 for(MInt child = 0; child < IPOW2(nDim); child++) {
3315 MInt childId = c_childId(cellId, child);
3316 if(childId > -1) a_levelSetValuesMb(cellId, 0) += a_levelSetValuesMb(childId, 0);
3317 }
3318 a_levelSetValuesMb(cellId, 0) /= c_noChildren(cellId);
3319 }
3320 }
3321
3322 mDeallocate(m_storeNghbrIds);
3323 mDeallocate(m_identNghbrIds);
3324}
3325
3326
3332template <MInt nDim, class SysEqn>
3334 TRACE();
3335
3336 // LevelSetValues of the direct and second Neighbours
3337 MFloat a[3] = {F0, F0, F0};
3338 MFloat delta_cell[3] = {F0, F0, F0};
3339 // 1.Index: approximation level 2.Index: direction
3340 MFloat delta_taylor[2][3] = {{F0, F0, F0}, {F0, F0, F0}};
3341 MFloat levelSetValues = c_cellLengthAtLevel(0);
3342 const MFloat eps = 1.0e-3 * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
3343 const MInt accepted = 0;
3344
3345 // find smallest values and associated delta_cell by every axes direction
3346 for(MInt direction = 0; direction < (2 * nDim); direction++) {
3347 MInt index = (MInt)direction / 2;
3348 for(MInt j = m_identNghbrIds[2 * cellId * nDim + direction]; j < m_identNghbrIds[2 * cellId * nDim + direction + 1];
3349 j++) {
3350 MInt nghbrId = m_storeNghbrIds[j];
3351 if(flag[nghbrId] == accepted && a_levelSetValuesMb(nghbrId, 0) < a_levelSetValuesMb(cellId, 0)) {
3352 if(a[index] > F0) {
3353 if(a_levelSetValuesMb(nghbrId, 0) < a[index]) {
3354 a[index] = a_levelSetValuesMb(nghbrId, 0);
3355 delta_cell[index] = c_cellLengthAtLevel(a_level(nghbrId));
3356 }
3357 } else {
3358 a[index] = a_levelSetValuesMb(nghbrId, 0);
3359 delta_cell[index] = c_cellLengthAtLevel(a_level(nghbrId));
3360 }
3361 }
3362 }
3363 }
3364 // 2D CalculateLSV by approximation with taylor
3365 IF_CONSTEXPR(nDim == 2) {
3366 if(!(a[0] > F0) && !(a[1] > F0)) {
3367 } else if(!(a[0] > F0)) {
3368 // only in y-Direction
3369 delta_taylor[0][1] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[1]) * FFPOW2(1);
3370 levelSetValues = a[1] + delta_taylor[0][1];
3371 } else if(!(a[1] > F0)) {
3372 // only in x-Direction
3373 delta_taylor[0][0] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[0]) * FFPOW2(1);
3374 levelSetValues = a[0] + delta_taylor[0][0];
3375 } else {
3376 // in both directions
3377 // 1.Order
3378 MFloat p, q;
3379 if(abs(delta_cell[0] - delta_cell[1]) < eps) { // same distance to both cells
3380 // pq-equation
3381 delta_taylor[0][0] = (delta_cell[0] + c_cellLengthAtLevel(a_level(cellId))) * FFPOW2(1);
3382 p = -(a[0] + a[1]);
3383 q = (a[0] * a[0] + a[1] * a[1] - delta_taylor[0][0] * delta_taylor[0][0]) * FFPOW2(1);
3384 } else {
3385 delta_taylor[0][0] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[0]) * FFPOW2(1);
3386 delta_taylor[0][1] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[1]) * FFPOW2(1);
3387 p = -2 * (delta_taylor[0][1] * delta_taylor[0][1] * a[0] + delta_taylor[0][0] * delta_taylor[0][0] * a[1])
3388 / (delta_taylor[0][0] * delta_taylor[0][0] + delta_taylor[0][1] * delta_taylor[0][1]);
3389 q = (delta_taylor[0][1] * delta_taylor[0][1] * a[0] * a[0]
3390 + delta_taylor[0][0] * delta_taylor[0][0] * a[1] * a[1]
3391 - delta_taylor[0][1] * delta_taylor[0][1] * delta_taylor[0][0] * delta_taylor[0][0])
3392 / (delta_taylor[0][1] * delta_taylor[0][1] + delta_taylor[0][0] * delta_taylor[0][0]);
3393 }
3394 MFloat psqf4mq = p * p * FFPOW2(2) - q;
3395 if(psqf4mq < F0) psqf4mq = F0;
3396 levelSetValues = -p * FFPOW2(1) + sqrt(psqf4mq);
3397 }
3398 }
3399 else IF_CONSTEXPR(nDim == 3) {
3400 // 3D CalculateLSV by approximation with taylor
3401 if(!(a[0] > F0) && !(a[1] > F0) && !(a[2] > F0)) { // no valid neighbor
3402 } else if(!(a[1] > F0) && !(a[2] > F0)) {
3403 // only in x-Direction
3404 delta_taylor[0][0] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[0]) * FFPOW2(1);
3405 levelSetValues = a[0] + delta_taylor[0][0];
3406 } else if(!(a[0] > F0) && !(a[2] > F0)) {
3407 // only in y-Direction
3408 delta_taylor[0][1] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[1]) * FFPOW2(1);
3409 levelSetValues = a[1] + delta_taylor[0][1];
3410 } else if(!(a[0] > F0) && !(a[1] > F0)) {
3411 // only in z-Direction
3412 delta_taylor[0][2] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[2]) * FFPOW2(1);
3413 levelSetValues = a[2] + delta_taylor[0][2];
3414 } else if(!(a[2] > F0)) {
3415 // in x- and y-Direction
3416 MFloat p, q;
3417 if(abs(delta_cell[0] - delta_cell[1]) < eps) { // same distance to both cells
3418 // pq-equation
3419 delta_taylor[0][0] = (delta_cell[0] + c_cellLengthAtLevel(a_level(cellId))) * FFPOW2(1);
3420 p = -(a[0] + a[1]);
3421 q = (a[0] * a[0] + a[1] * a[1] - delta_taylor[0][0] * delta_taylor[0][0]) * FFPOW2(1);
3422 } else {
3423 delta_taylor[0][0] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[0]) * FFPOW2(1);
3424 delta_taylor[0][1] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[1]) * FFPOW2(1);
3425 MFloat x2 = delta_taylor[0][0] * delta_taylor[0][0];
3426 MFloat y2 = delta_taylor[0][1] * delta_taylor[0][1];
3427 MFloat denominator = x2 + y2;
3428 MFloat x2y2 = x2 * y2;
3429 p = -2 * (a[0] * y2 + a[1] * x2) / denominator;
3430 q = (a[0] * a[0] * y2 + a[1] * a[1] * x2 - x2y2) / denominator;
3431 }
3432 MFloat psqf4mq = p * p * FFPOW2(2) - q;
3433 if(psqf4mq < F0) psqf4mq = F0;
3434 levelSetValues = -p * FFPOW2(1) + sqrt(psqf4mq);
3435 } else if(!(a[1] > F0)) {
3436 // in x- and z-Direction
3437 MFloat p, q;
3438 if(abs(delta_cell[0] - delta_cell[2]) < eps) { // same distance to both cells
3439 // pq-equation
3440 delta_taylor[0][0] = (delta_cell[0] + c_cellLengthAtLevel(a_level(cellId))) * FFPOW2(1);
3441 p = -(a[0] + a[2]);
3442 q = (a[0] * a[0] + a[2] * a[2] - delta_taylor[0][0] * delta_taylor[0][0]) * FFPOW2(1);
3443 } else {
3444 delta_taylor[0][0] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[0]) * FFPOW2(1);
3445 delta_taylor[0][2] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[2]) * FFPOW2(1);
3446 MFloat x2 = delta_taylor[0][0] * delta_taylor[0][0];
3447 MFloat z2 = delta_taylor[0][2] * delta_taylor[0][2];
3448 MFloat denominator = x2 + z2;
3449 MFloat x2z2 = x2 * z2;
3450 p = -2 * (a[0] * z2 + a[2] * x2) / denominator;
3451 q = (a[0] * a[0] * z2 + a[2] * a[2] * x2 - x2z2) / denominator;
3452 }
3453 MFloat psqf4mq = p * p * FFPOW2(2) - q;
3454 if(psqf4mq < F0) psqf4mq = F0;
3455 levelSetValues = -p * FFPOW2(1) + sqrt(psqf4mq);
3456 } else if(!(a[0] > F0)) {
3457 // in y- and z-Direction
3458 MFloat p, q;
3459 if(abs(delta_cell[1] - delta_cell[2]) < eps) { // same distance to both cells
3460 // pq-equation
3461 delta_taylor[0][0] = (delta_cell[1] + c_cellLengthAtLevel(a_level(cellId))) * FFPOW2(1);
3462 p = -(a[1] + a[2]);
3463 q = (a[1] * a[1] + a[2] * a[2] - delta_taylor[0][0] * delta_taylor[0][0]) * FFPOW2(1);
3464 } else {
3465 delta_taylor[0][1] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[1]) * FFPOW2(1);
3466 delta_taylor[0][2] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[2]) * FFPOW2(1);
3467 MFloat y2 = delta_taylor[0][1] * delta_taylor[0][1];
3468 MFloat z2 = delta_taylor[0][2] * delta_taylor[0][2];
3469 MFloat denominator = z2 + y2;
3470 MFloat z2y2 = z2 * y2;
3471 p = -2 * (a[1] * z2 + a[2] * y2) / denominator;
3472 q = (a[1] * a[1] * z2 + a[2] * a[2] * y2 - z2y2) / denominator;
3473 }
3474 MFloat psqf4mq = p * p * FFPOW2(2) - q;
3475 if(psqf4mq < F0) psqf4mq = F0;
3476 levelSetValues = -p * FFPOW2(1) + sqrt(psqf4mq);
3477 } else {
3478 // in all three directions
3479 MFloat p, q;
3480 if(abs(delta_cell[0] - delta_cell[2]) < eps
3481 && abs(delta_cell[1] - delta_cell[2]) < eps) { // same distance to all three cells
3482 // pq-equation
3483 delta_taylor[0][0] = (delta_cell[0] + c_cellLengthAtLevel(a_level(cellId))) * FFPOW2(1);
3484 p = -F2B3 * (a[0] + a[1] + a[2]);
3485 q = F1B3 * (a[0] * a[0] + a[1] * a[1] + a[2] * a[2] - delta_taylor[0][0] * delta_taylor[0][0]);
3486 } else { // different distances in at least one direction
3487 delta_taylor[0][0] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[0]) * FFPOW2(1);
3488 delta_taylor[0][1] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[1]) * FFPOW2(1);
3489 delta_taylor[0][2] = (c_cellLengthAtLevel(a_level(cellId)) + delta_cell[2]) * FFPOW2(1);
3490 MFloat x2y2 = delta_taylor[0][0] * delta_taylor[0][0] * delta_taylor[0][1] * delta_taylor[0][1];
3491 MFloat x2z2 = delta_taylor[0][0] * delta_taylor[0][0] * delta_taylor[0][2] * delta_taylor[0][2];
3492 MFloat y2z2 = delta_taylor[0][1] * delta_taylor[0][1] * delta_taylor[0][2] * delta_taylor[0][2];
3493 MFloat x2y2z2 = delta_taylor[0][0] * delta_taylor[0][0] * delta_taylor[0][1] * delta_taylor[0][1]
3494 * delta_taylor[0][2] * delta_taylor[0][2];
3495 MFloat denominator = (x2y2 + x2z2 + y2z2);
3496 p = -2 * (y2z2 * a[0] + x2z2 * a[1] + x2y2 * a[2]) / denominator;
3497 q = (y2z2 * a[0] * a[0] + x2z2 * a[1] * a[1] + x2y2 * a[2] * a[2] - x2y2z2) / denominator;
3498 }
3499 MFloat psqf4mq = p * p * FFPOW2(2) - q;
3500 if(psqf4mq < F0) psqf4mq = F0;
3501 levelSetValues = -p * FFPOW2(1) + sqrt(psqf4mq);
3502 }
3503 }
3504
3505 return levelSetValues;
3506}
3507
3508
3513template <MInt nDim, class SysEqn>
3515 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
3516
3517 MFloat dist = fabs(coordinates[0] - m_bodyCenter[bodyId * nDim]) - m_bodyRadius[bodyId];
3518
3519 return dist;
3520}
3521
3522
3527template <MInt nDim, class SysEqn>
3529 return getDistancePiston(&a_coordinate(cellId, 0), bodyId);
3530}
3531
3532
3537template <MInt nDim, class SysEqn>
3539 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
3540 if(bodyId != 0) mTerm(1, AT_, "Extend Naca00XX.");
3541
3542 const MFloat phi0 = getLevelSetValueNaca00XX(&a_coordinate(cellId, 0), -F1);
3543 const MFloat phi1 = getLevelSetValueNaca00XX(&a_coordinate(cellId, 0), F1);
3544 const MFloat phi = (fabs(phi0) < fabs(phi1)) ? phi0 : phi1;
3545
3546 return phi;
3547}
3548
3549
3554template <MInt nDim, class SysEqn>
3556 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
3557
3558 MFloatScratchSpace R(3, 3, AT_, "R");
3559 MFloat xw[3];
3560 MFloat xb[3];
3561
3562 computeRotationMatrix(R, &(m_bodyQuaternion[4 * bodyId]));
3563
3564 MFloat x = coordinates[0] - m_bodyCenter[bodyId * nDim + 0];
3565 MFloat y = coordinates[1] - m_bodyCenter[bodyId * nDim + 1];
3566 MFloat z = coordinates[2] - m_bodyCenter[bodyId * nDim + 2];
3567
3568 xw[0] = x;
3569 xw[1] = y;
3570 xw[2] = z;
3571 matrixVectorProduct(xb, R, xw);
3572 x = xb[0];
3573 y = xb[1];
3574 z = xb[2];
3575
3576 const MFloat a = m_bodyRadii[bodyId * nDim + 0];
3577 const MFloat b = m_bodyRadii[bodyId * nDim + 1];
3578 const MFloat c = m_bodyRadii[bodyId * nDim + 2];
3579
3580 MFloat ee[3] = {a, b, c};
3581 MFloat yy[3] = {x, y, z};
3582 MFloat xx[3] = {F0, F0, F0};
3583 MFloat dist = distancePointEllipsoid(ee, yy, xx);
3584 if((POW2(x / a) + POW2(y / b) + POW2(z / c)) < F1) dist = -dist;
3585
3586 return dist;
3587}
3588
3589
3594template <MInt nDim, class SysEqn>
3596 return getDistanceEllipsoid(&a_coordinate(cellId, 0), bodyId);
3597}
3598
3599
3604template <MInt nDim, class SysEqn>
3606 MFloat* xc1) {
3607 MFloatScratchSpace R0(3, 3, AT_, "R0");
3608 MFloatScratchSpace R1(3, 3, AT_, "R1");
3609 MFloat xw[3];
3610 MFloat xb[3];
3611
3612 computeRotationMatrix(R0, &(m_bodyQuaternion[4 * k0]));
3613 computeRotationMatrix(R1, &(m_bodyQuaternion[4 * k1]));
3614
3615 for(MInt i = 0; i < nDim; i++)
3616 xc0[i] = m_bodyCenter[k0 * nDim + i];
3617 for(MInt i = 0; i < nDim; i++)
3618 xc1[i] = m_bodyCenter[k1 * nDim + i];
3619
3620 MFloat x = xc1[0] - xc0[0];
3621 MFloat y = xc1[1] - xc0[1];
3622 MFloat z = xc1[2] - xc0[2];
3623
3624 MFloat* xc = xc1;
3625 MFloat* xc_next = xc0;
3626
3627 MFloat dist0 = 9999998.0;
3628 MFloat dist = sqrt(x * x + y * y + z * z);
3629 MInt iter = 0;
3630 MInt id = -1;
3631 const MInt maxIter = 200;
3632 const MFloat eps = 1e-3 * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
3633 while(fabs(dist0 - dist) > eps && iter < maxIter) {
3634 id = (iter % 2 == 0) ? k0 : k1;
3635 xc = (iter % 2 == 0) ? xc1 : xc0;
3636 xc_next = (iter % 2 == 0) ? xc0 : xc1;
3637
3638 x = xc[0] - m_bodyCenter[id * nDim + 0];
3639 y = xc[1] - m_bodyCenter[id * nDim + 1];
3640 z = xc[2] - m_bodyCenter[id * nDim + 2];
3641
3642 xw[0] = x;
3643 xw[1] = y;
3644 xw[2] = z;
3645 if(iter % 2 == 0)
3646 matrixVectorProduct(xb, R0, xw);
3647 else
3648 matrixVectorProduct(xb, R1, xw);
3649 x = xb[0];
3650 y = xb[1];
3651 z = xb[2];
3652
3653 MFloat a = m_bodyRadii[id * nDim + 0];
3654 MFloat b = m_bodyRadii[id * nDim + 1];
3655 MFloat c = m_bodyRadii[id * nDim + 2];
3656
3657 MFloat ee[3] = {a, b, c};
3658 MFloat yy[3] = {x, y, z};
3659 MFloat xx[3] = {F0, F0, F0};
3660
3661 dist0 = dist;
3662 dist = distancePointEllipsoid(ee, yy, xx);
3663 if((POW2(x / a) + POW2(y / b) + POW2(z / c)) < F1) dist = -dist;
3664
3665 xb[0] = xx[0];
3666 xb[1] = xx[1];
3667 xb[2] = xx[2];
3668 if(iter % 2 == 0)
3669 matrixVectorProductTranspose(xw, R0, xb);
3670 else
3671 matrixVectorProductTranspose(xw, R1, xb);
3672
3673 xc_next[0] = xw[0] + m_bodyCenter[id * nDim + 0];
3674 xc_next[1] = xw[1] + m_bodyCenter[id * nDim + 1];
3675 xc_next[2] = xw[2] + m_bodyCenter[id * nDim + 2];
3676
3677 iter++;
3678 }
3679 if(iter >= maxIter && domainId() == 0)
3680 cerr << setprecision(12) << domainId() << ": ellipsoid dist did not converge " << k0 << " " << k1 << " / "
3681 << dist - dist0 << " " << dist << " " << dist0 << " " << iter << " " << endl;
3682
3683 return dist;
3684}
3685
3686
3687// The ellipsoid is (x0/e0)^2 + (x1/e1)^2 + (x2/e2)^2 = 1 with e0 >= e1 >= e2.
3688// The query point is (y0,y1,y2) with y0 >= 0, y1 >= 0, and y2 >= 0. The
3689// function returns the distance from the query point to the ellipsoid. It
3690// also computes the ellipsoid point (x0,x1,x2) in the first octant that is
3691// closest to (y0,y1,y2).
3692// author: David Eberly, Geometric Tools, LLC
3693// http://www.geometrictools.com/
3694template <MInt nDim, class SysEqn>
3696 MFloat x[3]) {
3697 constexpr MFloat eps = 1e-14;
3698 MFloat distance;
3699
3700 if(y[2] > (MFloat)0) {
3701 if(y[1] > (MFloat)0) {
3702 if(y[0] > (MFloat)0) {
3703 // Bisect to compute the root of F(t) for t >= -e2*e2.
3704 MFloat esqr[3] = {e[0] * e[0], e[1] * e[1], e[2] * e[2]};
3705 MFloat ey[3] = {e[0] * y[0], e[1] * y[1], e[2] * y[2]};
3706 MFloat t0 = -esqr[2] + ey[2];
3707 MFloat t1 = -esqr[2] + sqrt(ey[0] * ey[0] + ey[1] * ey[1] + ey[2] * ey[2]);
3708 MFloat t = t0;
3709 const MInt imax = 2 * std::numeric_limits<MFloat>::max_exponent;
3710 for(MInt i = 0; i < imax; ++i) {
3711 t = ((MFloat)0.5) * (t0 + t1);
3712 if(fabs(t - t0) < eps || fabs(t - t1) < eps) {
3713 break;
3714 }
3715 MFloat r[3] = {ey[0] / (t + esqr[0]), ey[1] / (t + esqr[1]), ey[2] / (t + esqr[2])};
3716 MFloat f = r[0] * r[0] + r[1] * r[1] + r[2] * r[2] - (MFloat)1;
3717 if(f > (MFloat)0) {
3718 t0 = t;
3719 } else if(f < (MFloat)0) {
3720 t1 = t;
3721 } else {
3722 break;
3723 }
3724 }
3725 // if ( fabs( t0 - t1 ) > eps ) cerr << "ellipsoid dist not converged!" << endl;
3726 x[0] = esqr[0] * y[0] / (t + esqr[0]);
3727 x[1] = esqr[1] * y[1] / (t + esqr[1]);
3728 x[2] = esqr[2] * y[2] / (t + esqr[2]);
3729 MFloat d[3] = {x[0] - y[0], x[1] - y[1], x[2] - y[2]};
3730 distance = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
3731 } else // y0 == 0
3732 {
3733 x[0] = (MFloat)0;
3734 MFloat etmp[2] = {e[1], e[2]};
3735 MFloat ytmp[2] = {y[1], y[2]};
3736 MFloat xtmp[2];
3737 distance = distancePointEllipseSpecial(etmp, ytmp, xtmp);
3738 x[1] = xtmp[0];
3739 x[2] = xtmp[1];
3740 }
3741 } else // y1 == 0
3742 {
3743 x[1] = (MFloat)0;
3744 if(y[0] > (MFloat)0) {
3745 MFloat etmp[2] = {e[0], e[2]};
3746 MFloat ytmp[2] = {y[0], y[2]};
3747 MFloat xtmp[2];
3748 distance = distancePointEllipseSpecial(etmp, ytmp, xtmp);
3749 x[0] = xtmp[0];
3750 x[2] = xtmp[1];
3751 } else // y0 == 0
3752 {
3753 x[0] = (MFloat)0;
3754 x[2] = e[2];
3755 distance = fabs(y[2] - e[2]);
3756 }
3757 }
3758 } else // y2 == 0
3759 {
3760 MFloat denom[2] = {e[0] * e[0] - e[2] * e[2], e[1] * e[1] - e[2] * e[2]};
3761 MFloat ey[2] = {e[0] * y[0], e[1] * y[1]};
3762 if(ey[0] < denom[0] && ey[1] < denom[1]) {
3763 // (y0,y1) is inside the axis-aligned bounding rectangle of the
3764 // subellipse. This intermediate test is designed to guard
3765 // against the division by zero when e0 == e2 or e1 == e2.
3766 MFloat xde[2] = {ey[0] / denom[0], ey[1] / denom[1]};
3767 MFloat xdesqr[2] = {xde[0] * xde[0], xde[1] * xde[1]};
3768 MFloat discr = (MFloat)1 - xdesqr[0] - xdesqr[1];
3769 if(discr > (MFloat)0) {
3770 // (y0,y1) is inside the subellipse. The closest ellipsoid
3771 // point has x2 > 0.
3772 x[0] = e[0] * xde[0];
3773 x[1] = e[1] * xde[1];
3774 x[2] = e[2] * sqrt(discr);
3775 MFloat d[2] = {x[0] - y[0], x[1] - y[1]};
3776 distance = sqrt(d[0] * d[0] + d[1] * d[1] + x[2] * x[2]);
3777 } else {
3778 // (y0,y1) is outside the subellipse. The closest ellipsoid
3779 // point has x2 == 0 and is on the domain-boundary ellipse
3780 // (x0/e0)^2 + (x1/e1)^2 = 1.
3781 x[2] = (MFloat)0;
3782 distance = distancePointEllipseSpecial(e, y, x);
3783 }
3784 } else {
3785 // (y0,y1) is outside the subellipse. The closest ellipsoid
3786 // point has x2 == 0 and is on the domain-boundary ellipse
3787 // (x0/e0)^2 + (x1/e1)^2 = 1.
3788 x[2] = (MFloat)0;
3789 distance = distancePointEllipseSpecial(e, y, x);
3790 }
3791 }
3792 return distance;
3793}
3794
3795
3796// The ellipsoid is (x0/e0)^2 + (x1/e1)^2 + (x2/e2)^2 = 1 with e0 >= e1 >= e2.
3797// The query point is (y0,y1,y2) with y0 >= 0, y1 >= 0, and y2 >= 0. The
3798// function returns the distance from the query point to the ellipsoid. It
3799// also computes the ellipsoid point (x0,x1,x2) in the first octant that is
3800// closest to (y0,y1,y2).
3801// author: David Eberly, Geometric Tools, LLC
3802// http://www.geometrictools.com/
3803// note: variant of distancePointEllipsoidSpecial(...) assuming y>0 and using dynamic eps to improve performance,
3804// Lennart
3805// Performance optimizations: division elimination, loop unrolling
3806
3807template <MInt nDim, class SysEqn>
3809 MFloat x[3]) {
3810 constexpr MFloat eps0 = 1e-12;
3811 constexpr MFloat eps1 = 1e-6;
3812 const MFloat dist0 = c_cellLengthAtLevel(m_lsCutCellBaseLevel);
3813 const MFloat dist1 = m_maxBndryLayerWidth * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
3814 MFloat distance;
3815 // Bisect to compute the root of F(t) for t >= -e2*e2.
3816 MFloat esqr[3] = {e[0] * e[0], e[1] * e[1], e[2] * e[2]};
3817 MFloat ey[3] = {e[0] * y[0], e[1] * y[1], e[2] * y[2]};
3818 MFloat t0 = -esqr[2] + ey[2];
3819 MFloat t1 = -esqr[2] + sqrt(ey[0] * ey[0] + ey[1] * ey[1] + ey[2] * ey[2]);
3820 MFloat t;
3821 const MInt imax = 2 * std::numeric_limits<MFloat>::max_exponent;
3822 MFloat eps = eps1;
3823 if(fabs(t1 - t0) < eps) t1 = t0 + F2 * eps;
3824 t = F1B2 * (t0 + t1);
3825 MInt i = 0;
3826 distance = c_cellLengthAtLevel(0);
3827
3828 while(fabs(t1 - t0) > eps && i < imax) {
3829 // loop unrolling
3830 while ( i < imax ) {
3831 i++;
3832 t = F1B2 * (t0 + t1);
3833 MFloat f0 = (t + esqr[0]) * (t + esqr[0]);
3834 MFloat f1 = (t + esqr[1]) * (t + esqr[1]);
3835 MFloat f2 = (t + esqr[2]) * (t + esqr[2]);
3836 MFloat fs = f0 * f1 * f2;
3837 // avoid division
3838 MFloat f = ey[0] * ey[0] * f1 * f2 + ey[1] * ey[1] * f0 * f2 + ey[2] * ey[2] * f0 * f1;
3839 if(f > fs) {
3840 t0 = t;
3841 } else {
3842 t1 = t;
3843 }
3844 if( fabs(t1 - t0) < eps || i >= imax ) break;
3845
3846 i++;
3847 t = F1B2 * (t0 + t1);
3848 f0 = (t + esqr[0])*(t + esqr[0]);
3849 f1 = (t + esqr[1])*(t + esqr[1]);
3850 f2 = (t + esqr[2])*(t + esqr[2]);
3851 fs = f0*f1*f2;
3852 f = ey[0] * ey[0] * f1 * f2 + ey[1] * ey[1] * f0 * f2 + ey[2] * ey[2] * f0 * f1;
3853 if(f > fs) {
3854 t0 = t;
3855 } else {
3856 t1 = t;
3857 }
3858 if(fabs(t1 - t0) < eps || i >= imax) break;
3859
3860 i++;
3861 t = F1B2 * (t0 + t1);
3862 f0 = (t + esqr[0])*(t + esqr[0]);
3863 f1 = (t + esqr[1])*(t + esqr[1]);
3864 f2 = (t + esqr[2])*(t + esqr[2]);
3865 fs = f0 * f1 * f2;
3866 f = ey[0] * ey[0] * f1 * f2 + ey[1] * ey[1] * f0 * f2 + ey[2] * ey[2] * f0 * f1;
3867 if(f > fs) {
3868 t0 = t;
3869 } else {
3870 t1 = t;
3871 }
3872 if(fabs(t1 - t0) < eps || i >= imax) break;
3873
3874 i++;
3875 t = F1B2 * (t0 + t1);
3876 f0 = (t + esqr[0])*(t + esqr[0]);
3877 f1 = (t + esqr[1])*(t + esqr[1]);
3878 f2 = (t + esqr[2])*(t + esqr[2]);
3879 fs = f0*f1*f2;
3880 f = ey[0] * ey[0] * f1 * f2 + ey[1] * ey[1] * f0 * f2 + ey[2] * ey[2] * f0 * f1;
3881 if(f > fs) {
3882 t0 = t;
3883 } else {
3884 t1 = t;
3885 }
3886 if(fabs(t1 - t0) < eps || i >= imax) break;
3887 }
3888 x[0] = esqr[0] * y[0] / (t + esqr[0]);
3889 x[1] = esqr[1] * y[1] / (t + esqr[1]);
3890 x[2] = esqr[2] * y[2] / (t + esqr[2]);
3891 distance = sqrt(POW2(x[0] - y[0]) + POW2(x[1] - y[1]) + POW2(x[2] - y[2]));
3892 // adjust eps: small close to surface, larger further away from surface
3893 eps = eps0 + mMin(F1, mMax(F0, (distance - dist0) / (dist1 - dist0))) * (eps1 - eps0);
3894 }
3895 if(fabs(t0 - t1) > eps) cerr << setprecision(16) << "ellipsoid dist not converged! " << i << " " << t1 - t0 << endl;
3896 return distance;
3897}
3898
3899
3900// The ellipsoid is (x0/e0)^2 + (x1/e1)^2 + (x2/e2)^2 = 1. The query point is
3901// (y0,y1,y2). The function returns the distance from the query point to the
3902// ellipsoid. It also computes the ellipsoid point (x0,x1,x2) that is
3903// closest to (y0,y1,y2).
3904// author: David Eberly, Geometric Tools, LLC
3905// http://www.geometrictools.com/
3906template <MInt nDim, class SysEqn>
3908 // Determine reflections for y to the first octant.
3909 MBool reflect[3];
3910 MInt i, j;
3911 for(i = 0; i < 3; ++i) {
3912 reflect[i] = (y[i] < (MFloat)0);
3913 }
3914
3915 // Determine the axis order for decreasing extents.
3916 MInt permute[3];
3917 if(e[0] < e[1]) {
3918 if(e[2] < e[0]) {
3919 permute[0] = 1;
3920 permute[1] = 0;
3921 permute[2] = 2;
3922 } else if(e[2] < e[1]) {
3923 permute[0] = 1;
3924 permute[1] = 2;
3925 permute[2] = 0;
3926 } else {
3927 permute[0] = 2;
3928 permute[1] = 1;
3929 permute[2] = 0;
3930 }
3931 } else {
3932 if(e[2] < e[1]) {
3933 permute[0] = 0;
3934 permute[1] = 1;
3935 permute[2] = 2;
3936 } else if(e[2] < e[0]) {
3937 permute[0] = 0;
3938 permute[1] = 2;
3939 permute[2] = 1;
3940 } else {
3941 permute[0] = 2;
3942 permute[1] = 0;
3943 permute[2] = 1;
3944 }
3945 }
3946 MInt invpermute[3];
3947 for(i = 0; i < 3; ++i) {
3948 invpermute[permute[i]] = i;
3949 }
3950 MFloat locE[3], locY[3];
3951 for(i = 0; i < 3; ++i) {
3952 j = permute[i];
3953 locE[i] = e[j];
3954 locY[i] = y[j];
3955 if(reflect[j]) {
3956 locY[i] = -locY[i];
3957 }
3958 }
3959 MFloat locX[3];
3960#define IMPROVEDDISTELLIPSOID
3961#ifdef IMPROVEDDISTELLIPSOID
3962 for(i = 0; i < 3; ++i) {
3963 ASSERT(!(locY[i] < F0), "");
3964 locY[i] = mMax(1e-15, locY[i]); // guarantee non-zero entries
3965 }
3966 MFloat distance = distancePointEllipsoidSpecial2(locE, locY, locX);
3967#else
3968 MFloat distance = distancePointEllipsoidSpecial(locE, locY, locX);
3969#endif
3970 // Restore the axis order and reflections.
3971 for(i = 0; i < 3; ++i) {
3972 j = invpermute[i];
3973 if(reflect[i]) {
3974 locX[j] = -locX[j];
3975 }
3976 x[i] = locX[j];
3977 }
3978 return distance;
3979}
3980
3981
3982// The ellipse is (x0/e0)^2 + (x1/e1)^2 = 1 with e0 >= e1. The query point is
3983// (y0,y1) with y0 >= 0 and y1 >= 0. The function returns the distance from
3984// the query point to the ellipse. It also computes the ellipse point (x0,x1)
3985// in the first quadrant that is closest to (y0,y1).
3986// author: David Eberly, Geometric Tools, LLC
3987// http://www.geometrictools.com/
3988template <MInt nDim, class SysEqn>
3990 MFloat x[2]) {
3991 constexpr MFloat eps = 1e-14;
3992 MFloat distance;
3993
3994 if(y[1] > (MFloat)0) {
3995 if(y[0] > (MFloat)0) {
3996 // Bisect to compute the root of F(t) for t >= -e1*e1.
3997 MFloat esqr[2] = {e[0] * e[0], e[1] * e[1]};
3998 MFloat ey[2] = {e[0] * y[0], e[1] * y[1]};
3999 MFloat t0 = -esqr[1] + ey[1];
4000 MFloat t1 = -esqr[1] + sqrt(ey[0] * ey[0] + ey[1] * ey[1]);
4001 MFloat t = t0;
4002 const MInt imax = 2 * std::numeric_limits<MFloat>::max_exponent;
4003 for(MInt i = 0; i < imax; ++i) {
4004 t = ((MFloat)0.5) * (t0 + t1);
4005 if(fabs(t - t0) < eps || fabs(t - t1) < eps) {
4006 break;
4007 }
4008 MFloat r[2] = {ey[0] / (t + esqr[0]), ey[1] / (t + esqr[1])};
4009 MFloat f = r[0] * r[0] + r[1] * r[1] - (MFloat)1;
4010 if(f > (MFloat)0) {
4011 t0 = t;
4012 } else if(f < (MFloat)0) {
4013 t1 = t;
4014 } else {
4015 break;
4016 }
4017 }
4018 if(fabs(t0 - t1) > eps) cerr << "ellipse dist not converged!" << endl;
4019 x[0] = esqr[0] * y[0] / (t + esqr[0]);
4020 x[1] = esqr[1] * y[1] / (t + esqr[1]);
4021 MFloat d[2] = {x[0] - y[0], x[1] - y[1]};
4022 distance = sqrt(d[0] * d[0] + d[1] * d[1]);
4023 } else // y0 == 0
4024 {
4025 x[0] = (MFloat)0;
4026 x[1] = e[1];
4027 distance = fabs(y[1] - e[1]);
4028 }
4029 } else // y1 == 0
4030 {
4031 MFloat denom0 = e[0] * e[0] - e[1] * e[1];
4032 MFloat e0y0 = e[0] * y[0];
4033 if(e0y0 < denom0) {
4034 // y0 is inside the subinterval.
4035 MFloat x0de0 = e0y0 / denom0;
4036 MFloat x0de0sqr = x0de0 * x0de0;
4037 x[0] = e[0] * x0de0;
4038 x[1] = e[1] * sqrt(fabs((MFloat)1 - x0de0sqr));
4039 MFloat d0 = x[0] - y[0];
4040 distance = sqrt(d0 * d0 + x[1] * x[1]);
4041 } else {
4042 // y0 is outside the subinterval. The closest ellipse point has
4043 // x1 == 0 and is on the domain-boundary interval (x0/e0)^2 = 1.
4044 x[0] = e[0];
4045 x[1] = (MFloat)0;
4046 distance = fabs(y[0] - e[0]);
4047 }
4048 }
4049 return distance;
4050}
4051
4052
4057template <MInt nDim, class SysEqn>
4059 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
4060
4061 constexpr MFloat eps = 5e-3;
4062 const MFloat fac0 = F1 / sqrt(F3);
4063 const MFloat fac1 = F1B6 * pow(PI / F2, F1B3);
4064 const MFloat fac = fac1 * m_bodyDiameter[bodyId];
4065 constexpr MFloat dirs[4][3] = {{F1, F1, -F1}, {F1, -F1, F1}, {-F1, F1, F1}, {-F1, -F1, -F1}};
4066
4067 MFloat innerDist = std::numeric_limits<MFloat>::lowest();
4068 MFloat outerDist = F0;
4069
4070 MFloatScratchSpace R(3, 3, AT_, "R");
4071 MFloat xw[3];
4072 MFloat xb[3];
4073 computeRotationMatrix(R, &(m_bodyQuaternion[4 * bodyId]));
4074 MFloat x = coordinates[0] - m_bodyCenter[bodyId * nDim + 0];
4075 MFloat y = coordinates[1] - m_bodyCenter[bodyId * nDim + 1];
4076 MFloat z = F0;
4077 IF_CONSTEXPR(nDim == 3) { z = coordinates[2] - m_bodyCenter[bodyId * nDim + 2]; }
4078 xw[0] = x;
4079 xw[1] = y;
4080 IF_CONSTEXPR(nDim == 3) { xw[2] = z; }
4081 matrixVectorProduct(xb, R, xw);
4082 x = xb[0];
4083 y = xb[1];
4084 IF_CONSTEXPR(nDim == 3) { z = xb[2]; }
4085
4086 MFloat dists[4];
4087
4088 for(MInt face = 0; face < 4; face++) {
4089 MFloat dist = F0;
4090 IF_CONSTEXPR(nDim == 2) {
4091 dist = dirs[face][0] * fac0 * (x - fac * dirs[face][0]) + dirs[face][1] * fac0 * (y - fac * dirs[face][1]);
4092 }
4093 else IF_CONSTEXPR(nDim == 3) {
4094 dist = dirs[face][0] * fac0 * (x - fac * dirs[face][0]) + dirs[face][1] * fac0 * (y - fac * dirs[face][1])
4095 + dirs[face][2] * fac0 * (z - fac * dirs[face][2]);
4096 }
4097 innerDist = mMax(innerDist, dist);
4098 outerDist += POW2(mMax(F0, dist));
4099
4100 dists[face] = dist;
4101 }
4102 std::sort(dists, dists + 4, [](const MFloat& a, const MFloat& b) { return fabs(a) < fabs(b); });
4103
4104 if(innerDist < F0) {
4105 if(fabs(dists[1]) < eps * m_bodyDiameter[bodyId]) {
4106 innerDist = F0;
4107 for(MInt face = 0; face < 4; face++) {
4108 if(fabs(dists[face]) < eps * m_bodyDiameter[bodyId]) {
4109 innerDist = -sqrt(POW2(innerDist) + POW2(dists[face]));
4110 }
4111 }
4112 }
4113 } else {
4114 if(fabs(dists[1]) < eps * m_bodyDiameter[bodyId]) {
4115 outerDist = F0;
4116 for(MInt face = 0; face < 4; face++) {
4117 if(fabs(dists[face]) < eps * m_bodyDiameter[bodyId]) {
4118 outerDist += POW2(dists[face]);
4119 }
4120 }
4121 }
4122 }
4123
4124 return (innerDist < F0) ? innerDist : sqrt(outerDist);
4125}
4126
4127
4132template <MInt nDim, class SysEqn>
4134 R(0, 0) = q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3];
4135 R(1, 1) = q[0] * q[0] - q[1] * q[1] + q[2] * q[2] - q[3] * q[3];
4136 R(2, 2) = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
4137
4138 R(0, 1) = F2 * (q[1] * q[2] + q[0] * q[3]);
4139 R(0, 2) = F2 * (q[1] * q[3] - q[0] * q[2]);
4140 R(1, 0) = F2 * (q[1] * q[2] - q[0] * q[3]);
4141 R(1, 2) = F2 * (q[2] * q[3] + q[0] * q[1]);
4142 R(2, 0) = F2 * (q[1] * q[3] + q[0] * q[2]);
4143 R(2, 1) = F2 * (q[2] * q[3] - q[0] * q[1]);
4144}
4145
4146
4151template <MInt nDim, class SysEqn>
4153 MFloatScratchSpace& B) {
4154 ASSERT(A.size1() == B.size0(), "");
4155 C.fill(F0);
4156 for(MInt i = 0; i < C.size0(); i++) {
4157 for(MInt k = 0; k < C.size1(); k++) {
4158 for(MInt j = 0; j < A.size1(); j++) {
4159 C(i, k) += A(i, j) * B(j, k);
4160 }
4161 }
4162 }
4163}
4164
4165
4170template <MInt nDim, class SysEqn>
4172 MFloatScratchSpace& B) {
4173 ASSERT(A.size1() == B.size1(), "");
4174 C.fill(F0);
4175 for(MInt i = 0; i < C.size0(); i++) {
4176 for(MInt k = 0; k < C.size1(); k++) {
4177 for(MInt j = 0; j < A.size1(); j++) {
4178 C(i, k) += A(i, j) * B(k, j);
4179 }
4180 }
4181 }
4182}
4183
4184
4189template <MInt nDim, class SysEqn>
4191 MFloatScratchSpace& B) {
4192 ASSERT(A.size0() == B.size0(), "");
4193 C.fill(F0);
4194 for(MInt i = 0; i < C.size0(); i++) {
4195 for(MInt k = 0; k < C.size1(); k++) {
4196 for(MInt j = 0; j < A.size0(); j++) {
4197 C(i, k) += A(j, i) * B(j, k);
4198 }
4199 }
4200 }
4201}
4202
4203
4208template <MInt nDim, class SysEqn>
4210 for(MInt i = 0; i < A.size0(); i++) {
4211 c[i] = F0;
4212 for(MInt j = 0; j < A.size1(); j++) {
4213 c[i] += A(i, j) * b[j];
4214 }
4215 }
4216}
4217
4218
4223template <MInt nDim, class SysEqn>
4225 MFloat* b) {
4226 for(MInt i = 0; i < A.size1(); i++) {
4227 c[i] = F0;
4228 for(MInt j = 0; j < A.size0(); j++) {
4229 c[i] += A(j, i) * b[j];
4230 }
4231 }
4232}
4233
4234
4239template <MInt nDim, class SysEqn>
4241 if(m_fixedBodyComponentsRotation[0] && m_fixedBodyComponentsRotation[1] && m_fixedBodyComponentsRotation[2]) return;
4242
4243 MFloatScratchSpace R0(3, 3, AT_, "R0");
4244 MFloatScratchSpace R(3, 3, AT_, "R");
4245 MFloatScratchSpace W(4, 4, AT_, "W");
4246 MFloatScratchSpace iW(4, 4, AT_, "iW");
4247 MFloatScratchSpace iI(3, 3, AT_, "iI");
4248 MFloatScratchSpace tmpM(3, 3, AT_, "tmpM");
4249 MFloatScratchSpace rhs(4, AT_, "rhs");
4250
4251 MFloat tmp[3];
4252 MFloat tmp2[3];
4253 MFloat q0[3];
4254 MFloat q[3];
4255 MFloat tq0[3];
4256 MFloat tq[3];
4257 const MFloat dt2 = F1B2 * timeStep();
4258
4259 MIntScratchSpace recvCnt(noDomains(), AT_, "recvCnt");
4260 MIntScratchSpace recvDispl(noDomains() + 1, AT_, "recvDispl");
4261 MIntScratchSpace bodyOffsets(noDomains() + 1, AT_, "bodyOffsets");
4262 bodyOffsets(0) = 0;
4263 for(MLong i = 0; i < noDomains(); i++) {
4264 MLong tmpv = (((MLong)m_noEmbeddedBodies) * (i + 1)) / ((MLong)noDomains());
4265 if(tmpv > numeric_limits<MInt>::max()) mTerm(1, "MInt overflow");
4266 bodyOffsets(i + 1) = (MInt)tmpv;
4267 }
4268
4269 for(MInt k = bodyOffsets(domainId()); k < bodyOffsets(domainId() + 1); k++) {
4270 ASSERT(k > -1 && k < m_noEmbeddedBodies, "");
4271 computeRotationMatrix(R0, &(m_bodyQuaternionDt1[4 * k]));
4272 computeRotationMatrix(R, &(m_bodyQuaternion[4 * k]));
4273 const MFloat w = m_bodyQuaternionDt1[4 * k + 0];
4274 const MFloat x = m_bodyQuaternionDt1[4 * k + 1];
4275 const MFloat y = m_bodyQuaternionDt1[4 * k + 2];
4276 const MFloat z = m_bodyQuaternionDt1[4 * k + 3];
4277 for(MInt i = 0; i < 3; i++)
4278 tmp[i] = m_bodyAngularVelocityDt1[k * 3 + i];
4279 matrixVectorProduct(q0, R0, tmp);
4280 for(MInt i = 0; i < 3; i++)
4281 tmp[i] = m_bodyTorqueDt1[k * 3 + i];
4282 matrixVectorProduct(tq0, R0, tmp);
4283
4284 for(MInt i = 0; i < 3; i++)
4285 tmp[i] = m_bodyTorque[k * 3 + i];
4286 matrixVectorProduct(tq, R, tmp);
4287
4288 const MFloat* momi = &(m_bodyMomentOfInertia[3 * k]);
4289 const MFloat f0 = (momi[2] - momi[1]) / momi[0];
4290 const MFloat f1 = (momi[0] - momi[2]) / momi[1];
4291 const MFloat f2 = (momi[1] - momi[0]) / momi[2];
4292
4293 for(MInt i = 0; i < 3; i++)
4294 tmp[i] = m_bodyAngularVelocity[k * 3 + i];
4295 matrixVectorProduct(&(q[0]), R, tmp);
4296
4297 for(MInt i = 0; i < 3; i++) {
4298 if(std::isnan(tq[i]) || std::isnan(tq0[i]) || std::isnan(q[i])) {
4299 if(domainId() == 0) {
4300 cerr << "error rotation omega " << k << " " << i << " " << tq0[i] << " " << tq[i] << " " << q[i] << " ("
4301 << m_bodyTorque[k * 3 + 0] << "," << m_bodyTorque[k * 3 + 1] << "," << m_bodyTorque[k * 3 + 2] << ")"
4302 << endl;
4303 }
4304 if(std::isnan(tq0[i])) tq0[i] = F0;
4305 tq[i] = tq0[i];
4306 q[i] = q0[i];
4307 // mTerm(1,AT_, "Solution diverged at body rotational integration (omega).");
4308 }
4309 }
4310
4311 const MInt maxit = 100;
4312 MFloat delta = F1;
4313 MInt it = 0;
4314
4315 // Newton iterations
4316 while(delta > 1e-10 && it < maxit) {
4317 W(0, 0) = F1;
4318 W(0, 1) = dt2 * q[2] * f0;
4319 W(0, 2) = dt2 * q[1] * f0;
4320 W(1, 0) = dt2 * q[2] * f1;
4321 W(1, 1) = F1;
4322 W(1, 2) = dt2 * q[0] * f1;
4323 W(2, 0) = dt2 * q[1] * f2;
4324 W(2, 1) = dt2 * q[0] * f2;
4325 W(2, 2) = F1;
4326
4327 maia::math::invert(W, iW, 3, 3);
4328
4329 for(MInt i = 0; i < 3; i++)
4330 rhs[i] = q[i] - q0[i] - dt2 * (tq0[i] + tq[i]) / momi[i];
4331 rhs[0] += dt2 * f0 * (q0[1] * q0[2] + q[1] * q[2]);
4332 rhs[1] += dt2 * f1 * (q0[0] * q0[2] + q[0] * q[2]);
4333 rhs[2] += dt2 * f2 * (q0[0] * q0[1] + q[0] * q[1]);
4334 delta = F0;
4335 for(MInt i = 0; i < 3; i++) {
4336 const MFloat qq = q[i];
4337 for(MInt j = 0; j < 3; j++) {
4338 q[i] -= iW(i, j) * rhs(j);
4339 }
4340 delta = mMax(delta, fabs(q[i] - qq));
4341 }
4342 it++;
4343 }
4344 if(it >= maxit && domainId() == 0) {
4345 cerr << "Newton iterations did not converge " << k << endl;
4346 }
4347
4348 for(MInt i = 0; i < 3; i++) {
4349 if(std::isnan(q[i])) {
4350 if(domainId() == 0) {
4351 cerr << "error rotation quaternion " << k << " " << i << " " << q[i] << endl;
4352 cerr << q[0] << " " << q[1] << " " << q[2] << " " << endl;
4353 cerr << tq0[0] << " " << tq0[1] << " " << tq0[2] << endl;
4354 cerr << tq[0] << " " << tq[1] << " " << tq[2] << endl;
4355 }
4356 // MPI_Barrier(mpiComm(), AT_ );
4357 // mTerm(1,AT_, "Solution diverged at body rotational integration (quaternion)" + to_string(q[i]) );
4358 q[i] = q0[i];
4359 }
4360 }
4361
4362
4363 W(0, 0) = F0;
4364 W(0, 1) = -q[0];
4365 W(0, 2) = -q[1];
4366 W(0, 3) = -q[2];
4367 W(1, 0) = q[0];
4368 W(1, 1) = F0;
4369 W(1, 2) = q[2];
4370 W(1, 3) = -q[1];
4371 W(2, 0) = q[1];
4372 W(2, 1) = -q[2];
4373 W(2, 2) = F0;
4374 W(2, 3) = q[0];
4375 W(3, 0) = q[2];
4376 W(3, 1) = q[1];
4377 W(3, 2) = -q[0];
4378 W(3, 3) = F0;
4379 for(MInt i = 0; i < 4; i++)
4380 for(MInt j = 0; j < 4; j++)
4381 W(i, j) = -F1B2 * dt2 * W(i, j);
4382 for(MInt i = 0; i < 4; i++)
4383 W(i, i) = F1;
4384
4385 rhs(0) = w + F1B2 * dt2 * (-x * q0[0] - y * q0[1] - z * q0[2]);
4386 rhs(1) = x + F1B2 * dt2 * (w * q0[0] - z * q0[1] + y * q0[2]);
4387 rhs(2) = y + F1B2 * dt2 * (z * q0[0] + w * q0[1] - x * q0[2]);
4388 rhs(3) = z + F1B2 * dt2 * (-y * q0[0] + x * q0[1] + w * q0[2]);
4389
4390 maia::math::invert(W, iW, 4, 4);
4391
4392 for(MInt i = 0; i < 4; i++) {
4393 m_bodyQuaternion[4 * k + i] = F0;
4394 for(MInt j = 0; j < 4; j++) {
4395 m_bodyQuaternion[4 * k + i] += iW(i, j) * rhs(j);
4396 }
4397 }
4398
4399 MFloat abs = F0;
4400 for(MInt i = 0; i < 4; i++)
4401 abs += POW2(m_bodyQuaternion[4 * k + i]);
4402 for(MInt i = 0; i < 4; i++)
4403 m_bodyQuaternion[4 * k + i] /= sqrt(abs);
4404
4405
4406 computeRotationMatrix(R, &(m_bodyQuaternion[4 * k]));
4407 matrixVectorProductTranspose(tmp, R, &(q[0]));
4408
4409 for(MInt i = 0; i < 3; i++) {
4410 if(m_fixedBodyComponentsRotation[i]) continue;
4411 m_bodyAngularVelocity[k * 3 + i] = tmp[i];
4412 }
4413 for(MInt i = 0; i < 3; i++) {
4414 tmp[i] = (q[i] - q0[i]) / timeStep();
4415 }
4416 matrixVectorProductTranspose(tmp2, R, &(tmp[0]));
4417 for(MInt i = 0; i < 3; i++) {
4418 if(m_fixedBodyComponentsRotation[i]) continue;
4419 m_bodyAngularAcceleration[k * 3 + i] = tmp2[i];
4420 }
4421 }
4422
4423 recvDispl(0) = 0;
4424 for(MInt i = 0; i < noDomains(); i++) {
4425 recvDispl(i + 1) = 4 * bodyOffsets(i + 1);
4426 recvCnt(i) = recvDispl(i + 1) - recvDispl(i);
4427 }
4428 MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, m_bodyQuaternion, &recvCnt[0], &recvDispl[0], MPI_DOUBLE,
4429 mpiComm(), AT_, "MPI_IN_PLACE", "m_bodyQuaternion");
4430
4431 recvDispl(0) = 0;
4432 for(MInt i = 0; i < noDomains(); i++) {
4433 recvDispl(i + 1) = 3 * bodyOffsets(i + 1);
4434 recvCnt(i) = recvDispl(i + 1) - recvDispl(i);
4435 }
4436 MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, m_bodyAngularVelocity, &recvCnt[0], &recvDispl[0], MPI_DOUBLE,
4437 mpiComm(), AT_, "MPI_IN_PLACE", "m_bodyAngularVelocity");
4438 MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, m_bodyAngularAcceleration, &recvCnt[0], &recvDispl[0], MPI_DOUBLE,
4439 mpiComm(), AT_, "MPI_IN_PLACE", "m_bodyAngularAcceleration");
4440}
4441
4442
4447template <MInt nDim, class SysEqn>
4449 TRACE();
4450
4451 if(!m_constructGField) return;
4452
4453 const MFloat qw = m_bodyQuaternion[4 * bodyId + 0];
4454 const MFloat qx = m_bodyQuaternion[4 * bodyId + 1];
4455 const MFloat qy = m_bodyQuaternion[4 * bodyId + 2];
4456 const MFloat qz = m_bodyQuaternion[4 * bodyId + 3];
4457 bodyRotation[0] = atan2(F2 * qw * qx + 2 * qy * qz, F1 - F2 * qw * qw - F2 * qz * qz);
4458 bodyRotation[1] = asin(F2 * qx * qz - F2 * qw * qy);
4459 bodyRotation[2] = atan2(F2 * qx * qy + F2 * qw * qz, F1 - F2 * qy * qy - F2 * qz * qz);
4460}
4461
4462
4467template <MInt nDim, class SysEqn>
4469 TRACE();
4470
4471 if(!m_constructGField) return;
4472
4473 const MFloat qw = m_bodyQuaternionDt1[4 * bodyId + 0];
4474 const MFloat qx = m_bodyQuaternionDt1[4 * bodyId + 1];
4475 const MFloat qy = m_bodyQuaternionDt1[4 * bodyId + 2];
4476 const MFloat qz = m_bodyQuaternionDt1[4 * bodyId + 3];
4477 bodyRotation[0] = atan2(F2 * qw * qx + 2 * qy * qz, F1 - F2 * qw * qw - F2 * qz * qz);
4478 bodyRotation[1] = asin(F2 * qx * qz - F2 * qw * qy);
4479 bodyRotation[2] = atan2(F2 * qx * qy + F2 * qw * qz, F1 - F2 * qy * qy - F2 * qz * qz);
4480}
4481
4482
4487template <MInt nDim, class SysEqn>
4489 TRACE();
4490
4491 if(!m_constructGField) return;
4492
4493 m_bodyQuaternion[bodyId * 4 + 0] = cos(F1B2 * bodyRotation[1]) * cos(F1B2 * (bodyRotation[2] + bodyRotation[0]));
4494 m_bodyQuaternion[bodyId * 4 + 1] = sin(F1B2 * bodyRotation[1]) * sin(F1B2 * (bodyRotation[2] - bodyRotation[0]));
4495 m_bodyQuaternion[bodyId * 4 + 2] = sin(F1B2 * bodyRotation[1]) * cos(F1B2 * (bodyRotation[2] - bodyRotation[0]));
4496 m_bodyQuaternion[bodyId * 4 + 3] = cos(F1B2 * bodyRotation[1]) * sin(F1B2 * (bodyRotation[2] + bodyRotation[0]));
4497}
4498
4499
4505template <MInt nDim, class SysEqn>
4507 TRACE();
4508
4509 ASSERT(m_constructGField, "");
4510
4511 NEW_TIMER_GROUP_STATIC(t_initTimer, "GFieldPredictor");
4512 NEW_TIMER_STATIC(t_timertotal, "GFieldPredictor", t_initTimer);
4513 NEW_SUB_TIMER_STATIC(t_init, "init", t_timertotal);
4514 NEW_SUB_TIMER_STATIC(t_advance, "advance", t_timertotal);
4515 NEW_SUB_TIMER_STATIC(t_transfer, "transfer", t_timertotal);
4516
4517 m_structureStep = 0;
4518
4519 if(!m_trackMovingBndry || globalTimeStep < m_trackMbStart || globalTimeStep >= m_trackMbEnd) return;
4520
4521 RECORD_TIMER_START(t_timertotal);
4522 RECORD_TIMER_START(t_init);
4523
4524 if(m_motionEquation == 0 || globalTimeStep < m_FSIStart) {
4525 // forced motion
4526 if(m_constructGField && m_bodyTypeMb > 0) {
4527 constructGField();
4528 } else if(m_motionEquation == 0) {
4529 updateBodyProperties();
4530 }
4531 if(m_bodyTypeMb != 0) {
4532 createPeriodicGhostBodies();
4533 createBodyTree();
4534 }
4535 RECORD_TIMER_STOP(t_init);
4536 RECORD_TIMER_STOP(t_timertotal);
4537 return;
4538 }
4539
4540#if defined _MB_DEBUG_ || !defined NDEBUG
4541 m_solutionDiverged = false;
4542 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4543 for(MInt i = 0; i < nDim; i++) {
4544 m_solutionDiverged += std::isnan(m_bodyForce[k * nDim + i]);
4545 }
4546 for(MInt i = 0; i < 3; i++) {
4547 m_solutionDiverged += std::isnan(m_bodyTorque[k * 3 + i]);
4548 }
4549 }
4550 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
4551 "m_solutionDiverged");
4552 if(m_solutionDiverged) {
4553 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4554 for(MInt i = 0; i < nDim; i++) {
4555 m_log << m_bodyForce[k * nDim + i] << " ";
4556 }
4557 m_log << " / ";
4558 for(MInt i = 0; i < 3; i++) {
4559 m_log << m_bodyTorque[k * 3 + i] << " ";
4560 }
4561 m_log << endl;
4562 }
4563 const MInt writeHaloBack = m_haloCellOutput;
4564 m_haloCellOutput = true;
4565 writeVtkXmlFiles("QOUT", "GEOM", false, true);
4566 m_haloCellOutput = writeHaloBack;
4567 MPI_Barrier(mpiComm(), AT_);
4568 mTerm(1, AT_, "Solution diverged before structure predictor handling.");
4569 }
4570#endif
4571
4572 RECORD_TIMER_STOP(t_init);
4573 RECORD_TIMER_START(t_advance);
4574
4575
4576 MBool& firstRun = m_static_constructGFieldPredictor_firstRun;
4577 MBool& adaptiveGravity = m_static_constructGFieldPredictor_adaptiveGravity;
4578 if(firstRun) {
4579 if(Context::propertyExists("adaptiveGravity", m_solverId)) {
4592 adaptiveGravity = Context::getSolverProperty<MBool>("adaptiveGravity", m_solverId, AT_, &adaptiveGravity);
4593 }
4594 firstRun = false;
4595 }
4596 if(adaptiveGravity && globalTimeStep == m_FSIStart) {
4597 m_gravity[2] = -m_bodyForce[2] / m_bodyMass[0];
4598 // m_gravity[2] = -F3B4*CdLaw(m_Re)*POW2(m_Ma)/(m_referenceLength*m_rhoInfinity);
4599 // m_gravity[2] = -CdLaw(m_Re) * m_rhoU2 * PI*POW2( F1B2*m_bodyDiameter[0] );
4600 m_log << "adaptive gravity: " << m_gravity[2] << " " << m_bodyForce[2] << " " << m_bodyForce[nDim + 2] << endl;
4601 }
4602
4603
4604 switch(m_motionEquation) {
4605 // free motion under gravity
4606 case 1: {
4607 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4608 for(MInt i = 0; i < nDim; i++) {
4609 if(m_fixedBodyComponents[i]) continue;
4610
4611 m_bodyAcceleration[k * nDim + i] = m_bodyAccelerationDt1[k * nDim + i];
4612 m_bodyCenter[k * nDim + i] =
4613 m_bodyCenterDt1[k * nDim + i]
4614 + timeStep() * m_bodyVelocityDt1[k * nDim + i]
4615 + F1B4 * POW2(timeStep()) * (m_bodyAccelerationDt1[k * nDim + i] + m_bodyAcceleration[k * nDim + i]);
4616 m_bodyVelocity[k * nDim + i] =
4617 m_bodyVelocityDt1[k * nDim + i]
4618 + timeStep() * F1B2 * (m_bodyAccelerationDt1[k * nDim + i] + m_bodyAcceleration[k * nDim + i]);
4619 if(fabs(m_bodyCenter[k * nDim + i] - m_bodyCenterDt1[k * nDim + i])
4620 > c_cellLengthAtLevel(m_lsCutCellBaseLevel))
4621 cerr << "displ " << k << " " << i << " " << m_bodyCenter[k * nDim + i] << " "
4622 << m_bodyCenterDt1[k * nDim + i] << endl;
4623 }
4624 m_bodyTemperature[k] =
4625 m_bodyTemperatureDt1[k] + timeStep() * m_bodyHeatFlux[k] / (m_capacityConstantVolumeRatio * m_bodyMass[k]);
4626 }
4627 integrateBodyRotation();
4628
4629 break;
4630 }
4631
4632 // elastically mounted (Ahn & Kallinderis, JCP(2006))
4633 case 2: {
4634 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4635 for(MInt i = 0; i < nDim; i++) {
4636 if(m_fixedBodyComponents[i]) continue;
4637
4638 m_bodyCenterDt2[k * nDim + i] = m_bodyCenterDt1[k * nDim + i];
4639 m_bodyCenterDt1[k * nDim + i] = m_bodyCenter[k * nDim + i];
4640 m_bodyVelocityDt1[k * nDim + i] = m_bodyVelocity[k * nDim + i];
4641
4642 const MFloat A = F4 * PI * m_bodyDampingCoefficient[k] * m_bodyReducedFrequency[k];
4643 const MFloat B = F4 * POW2(PI) * POW2(m_bodyReducedFrequency[k]);
4644 const MFloat C = m_bodyForce[k * nDim + i] / m_bodyReducedMass[k];
4645 m_bodyCenter[k * nDim + i] =
4646 m_bodyCenterDt1[k * nDim + i] + timeStep() * m_bodyVelocityDt1[k * nDim + i]
4647 + POW2(timeStep())
4648 * (C - A * m_bodyVelocityDt1[k * nDim + i]
4649 - B * (m_bodyCenterDt1[k * nDim + i] - m_bodyNeutralCenter[k * nDim + i]));
4650 m_bodyVelocity[k * nDim + i] = (m_bodyCenter[k * nDim + i] - m_bodyCenterDt1[k * nDim + i]) / timeStep();
4651 m_bodyAcceleration[k * nDim + i] =
4652 (m_bodyCenter[k * nDim + i] - F2 * m_bodyCenterDt1[k * nDim + i] + m_bodyCenterDt2[k * nDim + i])
4653 / POW2(timeStep());
4654 }
4655 }
4656
4657 break;
4658 }
4659
4660 // elastically mounted - implicit discretization (Borazjani, JCP(2008))
4661 case 3: {
4662 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4663 for(MInt i = 0; i < nDim; i++) {
4664 if(m_fixedBodyComponents[i]) continue;
4665
4666 m_bodyCenterDt1[k * nDim + i] = m_bodyCenter[k * nDim + i];
4667 m_bodyVelocityDt1[k * nDim + i] = m_bodyVelocity[k * nDim + i];
4668
4669 const MFloat A = F4 * PI * m_bodyDampingCoefficient[k] * m_bodyReducedFrequency[k];
4670 const MFloat B = F4 * POW2(PI) * POW2(m_bodyReducedFrequency[k]);
4671 const MFloat C = m_bodyForce[k * nDim + i] / m_bodyReducedMass[k];
4672
4673 m_bodyVelocity[k * nDim + i] =
4674 (m_bodyVelocityDt1[k * nDim + i] * (F1 - F1B2 * POW2(timeStep()) * B) + timeStep() * C
4675 - timeStep() * B * (m_bodyCenterDt1[k * nDim + i] - m_bodyNeutralCenter[k * nDim + i]))
4676 / (F1 + timeStep() * A + F1B2 * POW2(timeStep()) * B);
4677 m_bodyCenter[k * nDim + i] =
4678 m_bodyCenterDt1[k * nDim + i]
4679 + timeStep() * F1B2 * (m_bodyVelocity[k * nDim + i] + m_bodyVelocityDt1[k * nDim + i]);
4680 m_bodyAcceleration[k * nDim + i] =
4681 (m_bodyVelocity[k * nDim + i] - m_bodyVelocityDt1[k * nDim + i]) / timeStep();
4682 }
4683 }
4684
4685 break;
4686 }
4687
4688 // elastically mounted - true Crank Nicolson ( Lennart's modification of Borazjani scheme )
4689 case 4: {
4690 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4691 for(MInt i = 0; i < nDim; i++) {
4692 if(m_fixedBodyComponents[i]) continue;
4693
4694 m_bodyForceDt1[k * nDim + i] = m_bodyForce[k * nDim + i];
4695 m_bodyCenterDt1[k * nDim + i] = m_bodyCenter[k * nDim + i];
4696 m_bodyVelocityDt1[k * nDim + i] = m_bodyVelocity[k * nDim + i];
4697
4698 const MFloat A = F4 * PI * m_bodyDampingCoefficient[k] * m_bodyReducedFrequency[k];
4699 const MFloat B = F4 * POW2(PI) * POW2(m_bodyReducedFrequency[k]);
4700 // the following yields essentially the old body force -> second order only recovered via the corrector steps!
4701 const MFloat C = F1B2 * (m_bodyForce[k * nDim + i] + m_bodyForceDt1[k * nDim + i]) / m_bodyReducedMass[k];
4702 const MFloat beta = F1B2 * timeStep() * (A + F1B2 * timeStep() * B);
4703
4704 m_bodyVelocity[k * nDim + i] =
4705 (m_bodyVelocityDt1[k * nDim + i] * (F1 - beta) + timeStep() * C
4706 - timeStep() * B * (m_bodyCenterDt1[k * nDim + i] - m_bodyNeutralCenter[k * nDim + i]))
4707 / (F1 + beta);
4708 m_bodyCenter[k * nDim + i] =
4709 m_bodyCenterDt1[k * nDim + i]
4710 + timeStep() * F1B2 * (m_bodyVelocity[k * nDim + i] + m_bodyVelocityDt1[k * nDim + i]);
4711 m_bodyAcceleration[k * nDim + i] =
4712 (m_bodyVelocity[k * nDim + i] - m_bodyVelocityDt1[k * nDim + i]) / timeStep();
4713 }
4714 }
4715
4716 break;
4717 }
4718
4719 // Beeman scheme
4720 case 5: {
4721 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4722 for(MInt i = 0; i < nDim; i++) {
4723 if(m_fixedBodyComponents[i]) continue;
4724
4725 m_bodyAcceleration[k * nDim + i] =
4726 m_bodyAccelerationDt1[k * nDim + i]
4727 + (timeStep() / m_previousTimeStep)
4728 * (m_bodyAccelerationDt1[k * nDim + i] - m_bodyAccelerationDt2[k * nDim + i]);
4729 m_bodyCenter[k * nDim + i] =
4730 m_bodyCenterDt1[k * nDim + i] + timeStep() * m_bodyVelocityDt1[k * nDim + i]
4731 + F1B6 * POW2(timeStep()) * (m_bodyAcceleration[k * nDim + i] + F2 * m_bodyAccelerationDt1[k * nDim + i]);
4732 m_bodyVelocity[k * nDim + i] =
4733 m_bodyVelocityDt1[k * nDim + i]
4734 + timeStep() * F1B2 * (m_bodyAcceleration[k * nDim + i] + m_bodyAccelerationDt1[k * nDim + i]);
4735 }
4736 }
4737 integrateBodyRotation();
4738
4739 break;
4740 }
4741
4742 case 6: { // fourth-order Beeman scheme -> JCP 20 (1976)
4743
4744 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4745 for(MInt i = 0; i < nDim; i++) {
4746 if(m_fixedBodyComponents[i]) continue;
4747
4748 // initial guess
4749 m_bodyAcceleration[k * nDim + i] = F3 * m_bodyAccelerationDt1[k * nDim + i]
4750 - F3 * m_bodyAccelerationDt2[k * nDim + i]
4751 + m_bodyAccelerationDt3[k * nDim + i];
4752 m_bodyCenter[k * nDim + i] =
4753 m_bodyCenterDt1[k * nDim + i] + timeStep() * m_bodyVelocityDt1[k * nDim + i]
4754 + F1B24 * POW2(timeStep())
4755 * (F3 * m_bodyAcceleration[k * nDim + i] + F10 * m_bodyAccelerationDt1[k * nDim + i]
4756 - m_bodyAccelerationDt2[k * nDim + i]);
4757 m_bodyVelocity[k * nDim + i] =
4758 m_bodyVelocityDt1[k * nDim + i]
4759 + timeStep() * F1B12
4760 * (F5 * m_bodyAcceleration[k * nDim + i] + F8 * m_bodyAccelerationDt1[k * nDim + i]
4761 - m_bodyAccelerationDt2[k * nDim + i]);
4762 }
4763 }
4764 integrateBodyRotation();
4765
4766 break;
4767 }
4768
4769 default: {
4770 mTerm(1, AT_, "Invalid motion equation specified!");
4771 }
4772 }
4773
4774 RECORD_TIMER_STOP(t_advance);
4775 RECORD_TIMER_START(t_transfer);
4776
4777#if defined _MB_DEBUG_ || !defined NDEBUG
4778 MBool nan = false;
4779 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4780 for(MInt i = 0; i < nDim; i++) {
4781 if(std::isnan(m_bodyVelocity[k * nDim + i]) || std::isnan(m_bodyCenter[k * nDim + i])
4782 || std::isnan(m_bodyAcceleration[k * nDim + i])) {
4783 nan = true;
4784 }
4785 }
4786 }
4787 if(nan) {
4788 m_solutionDiverged = true;
4789 cerr << "Solution diverged (SPRED) at solver " << domainId() << endl;
4790 }
4791 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
4792 "m_solutionDiverged");
4793 if(m_solutionDiverged) {
4794 writeVtkXmlFiles("QOUT", "GEOM", false, true);
4795 MPI_Barrier(mpiComm(), AT_);
4796 mTerm(1, AT_, "Solution diverged after structure predictor handling.");
4797 }
4798#endif
4799
4800 createPeriodicGhostBodies();
4801 createBodyTree();
4802
4803 RECORD_TIMER_STOP(t_transfer);
4804 RECORD_TIMER_STOP(t_timertotal);
4805 DISPLAY_TIMER_OFFSET(t_timertotal, m_restartInterval);
4806}
4807
4808
4813template <MInt nDim, class SysEqn>
4815 TRACE();
4816
4817 m_structureStep++;
4818
4819 if(!m_trackMovingBndry || globalTimeStep < m_trackMbStart || globalTimeStep >= m_trackMbEnd) return true;
4820 if(m_motionEquation == 0) return true;
4821 if(globalTimeStep < m_FSIStart) {
4822 return true;
4823 }
4824
4825 ASSERT(m_constructGField, "");
4826
4827 NEW_TIMER_GROUP_STATIC(t_initTimer, "GFieldCorrector");
4828 NEW_TIMER_STATIC(t_timertotal, "GFieldCorrector", t_initTimer);
4829 NEW_SUB_TIMER_STATIC(t_init, "init", t_timertotal);
4830 NEW_SUB_TIMER_STATIC(t_advance, "advance", t_timertotal);
4831 NEW_SUB_TIMER_STATIC(t_transfer, "transfer", t_timertotal);
4832 RECORD_TIMER_START(t_timertotal);
4833 RECORD_TIMER_START(t_init);
4834
4835 MFloatScratchSpace oldX(m_noEmbeddedBodies, nDim, AT_, "oldX");
4836 MFloatScratchSpace oldV(m_noEmbeddedBodies, nDim, AT_, "oldV");
4837 MFloatScratchSpace oldQ(m_noEmbeddedBodies, 4, AT_, "oldQ");
4838 MFloatScratchSpace oldW(m_noEmbeddedBodies, 3, AT_, "oldW");
4839
4840 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4841 for(MInt i = 0; i < nDim; i++)
4842 oldX(k, i) = m_bodyCenter[k * nDim + i];
4843 for(MInt i = 0; i < nDim; i++)
4844 oldV(k, i) = m_bodyVelocity[k * nDim + i];
4845 for(MInt i = 0; i < 3; i++)
4846 oldW(k, i) = m_bodyAngularVelocity[k * 3 + i];
4847 for(MInt i = 0; i < 4; i++)
4848 oldQ(k, i) = m_bodyQuaternion[k * 4 + i];
4849 }
4850
4851 RECORD_TIMER_STOP(t_init);
4852 RECORD_TIMER_START(t_advance);
4853
4854
4855 switch(m_motionEquation) {
4856 // free motion under gravity
4857 case 1: {
4858 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4859 for(MInt i = 0; i < nDim; i++) {
4860 if(m_fixedBodyComponents[i]) continue;
4861
4862 m_bodyAcceleration[k * nDim + i] = (m_bodyForce[k * nDim + i]) / m_bodyMass[k] + m_gravity[i];
4863 m_bodyCenter[k * nDim + i] =
4864 m_bodyCenterDt1[k * nDim + i]
4865 + timeStep() * m_bodyVelocityDt1[k * nDim + i]
4866 + F1B4 * POW2(timeStep()) * (m_bodyAccelerationDt1[k * nDim + i] + m_bodyAcceleration[k * nDim + i]);
4867 m_bodyVelocity[k * nDim + i] =
4868 m_bodyVelocityDt1[k * nDim + i]
4869 + timeStep() * F1B2 * (m_bodyAccelerationDt1[k * nDim + i] + m_bodyAcceleration[k * nDim + i]);
4870 if(fabs(m_bodyCenter[k * nDim + i] - m_bodyCenterDt1[k * nDim + i])
4871 > c_cellLengthAtLevel(m_lsCutCellBaseLevel))
4872 cerr << "displ " << k << " " << i << " " << m_bodyCenter[k * nDim + i] << " "
4873 << m_bodyCenterDt1[k * nDim + i] << endl;
4874 }
4875 m_bodyTemperature[k] = F1B2
4876 * (m_bodyTemperature[k] + m_bodyTemperatureDt1[k]
4877 + timeStep() * (m_bodyHeatFlux[k] / (m_capacityConstantVolumeRatio * m_bodyMass[k])));
4878 }
4879 integrateBodyRotation();
4880
4881 break;
4882 }
4883
4884 case 2: {
4885 /*
4886 if ( m_initialCondition == 459 ) {
4887 const MFloat rhosbrhof = 1.05 / 1.0;
4888 const MFloat rhofbrhos = 1.0 / rhosbrhof;
4889 const MFloat Cd = 24.0 * POW2( 9.06/sqrt(m_Re) + 1.0 ) / POW2( 9.06 );
4890 const MFloat ut = sqrt( 4.0/3.0 * m_physicalReferenceLength * 9.81 * (rhosbrhof-1.0) / Cd );
4891 const MFloat Froude = ut / sqrt( 9.81 * m_physicalReferenceLength );
4892 const MFloat g[3] = { F0, F0, -POW2( m_Ma / Froude ) };
4893
4894 dxmax = F0;
4895 dumax = F0;
4896
4897 for ( MInt k = 0; k < m_noEmbeddedBodies; k++ ) {
4898 dx = F0;
4899 du = F0;
4900 for( MInt i=0; i<nDim; i++ ) {
4901 if( m_fixedBodyComponents[ i ] )
4902 continue;
4903
4904 tmpx = m_bodyCenter[ k*nDim+i ];
4905 tmpu = m_bodyVelocity[ k*nDim+i ];
4906
4907 m_bodyAcceleration[ k*nDim+i ] =
4908 ( F1 - rhofbrhos ) * g[ i ] + rhofbrhos * m_bodyForce[ k*nDim+i ] / m_bodyMass[ k ] ;
4909
4910 m_bodyVelocity[ k*nDim+i ] =
4911 m_bodyVelocityDt1[ k*nDim+i ] + timeStep() * 0.5 *
4912 ( m_bodyAcceleration[ k*nDim+i ] + m_bodyAccelerationDt1[ k*nDim+i ] );
4913
4914 m_bodyCenter[ k*nDim+i ] =
4915 m_bodyCenterDt1[ k*nDim+i ] + timeStep() * 0.5 *
4916 ( m_bodyVelocity[ k*nDim+i ] + m_bodyVelocityDt1[ k*nDim+i ] );
4917
4918 // m_bodyVelocity[ k*nDim+i ] =
4919 // ( m_bodyCenter[ k*nDim+i ] - m_bodyCenterDt1[ k*nDim+i ] ) / timeStep();
4920
4921 dx += POW2( m_bodyCenter[ k*nDim+i ] - tmpx );
4922 du += POW2( m_bodyVelocity[ k*nDim+i ] - tmpu );
4923 }
4924 du = sqrt( du );
4925 dx = sqrt( dx );
4926 dumax = mMax( dumax, du );
4927 dxmax = mMax( dxmax, dx );
4928 }
4929
4930 cerr << "corr: " << globalTimeStep << " " << m_structureStep << " " << dxmax << " " << dumax << endl;
4931 }
4932 */
4933
4934 break;
4935 }
4936
4937 // elastically mounted - implicit discretization (Borazjani, JCP(2008))
4938 case 3: {
4939 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4940 for(MInt i = 0; i < nDim; i++) {
4941 if(m_fixedBodyComponents[i]) continue;
4942
4943 const MFloat A = F4 * PI * m_bodyDampingCoefficient[k] * m_bodyReducedFrequency[k];
4944 const MFloat B = F4 * POW2(PI) * POW2(m_bodyReducedFrequency[k]);
4945 const MFloat C = m_bodyForce[k * nDim + i] / m_bodyReducedMass[k];
4946
4947 m_bodyVelocity[k * nDim + i] =
4948 (m_bodyVelocityDt1[k * nDim + i] * (F1 - F1B2 * POW2(timeStep()) * B) + timeStep() * C
4949 - timeStep() * B * (m_bodyCenterDt1[k * nDim + i] - m_bodyNeutralCenter[k * nDim + i]))
4950 / (F1 + timeStep() * A + F1B2 * POW2(timeStep()) * B);
4951 m_bodyCenter[k * nDim + i] =
4952 m_bodyCenterDt1[k * nDim + i]
4953 + timeStep() * F1B2 * (m_bodyVelocity[k * nDim + i] + m_bodyVelocityDt1[k * nDim + i]);
4954 m_bodyAcceleration[k * nDim + i] =
4955 (m_bodyVelocity[k * nDim + i] - m_bodyVelocityDt1[k * nDim + i]) / timeStep();
4956 }
4957 }
4958
4959 break;
4960 }
4961
4962 // elastically mounted - true Crank Nicolson ( Lennart's modification of Borazjani scheme )
4963 case 4: {
4964 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4965 for(MInt i = 0; i < nDim; i++) {
4966 if(m_fixedBodyComponents[i]) continue;
4967
4968 const MFloat A = F4 * PI * m_bodyDampingCoefficient[k] * m_bodyReducedFrequency[k];
4969 const MFloat B = F4 * POW2(PI) * POW2(m_bodyReducedFrequency[k]);
4970 const MFloat C = F1B2 * (m_bodyForce[k * nDim + i] + m_bodyForceDt1[k * nDim + i]) / m_bodyReducedMass[k];
4971 const MFloat beta = F1B2 * timeStep() * (A + F1B2 * timeStep() * B);
4972
4973 m_bodyVelocity[k * nDim + i] =
4974 (m_bodyVelocityDt1[k * nDim + i] * (F1 - beta) + timeStep() * C
4975 - timeStep() * B * (m_bodyCenterDt1[k * nDim + i] - m_bodyNeutralCenter[k * nDim + i]))
4976 / (F1 + beta);
4977 m_bodyCenter[k * nDim + i] =
4978 m_bodyCenterDt1[k * nDim + i]
4979 + timeStep() * F1B2 * (m_bodyVelocity[k * nDim + i] + m_bodyVelocityDt1[k * nDim + i]);
4980 m_bodyAcceleration[k * nDim + i] =
4981 (m_bodyVelocity[k * nDim + i] - m_bodyVelocityDt1[k * nDim + i]) / timeStep();
4982 }
4983 }
4984
4985 break;
4986 }
4987
4988 // Beeman scheme
4989 case 5: {
4990 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
4991 for(MInt i = 0; i < nDim; i++) {
4992 if(m_fixedBodyComponents[i]) continue;
4993
4994 m_bodyAcceleration[k * nDim + i] = (m_bodyForce[k * nDim + i] + m_gravity[i]) / m_bodyMass[k];
4995 m_bodyCenter[k * nDim + i] =
4996 m_bodyCenterDt1[k * nDim + i] + timeStep() * m_bodyVelocityDt1[k * nDim + i]
4997 + F1B6 * POW2(timeStep()) * (m_bodyAcceleration[k * nDim + i] + F2 * m_bodyAccelerationDt1[k * nDim + i]);
4998 m_bodyVelocity[k * nDim + i] =
4999 m_bodyVelocityDt1[k * nDim + i]
5000 + timeStep() * F1B2 * (m_bodyAcceleration[k * nDim + i] + m_bodyAccelerationDt1[k * nDim + i]);
5001 }
5002 }
5003 integrateBodyRotation();
5004
5005 break;
5006 }
5007
5008 // fourth-order Beeman scheme -> JCP 20 (1976)
5009 case 6: {
5010 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
5011 for(MInt i = 0; i < nDim; i++) {
5012 if(m_fixedBodyComponents[i]) continue;
5013
5014 m_bodyAcceleration[k * nDim + i] = (m_bodyForce[k * nDim + i] + m_gravity[i]) / m_bodyMass[k];
5015 m_bodyCenter[k * nDim + i] =
5016 m_bodyCenterDt1[k * nDim + i] + timeStep() * m_bodyVelocityDt1[k * nDim + i]
5017 + F1B24 * POW2(timeStep())
5018 * (F3 * m_bodyAcceleration[k * nDim + i] + F10 * m_bodyAccelerationDt1[k * nDim + i]
5019 - m_bodyAccelerationDt2[k * nDim + i]);
5020 m_bodyVelocity[k * nDim + i] =
5021 m_bodyVelocityDt1[k * nDim + i]
5022 + timeStep() * F1B12
5023 * (F5 * m_bodyAcceleration[k * nDim + i] + F8 * m_bodyAccelerationDt1[k * nDim + i]
5024 - m_bodyAccelerationDt2[k * nDim + i]);
5025 }
5026 }
5027 integrateBodyRotation();
5028
5029 break;
5030 }
5031
5032 default: {
5033 mTerm(1, AT_, "Invalid motion equation specified!");
5034 }
5035 }
5036
5037 RECORD_TIMER_STOP(t_advance);
5038 RECORD_TIMER_START(t_transfer);
5039
5040#if defined _MB_DEBUG_ || !defined NDEBUG
5041 MBool nan = false;
5042 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
5043 for(MInt i = 0; i < nDim; i++) {
5044 if(std::isnan(m_bodyVelocity[k * nDim + i]) || std::isnan(m_bodyCenter[k * nDim + i])
5045 || std::isnan(m_bodyAcceleration[k * nDim + i])) {
5046 nan = true;
5047 }
5048 }
5049 }
5050 if(nan) {
5051 m_solutionDiverged = true;
5052 cerr << "Solution diverged (SCORR) at solver " << domainId() << endl;
5053 }
5054 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
5055 "m_solutionDiverged");
5056 if(m_solutionDiverged) {
5057 writeVtkXmlFiles("QOUT", "GEOM", false, true);
5058 MPI_Barrier(mpiComm(), AT_);
5059 mTerm(1, AT_, "Solution diverged after structure corrector handling.");
5060 }
5061#endif
5062
5063 createPeriodicGhostBodies();
5064 createBodyTree();
5065
5066 MFloat dxmax = F0;
5067 MFloat dumax = F0;
5068 MFloat drmax = F0;
5069 MFloat dwmax = F0;
5070 MFloat dxavg = F0;
5071 MFloat duavg = F0;
5072 MFloat dravg = F0;
5073 MFloat dwavg = F0;
5074
5075 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
5076 for(MInt i = 0; i < nDim; i++) {
5077 if(m_fixedBodyComponents[i]) continue;
5078 MFloat dx = fabs(m_bodyCenter[k * nDim + i] - oldX(k, i));
5079 MFloat du = fabs(m_bodyVelocity[k * nDim + i] - oldV(k, i));
5080 dumax = mMax(dumax, du);
5081 dxmax = mMax(dxmax, dx);
5082 duavg += du;
5083 dxavg += dx;
5084 }
5085 }
5086
5087 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
5088 for(MInt i = 0; i < 3; i++) {
5089 if(m_fixedBodyComponentsRotation[i]) continue;
5090 MFloat dw = fabs(m_bodyAngularVelocity[k * 3 + i] - oldW(k, i));
5091 dwmax = mMax(dwmax, dw);
5092 dwavg += dw;
5093 }
5094 for(MInt i = 0; i < 4; i++) {
5095 MFloat dr = fabs(m_bodyQuaternion[k * 4 + i] - oldQ(k, i));
5096 drmax = mMax(drmax, dr);
5097 dravg += dr;
5098 }
5099 }
5100
5101 dxavg /= ((MFloat)m_noEmbeddedBodies);
5102 duavg /= ((MFloat)m_noEmbeddedBodies);
5103 dravg /= ((MFloat)m_noEmbeddedBodies);
5104 dwavg /= ((MFloat)m_noEmbeddedBodies);
5105
5106 if(globalTimeStep % 10 == 0 || m_structureStep > 1) {
5107 cerr0 << "corr: " << globalTimeStep << " (" << m_structureStep << "): " << dxmax << " " << dumax << " / " << drmax
5108 << " " << dwmax << " (" << dxavg << " " << duavg << " / " << dravg << " " << dwavg << ")" << endl;
5109 }
5110
5111 RECORD_TIMER_STOP(t_transfer);
5112 RECORD_TIMER_STOP(t_timertotal);
5113 DISPLAY_TIMER_OFFSET(t_timertotal, m_restartInterval);
5114
5115 if((dxmax < m_FSIToleranceX) && (dumax < m_FSIToleranceU) && (drmax < m_FSIToleranceR) && (dwmax < m_FSIToleranceW)) {
5116 return true;
5117 } else {
5118 return false;
5119 }
5120}
5121
5122
5127template <MInt nDim, class SysEqn>
5129#ifdef _MB_DEBUG_
5130 for(MInt i = 0; i < noNeighborDomains(); i++) {
5131 for(MInt j = 0; j < noHaloCells(i); j++) {
5132 MInt cellId = haloCellId(i, j);
5133
5134 if(c_noChildren(cellId) > 0) continue;
5135 if(!a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
5136
5137 for(MInt var = 0; var < m_noFVars; var++) {
5138 a_rightHandSide(cellId, var) = F0;
5139 }
5140 }
5141 }
5142#endif
5143}
5144
5145
5150template <MInt nDim, class SysEqn>
5152 TRACE();
5153
5154 const MInt noCBytes = a_noCells() * m_noCVars * sizeof(MFloat);
5155 const MInt noFBytes = a_noCells() * m_noFVars * sizeof(MFloat);
5156 MFloat* RESTRICT cVars = (MFloat*)(&(a_variable(0, 0)));
5157 MFloat* RESTRICT oCVars = (MFloat*)(&(a_oldVariable(0, 0)));
5158
5159 memcpy(oCVars, cVars, noCBytes);
5160 memcpy(&(m_rhs0[0][0]), &(a_rightHandSide(0, 0)), noFBytes);
5161
5162 if(m_dualTimeStepping) memcpy(&(m_cellVolumesDt2[0]), &(m_cellVolumesDt1[0]), a_noCells() * sizeof(MFloat));
5163 memcpy(&(m_cellVolumesDt1[0]), &(a_cellVolume(0)), a_noCells() * sizeof(MFloat));
5164
5165 for(MInt cellId = 0; cellId < m_bndryGhostCellsOffset; cellId++) {
5166 a_hasProperty(cellId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::IsInactive);
5167 }
5168
5169 advanceExternalSource();
5170
5171 m_nearBoundaryBackup.clear();
5172
5173 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
5174 MInt cellId = m_bndryLayerCells[c];
5175 if(!m_constructGField) {
5176 ASSERT(a_hasProperty(cellId, SolverCell::NearWall),
5177 to_string(m_solverId) + " " + to_string(globalDomainId()) + " " + to_string(domainId()));
5178 }
5179
5180 vector<MFloat> tmp(max(m_noCVars + m_noFVars, 0) + 1);
5181 tmp[0] = m_cellVolumesDt1[cellId];
5182
5183 for(MInt v = 0; v < m_noCVars; v++) {
5184 tmp[1 + v] = a_oldVariable(cellId, v);
5185 }
5186
5187 for(MInt v = 0; v < m_noFVars; v++) {
5188 tmp[1 + m_noCVars + v] = m_rhs0[cellId][v];
5189 }
5190
5191 m_nearBoundaryBackup.insert(make_pair(cellId, tmp));
5192 }
5193
5194 m_oldBndryCells.clear();
5195 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
5196 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
5197
5198 ASSERT(!a_isBndryGhostCell(cellId), "");
5199 if(!m_constructGField) {
5200 ASSERT(a_hasProperty(cellId, SolverCell::IsMovingBnd), "");
5201 }
5202
5203 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
5204 a_hasProperty(cellId, SolverCell::IsMovingBnd) = false;
5205 a_hasProperty(cellId, SolverCell::NearWall) = false;
5206 continue;
5207 }
5208 m_oldBndryCells.insert(make_pair(cellId, m_sweptVolume[bndryId]));
5209 }
5210 m_reComputedBndry = false;
5211
5212 for(MUint it = 0; it < m_temporarilyLinkedCells.size(); it++) {
5213 const MInt cellId = get<1>(m_temporarilyLinkedCells[it]);
5214 a_hasProperty(cellId, SolverCell::IsTempLinked) = false;
5215 }
5216 m_temporarilyLinkedCells.clear();
5217 for(MInt i = 0; i < noNeighborDomains(); i++) {
5218 m_linkedWindowCells[i].clear();
5219 m_linkedHaloCells[i].clear();
5220 }
5221}
5222
5223
5228template <MInt nDim, class SysEqn>
5230 TRACE();
5231
5232 const size_t dim3 = 3 * m_noEmbeddedBodies * sizeof(MFloat);
5233 const size_t dim4 = 4 * m_noEmbeddedBodies * sizeof(MFloat);
5234 const size_t dimD = nDim * m_noEmbeddedBodies * sizeof(MFloat);
5235
5236 if(m_motionEquation > 1) {
5237 memcpy(m_bodyVelocityDt2, m_bodyVelocityDt1, dimD);
5238 memcpy(m_bodyCenterDt2, m_bodyCenterDt1, dimD);
5239 memcpy(m_bodyAccelerationDt3, m_bodyAccelerationDt2, dimD);
5240 memcpy(m_bodyAccelerationDt2, m_bodyAccelerationDt1, dimD);
5241 }
5242
5243 memcpy(m_bodyVelocityDt1, m_bodyVelocity, dimD);
5244 memcpy(m_bodyCenterDt1, m_bodyCenter, dimD);
5245 memcpy(m_bodyAccelerationDt1, m_bodyAcceleration, dimD);
5246 memcpy(m_bodyTorqueDt1, m_bodyTorque, dim3);
5247 memcpy(m_bodyAngularVelocityDt1, m_bodyAngularVelocity, dim3);
5248 memcpy(m_bodyAngularAccelerationDt1, m_bodyAngularAcceleration, dim3);
5249 memcpy(m_bodyQuaternionDt1, m_bodyQuaternion, dim4);
5250 memcpy(m_bodyTemperatureDt1, m_bodyTemperature, m_noEmbeddedBodies * sizeof(MFloat));
5251
5252 if(!m_constructGField) return;
5253
5254 if(m_noPointParticles > 0) {
5255 m_fvBndryCnd->recorrectCellCoordinates();
5256
5257 const MInt heatRelated = 2;
5258 const MInt dataSize = 7 * 3 + 2 * 4 + heatRelated;
5259
5260 MIntScratchSpace sendCount(noDomains(), AT_, "sendCount");
5261 MIntScratchSpace recvCount(noDomains(), AT_, "recvCount");
5262 ScratchSpace<MPI_Request> sendReq(noNeighborDomains(), AT_, "sendReq");
5263 ScratchSpace<vector<MFloat>> sendVars(noNeighborDomains(), AT_, "sendVars");
5264 ScratchSpace<vector<MFloat>> recvVars(noNeighborDomains(), AT_, "recvVars");
5265 ScratchSpace<vector<MLong>> sendIds(noNeighborDomains(), AT_, "sendIds");
5266 ScratchSpace<vector<MLong>> recvIds(noNeighborDomains(), AT_, "recvIds");
5267 ScratchSpace<vector<MInt>> sendParticleGlobalIds(noNeighborDomains(), AT_, "sendParticleGlobalIds");
5268 ScratchSpace<vector<MInt>> recvParticleGlobalIds(noNeighborDomains(), AT_, "recvParticleGlobalIds");
5269 map<MLong, MInt> globalToLocal;
5270 ScratchSpace<MLong> globalIds(a_noCells(), AT_, "globalId");
5271 sendCount.fill(0);
5272 recvCount.fill(0);
5273
5274 for(MInt i = 0; i < noNeighborDomains(); ++i) {
5275 sendVars[i].clear();
5276 recvVars[i].clear();
5277 sendIds[i].clear();
5278 recvIds[i].clear();
5279 }
5280
5281 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
5282 if(!a_isHalo(cellId) && c_globalId(cellId) > -1) {
5283 globalToLocal[(MLong)c_globalId(cellId)] = cellId;
5284 }
5285 globalIds(cellId) = (MLong)c_globalId(cellId);
5286 }
5287
5288 exchangeDataFV(&globalIds[0]);
5289
5290 for(MUint p = 0; p < m_particleCellLink.size(); p++) {
5291 const MInt cellId = m_particleCellLink[p];
5292 const MFloat cellHalfLength = F1B2 * c_cellLengthAtCell(cellId);
5293 MInt dirCode[3] = {0, 0, 0};
5294 for(MInt i = 0; i < nDim; i++) {
5295 if(m_particleCoords[nDim * p + i] < a_coordinate(cellId, i) - cellHalfLength)
5296 dirCode[i] = -1;
5297 else if(m_particleCoords[nDim * p + i] > a_coordinate(cellId, i) + cellHalfLength)
5298 dirCode[i] = 1;
5299 }
5300 if(dirCode[0] != 0 || dirCode[1] != 0 || dirCode[2] != 0) {
5301 MInt nghbrId = cellId;
5302 for(MInt i = 0; i < nDim; i++) {
5303 if(dirCode[i] == 0) continue;
5304 MInt dir = (dirCode[i] > 0) ? 2 * i + 1 : 2 * i;
5305 if(dirCode[i] > 0 && a_hasNeighbor(nghbrId, dir) == 0) mTerm(1, AT_, "particle moved into void");
5306 nghbrId = c_neighborId(nghbrId, dir);
5307 }
5308 while(c_noChildren(nghbrId) > 0) {
5309 MInt child = 0;
5310 for(MUint i = 0; i < nDim; i++) {
5311 if(m_particleCoords[nDim * p + i] > a_coordinate(nghbrId, i)) child += IPOW2(i);
5312 }
5313 nghbrId = c_childId(nghbrId, child);
5314 if(nghbrId < 0 || nghbrId >= a_noCells()) mTerm(1, AT_, "Point particle linking failed.");
5315 }
5316 if(!a_isHalo(nghbrId)) {
5317 m_particleCellLink[p] = nghbrId;
5318 } else {
5319 MLong globalId = globalIds(nghbrId); // c_globalId(nghbrId); //since m_globalId not set in periodic cells...
5320 MInt nghbrDomain = -1;
5321 for(MInt i = 0; i < noNeighborDomains(); ++i) {
5322 if(globalId >= domainOffset(neighborDomain(i)) && globalId < domainOffset(neighborDomain(i) + 1)) {
5323 nghbrDomain = i;
5324 break;
5325 }
5326 }
5327 if(nghbrDomain < 0) mTerm(1, AT_, "Neighbor domain not found " + to_string(globalId));
5328 for(MInt i = 0; i < 3; i++) {
5329 sendVars[nghbrDomain].push_back(m_particleCoords[nDim * p + i] - a_coordinate(nghbrId, i));
5330 }
5331 for(MInt i = 0; i < 3; i++) {
5332 sendVars[nghbrDomain].push_back(m_particleVelocity[nDim * p + i]);
5333 }
5334 for(MInt i = 0; i < 3; i++) {
5335 sendVars[nghbrDomain].push_back(m_particleAcceleration[nDim * p + i]);
5336 }
5337 for(MInt i = 0; i < 4; i++) {
5338 sendVars[nghbrDomain].push_back(m_particleQuaternions[4 * p + i]);
5339 }
5340 for(MInt i = 0; i < 3; i++) {
5341 sendVars[nghbrDomain].push_back(m_particleAngularVelocity[3 * p + i]);
5342 }
5343 for(MInt i = 0; i < 3; i++) {
5344 sendVars[nghbrDomain].push_back(m_particleAngularAcceleration[3 * p + i]);
5345 }
5346 for(MInt i = 0; i < 4; i++) {
5347 sendVars[nghbrDomain].push_back(m_particleShapeParams[4 * p + i]);
5348 }
5349 for(MInt i = 0; i < 3; i++) {
5350 sendVars[nghbrDomain].push_back(m_particleRadii[3 * p + i]);
5351 }
5352
5353 sendVars[nghbrDomain].push_back(m_particleTemperature[p]);
5354 sendVars[nghbrDomain].push_back(m_particleHeatFlux[p]);
5355
5356 sendIds[nghbrDomain].push_back(globalId);
5357 m_particleCellLink[p] = -1;
5358 sendCount(neighborDomain(nghbrDomain))++;
5359 sendParticleGlobalIds[nghbrDomain].push_back(m_particleGlobalId[p]);
5360 }
5361 }
5362 }
5363 MPI_Alltoall(&sendCount[0], 1, MPI_INT, &recvCount[0], 1, MPI_INT, mpiComm(), AT_, "sendCount[0]", "recvCount[0]");
5364 for(MInt i = 0; i < noNeighborDomains(); ++i) {
5365 if(recvCount[neighborDomain(i)] > 0) {
5366 recvVars[i].resize(dataSize * recvCount[neighborDomain(i)]);
5367 recvIds[i].resize(recvCount[neighborDomain(i)]);
5368 recvParticleGlobalIds[i].resize(recvCount[neighborDomain(i)]);
5369 }
5370 }
5371 sendReq.fill(MPI_REQUEST_NULL);
5372 MInt cnt = 0;
5373 for(MInt i = 0; i < noNeighborDomains(); i++) {
5374 if(sendCount[neighborDomain(i)] == 0) continue;
5375 MPI_Issend(&sendIds[i].front(), sendCount[neighborDomain(i)], MPI_LONG, neighborDomain(i), 78, mpiComm(),
5376 &sendReq[cnt], AT_, "sendIds[i].front()");
5377 cnt++;
5378 }
5379 for(MInt i = 0; i < noNeighborDomains(); i++) {
5380 if(recvCount[neighborDomain(i)] == 0) continue;
5381 MPI_Recv(&recvIds[i].front(), recvCount[neighborDomain(i)], MPI_LONG, neighborDomain(i), 78, mpiComm(),
5382 MPI_STATUS_IGNORE, AT_, "recvIds[i].front()");
5383 }
5384 if(cnt > 0) MPI_Waitall(cnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
5385 sendReq.fill(MPI_REQUEST_NULL);
5386 cnt = 0;
5387 for(MInt i = 0; i < noNeighborDomains(); i++) {
5388 if(sendCount[neighborDomain(i)] == 0) continue;
5389 MPI_Issend(&sendVars[i].front(), dataSize * sendCount[neighborDomain(i)], MPI_DOUBLE, neighborDomain(i), 79,
5390 mpiComm(), &sendReq[cnt], AT_, "sendVars[i].front()");
5391 cnt++;
5392 }
5393 for(MInt i = 0; i < noNeighborDomains(); i++) {
5394 if(recvCount[neighborDomain(i)] == 0) continue;
5395 MPI_Recv(&recvVars[i].front(), dataSize * recvCount[neighborDomain(i)], MPI_DOUBLE, neighborDomain(i), 79,
5396 mpiComm(), MPI_STATUS_IGNORE, AT_, "recvVars[i].front()");
5397 }
5398 if(cnt > 0) MPI_Waitall(cnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
5399 sendReq.fill(MPI_REQUEST_NULL);
5400 cnt = 0;
5401 for(MInt i = 0; i < noNeighborDomains(); i++) {
5402 if(sendCount[neighborDomain(i)] == 0) continue;
5403 MPI_Issend(&sendParticleGlobalIds[i].front(), sendCount[neighborDomain(i)], MPI_INT, neighborDomain(i), 80,
5404 mpiComm(), &sendReq[cnt], AT_, "sendParticleGlobalIds[i].front()");
5405 cnt++;
5406 }
5407 for(MInt i = 0; i < noNeighborDomains(); i++) {
5408 if(recvCount[neighborDomain(i)] == 0) continue;
5409 MPI_Recv(&recvParticleGlobalIds[i].front(), recvCount[neighborDomain(i)], MPI_INT, neighborDomain(i), 80,
5410 mpiComm(), MPI_STATUS_IGNORE, AT_, "recvParticleGlobalIds[i].front()");
5411 }
5412
5413 if(cnt > 0) MPI_Waitall(cnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
5414
5415 vector<MFloat> tmpCoord;
5416 vector<MFloat> tmpVel;
5417 vector<MFloat> tmpTemp;
5418 vector<MFloat> tmpHeat;
5419 vector<MFloat> tmpAcc;
5420 vector<MFloat> tmpCoordsInitial;
5421 vector<MFloat> tmpQuat;
5422 vector<MFloat> tmpAngVel;
5423 vector<MFloat> tmpAngAcc;
5424 vector<MFloat> tmpShape;
5425 vector<MFloat> tmpRad;
5426 vector<MInt> tmpLink;
5427 vector<MInt> tmpParticleGlobalId;
5428
5429 tmpCoord.clear();
5430 tmpVel.clear();
5431 tmpTemp.clear();
5432 tmpHeat.clear();
5433 tmpAcc.clear();
5434 tmpLink.clear();
5435 tmpQuat.clear();
5436 tmpAngVel.clear();
5437 tmpAngAcc.clear();
5438 tmpShape.clear();
5439 tmpRad.clear();
5440 tmpParticleGlobalId.clear();
5441
5442 for(MInt p = 0; p < m_noPointParticlesLocal; p++) {
5443 if(m_particleCellLink[p] > -1) {
5444 tmpLink.push_back(m_particleCellLink[p]);
5445 for(MInt i = 0; i < 3; i++)
5446 tmpCoord.push_back(m_particleCoords[nDim * p + i]);
5447 for(MInt i = 0; i < 3; i++)
5448 tmpVel.push_back(m_particleVelocity[nDim * p + i]);
5449 for(MInt i = 0; i < 3; i++)
5450 tmpAcc.push_back(m_particleAcceleration[nDim * p + i]);
5451 for(MInt i = 0; i < 4; i++)
5452 tmpQuat.push_back(m_particleQuaternions[4 * p + i]);
5453 for(MInt i = 0; i < 3; i++)
5454 tmpAngVel.push_back(m_particleAngularVelocity[3 * p + i]);
5455 for(MInt i = 0; i < 3; i++)
5456 tmpAngAcc.push_back(m_particleAngularAcceleration[3 * p + i]);
5457 for(MInt i = 0; i < 4; i++)
5458 tmpShape.push_back(m_particleShapeParams[4 * p + i]);
5459 for(MInt i = 0; i < 3; i++)
5460 tmpRad.push_back(m_particleRadii[3 * p + i]);
5461 tmpTemp.push_back(m_particleTemperature[p]);
5462 tmpHeat.push_back(m_particleHeatFlux[p]);
5463 tmpParticleGlobalId.push_back(m_particleGlobalId[p]);
5464 }
5465 }
5466
5467 m_particleCellLink = tmpLink;
5468 m_particleCoords = tmpCoord;
5469 m_particleVelocity = tmpVel;
5470 m_particleTemperature = tmpTemp;
5471 m_particleHeatFlux = tmpHeat;
5472 m_particleAcceleration = tmpAcc;
5473 m_particleQuaternions = tmpQuat;
5474 m_particleAngularVelocity = tmpAngVel;
5475 m_particleAngularAcceleration = tmpAngAcc;
5476 m_particleShapeParams = tmpShape;
5477 m_particleRadii = tmpRad;
5478 m_particleGlobalId = tmpParticleGlobalId;
5479
5480 for(MInt i = 0; i < noNeighborDomains(); i++) {
5481 for(MInt k = 0; k < recvCount[neighborDomain(i)]; k++) {
5482 if(globalToLocal.count(recvIds[i][k]) == 0) mTerm(1, AT_, "Global id invalid " + to_string(recvIds[i][k]));
5483 MInt cellId = globalToLocal[recvIds[i][k]];
5484 if(cellId < 0 || cellId >= a_noCells() || c_globalId(cellId) != recvIds[i][k]) {
5485 cerr << cellId << " " << c_globalId(cellId) << " " << recvIds[i][k] << endl;
5486 mTerm(1, AT_,
5487 "Global id mismatch " + to_string(cellId) + " " + to_string(c_globalId(cellId)) + " "
5488 + to_string(recvIds[i][k]));
5489 }
5490 m_particleCellLink.push_back(cellId);
5491 MInt id = 0;
5492
5493 for(MInt j = 0; j < 3; j++) {
5494 m_particleCoords.push_back(a_coordinate(cellId, j) + recvVars[i][dataSize * k + id]);
5495 id++;
5496 }
5497 for(MInt j = 0; j < 3; j++) {
5498 m_particleVelocity.push_back(recvVars[i][dataSize * k + id]);
5499 id++;
5500 }
5501 for(MInt j = 0; j < 3; j++) {
5502 m_particleAcceleration.push_back(recvVars[i][dataSize * k + id]);
5503 id++;
5504 }
5505 for(MInt j = 0; j < 4; j++) {
5506 m_particleQuaternions.push_back(recvVars[i][dataSize * k + id]);
5507 id++;
5508 }
5509 for(MInt j = 0; j < 3; j++) {
5510 m_particleAngularVelocity.push_back(recvVars[i][dataSize * k + id]);
5511 id++;
5512 }
5513 for(MInt j = 0; j < 3; j++) {
5514 m_particleAngularAcceleration.push_back(recvVars[i][dataSize * k + id]);
5515 id++;
5516 }
5517 for(MInt j = 0; j < 4; j++) {
5518 m_particleShapeParams.push_back(recvVars[i][dataSize * k + id]);
5519 id++;
5520 }
5521 for(MInt j = 0; j < 3; j++) {
5522 m_particleRadii.push_back(recvVars[i][dataSize * k + id]);
5523 id++;
5524 }
5525 m_particleTemperature.push_back(recvVars[i][dataSize * k + id]);
5526 id++;
5527 m_particleHeatFlux.push_back(recvVars[i][dataSize * k + id]);
5528 id++;
5529 m_particleGlobalId.push_back(recvParticleGlobalIds[i][k]);
5530 }
5531 }
5532
5533 m_fvBndryCnd->rerecorrectCellCoordinates();
5534
5535 m_noPointParticlesLocal = (signed)m_particleCellLink.size();
5536 m_particleAccelerationDt1 = m_particleAcceleration;
5537 m_particleVelocityDt1 = m_particleVelocity;
5538 m_particleTemperatureDt1 = m_particleTemperature;
5539 m_particleCoordsDt1 = m_particleCoords;
5540 m_particleAngularAccelerationDt1 = m_particleAngularAcceleration;
5541 m_particleAngularVelocityDt1 = m_particleAngularVelocity;
5542 m_particleQuaternionsDt1 = m_particleQuaternions;
5543 m_particleVelocityFluid.resize(m_particleVelocity.size());
5544 m_particleFluidTemperature.resize(m_particleTemperature.size());
5545 m_particleVelocityGradientFluid.resize(nDim * m_particleVelocityFluid.size());
5546
5547 if(m_noPointParticles == 1) {
5548 for(MInt p = 0; p < m_noPointParticlesLocal; p++) {
5549 cerr << domainId() << ": particle " << globalTimeStep << " / " << m_particleCoords[nDim * p] << " "
5550 << m_particleCoords[nDim * p + 1] << " " << m_particleCoords[nDim * p + 2] << " / "
5551 << m_particleVelocity[nDim * p] << " " << m_particleVelocity[nDim * p + 1] << " "
5552 << m_particleVelocity[nDim * p + 2] << "/ " << m_particleTemperature[p] << "/ " << m_particleHeatFlux[p]
5553 << endl;
5554 }
5555 }
5556 }
5557}
5558
5559
5564template <MInt nDim, class SysEqn>
5566 TRACE();
5567
5568 if(!m_dualTimeStepping) {
5569 m_physicalTimeDt1 = m_physicalTime;
5570 m_physicalTime += timeStep();
5571 }
5572
5573 m_time += timeStep() * m_timeRef;
5574 m_RKStep = 0;
5575}
5576
5581template <MInt nDim, class SysEqn>
5583 TRACE();
5584
5585 MFloat dummyCoord[3];
5586 const MFloat cellHalfLength = F1B2 * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
5587 const MFloat limitDistance = F2 * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
5588 const MFloat nodeStencil[3][8] = {
5589 {-F1, F1, -F1, F1, -F1, F1, -F1, F1}, {-F1, -F1, F1, F1, -F1, -F1, F1, F1}, {-F1, -F1, -F1, -F1, F1, F1, F1, F1}};
5590 const MInt dirStencil[8][3] = {{0, 0, 0}, {1, 0, 0}, {0, 1, 0}, {1, 1, 0},
5591 {0, 0, 1}, {1, 0, 1}, {0, 1, 1}, {1, 1, 1}};
5592
5593 m_bndryCandidateIds.resize(a_noCells());
5594 for(MInt c = 0; c < a_noCells(); c++)
5595 m_bndryCandidateIds[c] = -1;
5596 m_bndryCandidates.clear();
5597 m_candidateNodeSet.clear();
5598 m_candidateNodeValues.clear();
5599 m_noBndryCandidates = 0;
5600
5601 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
5602 const MInt cellId = m_bndryLayerCells[c];
5603
5604 if(a_level(cellId) < m_lsCutCellMinLevel || !c_isLeafCell(cellId)) continue;
5605
5606 ASSERT(m_bodyTypeMb > 0, "");
5607 MFloat phi = a_levelSetValuesMb(cellId, 0);
5608
5609 m_bndryCandidateIds[cellId] = -1;
5610 MInt candidate = -1;
5611 if(fabs(phi) < limitDistance) {
5612 candidate = m_noBndryCandidates;
5613 m_bndryCandidates.push_back(cellId);
5614 m_bndryCandidateIds[cellId] = candidate;
5615 m_noBndryCandidates++;
5616 }
5617 }
5618 m_candidateNodeSet.resize(m_noBndryCandidates * m_noCellNodes);
5619 m_candidateNodeValues.resize(m_noLevelSetsUsedForMb * m_noBndryCandidates * m_noCellNodes);
5620 for(MInt candidate = 0; candidate < m_noBndryCandidates; candidate++) {
5621 for(MInt node = 0; node < m_noCellNodes; node++) {
5622 m_candidateNodeSet[candidate * m_noCellNodes + node] = false;
5623 }
5624 }
5625
5626 for(MInt candidate = 0; candidate < m_noBndryCandidates; candidate++) {
5627 MInt cellId = m_bndryCandidates[candidate];
5628
5629 for(MInt node = 0; node < m_noCellNodes; node++) {
5630 if(m_candidateNodeSet[candidate * m_noCellNodes + node]) continue;
5631 for(MInt i = 0; i < nDim; i++) {
5632 dummyCoord[i] = a_coordinate(cellId, i) + nodeStencil[i][node] * cellHalfLength;
5633 }
5634 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
5635 const MInt b = a_associatedBodyIds(cellId, set);
5636 MFloat phi = m_bodyDistThreshold + 1e-14;
5637 if(b > -1) {
5638 phi = getDistance(&dummyCoord[0], b);
5639 }
5640 m_candidateNodeValues[IDX_LSSETNODES(candidate, node, set)] = phi;
5641 }
5642 m_candidateNodeSet[candidate * m_noCellNodes + node] = true;
5643
5644 // update neighbor candidates
5645 for(MInt i = 0; i < nDim; i++) {
5646 MInt dir0 = 2 * i + dirStencil[node][i];
5647 if(a_hasNeighbor(cellId, dir0) == 0) continue;
5648 MInt nghbrId0 = c_neighborId(cellId, dir0);
5649 MInt n0 = (dirStencil[node][i] == 0) ? node + IPOW2(i) : node - IPOW2(i);
5650 MInt cand0 = m_bndryCandidateIds[nghbrId0];
5651 if(cand0 > -1) {
5652 MBool match = true;
5653 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
5654 if(a_associatedBodyIds(nghbrId0, set) == a_associatedBodyIds(cellId, set)) {
5655 m_candidateNodeValues[IDX_LSSETNODES(cand0, n0, set)] =
5656 m_candidateNodeValues[IDX_LSSETNODES(candidate, node, set)];
5657 } else
5658 match = false;
5659 }
5660 if(match) m_candidateNodeSet[cand0 * m_noCellNodes + n0] = true;
5661 }
5662 for(MInt j = i + 1; j < nDim; j++) {
5663 MInt dir1 = 2 * j + dirStencil[node][j];
5664 if(a_hasNeighbor(nghbrId0, dir1) == 0) continue;
5665 MInt nghbrId1 = c_neighborId(nghbrId0, dir1);
5666 MInt n1 = (dirStencil[node][j] == 0) ? n0 + IPOW2(j) : n0 - IPOW2(j);
5667 MInt cand1 = m_bndryCandidateIds[nghbrId1];
5668 if(cand1 > -1) {
5669 MBool match = true;
5670 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
5671 if(a_associatedBodyIds(nghbrId1, set) == a_associatedBodyIds(cellId, set)) {
5672 m_candidateNodeValues[IDX_LSSETNODES(cand1, n1, set)] =
5673 m_candidateNodeValues[IDX_LSSETNODES(candidate, node, set)];
5674 } else
5675 match = false;
5676 }
5677 if(match) m_candidateNodeSet[cand1 * m_noCellNodes + n1] = true;
5678 }
5679 for(MInt k = j + 1; k < nDim; k++) {
5680 MInt dir2 = 2 * k + dirStencil[node][k];
5681 if(a_hasNeighbor(nghbrId1, dir2) == 0) continue;
5682 MInt nghbrId2 = c_neighborId(nghbrId1, dir2);
5683 MInt n2 = (dirStencil[node][k] == 0) ? n1 + IPOW2(k) : n1 - IPOW2(k);
5684 MInt cand2 = m_bndryCandidateIds[nghbrId2];
5685 if(cand2 > -1) {
5686 MBool match = true;
5687 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
5688 if(a_associatedBodyIds(nghbrId2, set) == a_associatedBodyIds(cellId, set)) {
5689 m_candidateNodeValues[IDX_LSSETNODES(cand2, n2, set)] =
5690 m_candidateNodeValues[IDX_LSSETNODES(candidate, node, set)];
5691 } else
5692 match = false;
5693 }
5694 if(match) m_candidateNodeSet[cand2 * m_noCellNodes + n2] = true;
5695 }
5696 }
5697 }
5698 }
5699 }
5700 }
5701}
5702
5703
5713template <MInt nDim, class SysEqn>
5715 TRACE();
5716
5717 ASSERT(!m_constructGField, "");
5718
5719 for(MInt cnd = 0; cnd < m_noBndryCandidates; cnd++) {
5720 m_bndryCandidateIds[m_bndryCandidates[cnd]] = -1;
5721 }
5722
5723 m_bndryCandidateIds.resize(a_noCells());
5724 m_bndryCandidates.clear();
5725 m_noBndryCandidates = 0;
5726
5727 const MFloat limitDistance = F2 * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
5728
5729 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
5730 const MInt cellId = m_bndryLayerCells[c];
5731 if(a_bndryId(cellId) < -1) continue;
5732 if(cellId >= a_noCells()) continue;
5733 if(fabs(a_levelSetValuesMb(cellId, 0)) < limitDistance
5734 && a_level(cellId) >= m_lsCutCellMinLevel && c_noChildren(cellId) == 0 && !a_isHalo(cellId)) {
5735 m_bndryCandidates.push_back(cellId);
5736 m_bndryCandidateIds[cellId] = m_noBndryCandidates;
5737 m_noBndryCandidates++;
5738 } else {
5739 m_bndryCandidateIds[cellId] = -1;
5740 // instead of candidates take g0 cells --> no, g0 cells can exlude bndry cell!
5741 // solution: make sure g0 neighbour cell stores cutpoint for those cells !
5742 }
5743 }
5744
5745 ASSERT(m_bndryCandidates.size() <= m_bndryLayerCells.size(), "");
5746 ASSERT(m_noBndryCandidates == (signed)m_bndryCandidates.size(), "");
5747
5748 for(MInt cnd = 0; cnd < m_noBndryCandidates; cnd++) {
5749 ASSERT(cnd == m_bndryCandidateIds[m_bndryCandidates[cnd]],
5750 to_string(cnd) + " " + to_string(m_bndryCandidates[cnd]) + " "
5751 + to_string(m_bndryCandidateIds[m_bndryCandidates[cnd]]) + " "
5752 + to_string(a_isHalo(m_bndryCandidates[cnd])));
5753 }
5754}
5755
5756
5761template <MInt nDim, class SysEqn>
5763 TRACE();
5764
5765 MBool gapClosure = false;
5766 if(m_levelSet && m_closeGaps && (m_gapInitMethod > 0 || nDim == 3)) {
5767 gapClosure = true;
5768 }
5769
5770 // fill cutCandidates-Information!
5771 m_cutCandidates.clear();
5772
5773 for(MInt cnd = 0; cnd < m_noBndryCandidates; cnd++) {
5774 const MInt cellId = m_bndryCandidates[cnd];
5775 ASSERT(!a_isHalo(cellId), "");
5776 m_cutCandidates.emplace_back();
5777 m_cutCandidates[cnd].cellId = cellId;
5778 }
5779
5780
5781 MBoolScratchSpace isGapCell(a_noCells(), AT_, "isGapCell");
5782 isGapCell.fill(false);
5783 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
5784 if(a_isGapCell(cellId)) isGapCell[cellId] = true;
5785 }
5786
5787 m_geometryIntersection->computeNodalValues(m_cutCandidates, &m_bndryCandidateIds[0], &a_levelSetValuesMb(0, 0),
5788 &a_associatedBodyIds(0, 0), &isGapCell(0), gapClosure);
5789
5790 ASSERT((signed)m_cutCandidates.size() == m_noBndryCandidates, "");
5791
5792 ScratchSpace<const MInt*> p_maxLevelWindowCells(noNeighborDomains(), AT_, "p_maxLevelWindowCells");
5793 ScratchSpace<const MInt*> p_maxLevelHaloCells(noNeighborDomains(), AT_, "p_maxLevelHaloCells");
5794
5795 for(MInt d = 0; d < noNeighborDomains(); d++) {
5796 p_maxLevelWindowCells[d] = m_maxLevelWindowCells[d];
5797 p_maxLevelHaloCells[d] = m_maxLevelHaloCells[d];
5798 }
5799
5800 m_geometryIntersection->exchangeNodalValues(p_maxLevelWindowCells.data(), &m_noMaxLevelWindowCells[0],
5801 p_maxLevelHaloCells.data(), m_cutCandidates, &m_bndryCandidateIds[0]);
5802
5803 // Azimuthal periodicity
5804 if(grid().azimuthalPeriodicity()) {
5805 computeAzimuthalHaloNodalValues();
5806 }
5807
5808 ASSERT((signed)m_cutCandidates.size() >= m_noBndryCandidates, "");
5809
5810 // fill fv-solver-structre
5811 m_noBndryCandidates = (signed)m_cutCandidates.size();
5812 m_bndryCandidates.clear();
5813
5814 m_candidateNodeSet.resize(m_noBndryCandidates * m_noCellNodes);
5815 m_candidateNodeValues.resize(m_noLevelSetsUsedForMb * m_noBndryCandidates * m_noCellNodes);
5816
5817 for(MInt cnd = 0; cnd < m_noBndryCandidates; cnd++) {
5818 const MInt cellId = m_cutCandidates[cnd].cellId;
5819 ASSERT(!m_cutCandidates[cnd].isbndryLvlJumpParent, "");
5820
5821 m_bndryCandidates.push_back(cellId);
5822
5823 for(MInt node = 0; node < m_noCellNodes; node++) {
5824 m_candidateNodeSet[cnd * m_noCellNodes + node] = m_cutCandidates[cnd].nodeValueSet[node];
5825 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
5826 m_candidateNodeValues[IDX_LSSETNODES(cnd, node, set)] = m_cutCandidates[cnd].nodalValues[set][node];
5827 }
5828 }
5829 m_bndryCandidateIds[cellId] = cnd;
5830 }
5831}
5832
5837template <MInt nDim, class SysEqn>
5839 TRACE();
5840
5841 MBool gapClosure = false;
5842 if(m_levelSet && m_closeGaps && (m_gapInitMethod > 0 || nDim == 3)) {
5843 gapClosure = true;
5844 }
5845 if(gapClosure) ASSERT(false, "Are you sure? AzimuthalPer with gapClosing is untested!");
5846
5847 const MFloat limitDistance = F2 * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
5848
5849 std::vector<MInt> azimuthalCandidateIds;
5850 std::vector<CutCandidate<nDim>> azimuthalCandidates;
5851 MInt noAzimuthalCandidates = 0;
5852
5853 azimuthalCandidateIds.assign(a_noCells(), -1);
5854 azimuthalCandidates.clear();
5855
5856 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
5857 for(MUint j = 0; j < m_azimuthalMaxLevelHaloCells[i].size(); j++) {
5858 const MInt cellId = m_azimuthalMaxLevelHaloCells[i][j];
5859 if(a_bndryId(cellId) < -1) continue;
5860 if(cellId >= a_noCells()) continue;
5861 if(fabs(a_levelSetValuesMb(cellId, 0)) < limitDistance && a_level(cellId) >= m_lsCutCellMinLevel) {
5862 azimuthalCandidates.emplace_back();
5863 azimuthalCandidates[noAzimuthalCandidates].cellId = cellId;
5864 azimuthalCandidateIds[cellId] = noAzimuthalCandidates;
5865 noAzimuthalCandidates++;
5866 } else {
5867 azimuthalCandidateIds[cellId] = -1;
5868 }
5869 }
5870 }
5871
5872 MBoolScratchSpace isGapCell(a_noCells(), AT_, "isGapCell");
5873 isGapCell.fill(false);
5874 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
5875 if(a_isGapCell(cellId)) isGapCell[cellId] = true;
5876 }
5877
5878 m_geometryIntersection->computeNodalValues(azimuthalCandidates, &azimuthalCandidateIds[0], &a_levelSetValuesMb(0, 0),
5879 &a_associatedBodyIds(0, 0), &isGapCell(0), gapClosure);
5880
5881 exchangeAzimuthalOuterNodalValues(azimuthalCandidates, azimuthalCandidateIds);
5882
5883 for(MUint i = 0; i < azimuthalCandidates.size(); i++) {
5884 // add halo-cutCandidate
5885 MInt cellId = azimuthalCandidates[i].cellId;
5886 const MInt candId = m_cutCandidates.size();
5887 m_cutCandidates.emplace_back();
5888 m_cutCandidates[candId].cellId = cellId;
5889
5890 // add infomation from computeNodalvalues:
5891 for(MInt node = 0; node < m_noCorners; node++) {
5892 m_cutCandidates[candId].nodeValueSet[node] = true;
5893 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
5894 m_cutCandidates[candId].nodalValues[set][node] = azimuthalCandidates[i].nodalValues[set][node];
5895 }
5896 }
5897 m_cutCandidates[candId].isGapCell = azimuthalCandidates[i].isGapCell;
5898
5899 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
5900 m_cutCandidates[candId].associatedBodyIds[set] = azimuthalCandidates[i].associatedBodyIds[set];
5901 }
5902
5903 m_bndryCandidateIds[cellId] = candId;
5904 }
5905}
5906
5911template <MInt nDim, class SysEqn>
5913 std::vector<MInt>& candidateIds) {
5914 TRACE();
5915
5916 const MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
5917 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
5918 const MInt nodeStencil[3][8] = {{0, 1, 0, 1, 0, 1, 0, 1}, {2, 2, 3, 3, 2, 2, 3, 3}, {4, 4, 4, 4, 5, 5, 5, 5}};
5919 const MInt reverseNode[3][8] = {{1, 0, 3, 2, 5, 4, 7, 6}, {2, 3, 0, 1, 6, 7, 4, 5}, {4, 5, 6, 7, 0, 1, 2, 3}};
5920
5921
5922 MIntScratchSpace notGradientIds(a_noCells(), AT_, "notGradientIds");
5923 notGradientIds.fill(-1);
5924 MUint noAzimuthalHalos = maia::mpi::getBufferSize(m_azimuthalMaxLevelHaloCells);
5925 MIntScratchSpace notGradientCells(noAzimuthalHalos, AT_, "notGradientCells");
5926 MIntScratchSpace notGradientDomain(noAzimuthalHalos, AT_, "notGradientDomain");
5927 MIntScratchSpace notGradientOffset(noAzimuthalHalos, AT_, "notGradientOffset");
5928 MInt notGradientCntr = 0;
5929 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
5930 for(MUint j = 0; j < m_azimuthalMaxLevelHaloCells[i].size(); j++) {
5931 MInt cellId = m_azimuthalMaxLevelHaloCells[i][j];
5932 if(candidateIds[cellId] < 0) continue;
5933 notGradientCells[notGradientCntr] = cellId;
5934 notGradientDomain[notGradientCntr] = i;
5935 notGradientOffset[notGradientCntr] = j;
5936 notGradientIds[cellId] = notGradientCntr;
5937 notGradientCntr++;
5938 }
5939 }
5940
5941 MIntScratchSpace notGradientCorners(notGradientCntr * m_noCorners, AT_, "notGradientCorners");
5942 notGradientCorners.fill(-2);
5943
5944 MInt outerCnt = notGradientCntr * m_noCorners * (nDim + 1);
5945 MFloatScratchSpace outerNodes(outerCnt, AT_, "outerNodes");
5946 outerNodes.fill(F0);
5947 outerCnt = 0;
5948
5949 MIntScratchSpace sndSize(grid().noAzimuthalNeighborDomains(), AT_, "sndSize");
5950 sndSize.fill(0);
5951
5952 MFloat angle = grid().azimuthalAngle();
5953
5954 const MInt maxNoNghbrs = 56; // IPOW3[nDim];
5955 MIntScratchSpace nghbrList(maxNoNghbrs, AT_, "nghbrList");
5956 MIntScratchSpace nghbrNodes(maxNoNghbrs, AT_, "nghbrNodes");
5957 // MIntScratchSpace layerId(maxNoNghbrs, AT_, "layerList");
5958 nghbrList.fill(-1);
5959 nghbrNodes.fill(-1);
5960 MFloatScratchSpace nodalValue(m_noLevelSetsUsedForMb, AT_, "nodalValue");
5961 MFloat corner[nDim];
5962 for(MInt i = 0; i < notGradientCntr; i++) {
5963 MInt cellId = notGradientCells[i];
5964
5965 MFloat cellHalfLength = F1B2 * c_cellLengthAtCell(cellId);
5966 MInt counter;
5967 for(MInt node = 0; node < m_noCorners; node++) {
5968 counter = 0;
5969 if(notGradientCorners[i * m_noCorners + node] > -2) continue;
5970 MBool isOuter = true;
5971 nghbrList[counter] = cellId;
5972 nghbrNodes[counter] = node;
5973 counter++;
5974
5975 for(MInt d0 = 0; d0 < nDim; d0++) {
5976 MInt dir0 = nodeStencil[d0][node];
5977 MInt nghbrId0 = c_neighborId(cellId, dir0);
5978 if(nghbrId0 < 0) {
5979 MInt parentId = c_parentId(cellId);
5980 if(parentId > -1) nghbrId0 = c_neighborId(parentId, dir0);
5981 }
5982 if(nghbrId0 < 0) continue;
5983 nghbrList[counter] = nghbrId0;
5984 nghbrNodes[counter] = reverseNode[d0][node];
5985 counter++;
5986 for(MInt d1 = 0; d1 < nDim; d1++) {
5987 if(d1 == d0) continue;
5988 MInt dir1 = nodeStencil[d1][node];
5989 MInt nghbrId1 = c_neighborId(nghbrId0, dir1);
5990 if(nghbrId1 < 0) {
5991 MInt parentId = c_parentId(nghbrId0);
5992 if(parentId > -1) nghbrId1 = c_neighborId(parentId, dir1);
5993 }
5994 if(nghbrId1 < 0) continue;
5995 nghbrList[counter] = nghbrId1;
5996 nghbrNodes[counter] = reverseNode[d1][reverseNode[d0][node]];
5997 counter++;
5998 for(MInt d2 = 0; d2 < nDim; d2++) {
5999 if((d2 == d0) || (d2 == d1)) continue;
6000 MInt dir2 = nodeStencil[d2][node];
6001 MInt nghbrId2 = c_neighborId(nghbrId1, dir2);
6002 if(nghbrId2 < 0) {
6003 MInt parentId = c_parentId(nghbrId1);
6004 if(parentId > -1) nghbrId2 = c_neighborId(parentId, dir2);
6005 }
6006 if(nghbrId2 < 0) continue;
6007 nghbrList[counter] = nghbrId2;
6008 nghbrNodes[counter] = reverseNode[d2][reverseNode[d1][reverseNode[d0][node]]];
6009 counter++;
6010 }
6011 }
6012 }
6013
6014 for(MInt n = 0; n < counter; n++) {
6015 MInt nghbrId = nghbrList[n];
6016 if(!a_isPeriodic(nghbrId) && m_bndryCandidateIds[nghbrId] > 1) {
6017 isOuter = false;
6018 MInt nghbrNode = nghbrNodes[n];
6019 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6020 nodalValue[set] = m_cutCandidates[m_bndryCandidateIds[nghbrId]].nodalValues[set][nghbrNode];
6021 }
6022 break;
6023 }
6024 }
6025
6026 if(isOuter) {
6027 outerNodes[outerCnt * (nDim + 1)] = (MFloat)notGradientOffset[i];
6028 for(MInt d = 0; d < nDim; d++) {
6029 corner[d] = c_coordinate(cellId, d) + signStencil[node][d] * cellHalfLength;
6030 }
6031 MInt side = grid().determineAzimuthalBoundarySide(corner);
6032 grid().rotateCartesianCoordinates(corner, (side * angle));
6033 std::copy_n(&corner[0], nDim, &outerNodes[outerCnt * (nDim + 1) + 1]);
6034 sndSize[notGradientDomain[i]]++;
6035
6036 for(MInt n = 0; n < counter; n++) {
6037 MInt nghbrId = nghbrList[n];
6038 MInt nId = notGradientIds[nghbrId];
6039 if(nId > -1) {
6040 MInt nghbrNode = nghbrNodes[n];
6041 notGradientCorners[nId * m_noCorners + nghbrNode] = outerCnt;
6042 }
6043 }
6044 outerCnt++;
6045 } else {
6046 for(MInt n = 0; n < counter; n++) {
6047 MInt nghbrId = nghbrList[n];
6048 MInt cndId = candidateIds[nghbrId];
6049 MInt nghbrNode = nghbrNodes[n];
6050 MInt nId = notGradientIds[nghbrId];
6051 if(cndId > -1) {
6052 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6053 candidates[cndId].nodalValues[set][nghbrNode] = nodalValue[set];
6054 }
6055 }
6056 if(nId > -1) {
6057 notGradientCorners[nId * m_noCorners + nghbrNode] = -1;
6058 }
6059 }
6060 }
6061 }
6062 }
6063
6064 ScratchSpace<MPI_Request> mpi_send_req(grid().noAzimuthalNeighborDomains(), AT_, "mpi_send_req");
6065 ScratchSpace<MPI_Request> mpi_recv_req(grid().noAzimuthalNeighborDomains(), AT_, "mpi_recv_req");
6066 MIntScratchSpace rcvSize(grid().noAzimuthalNeighborDomains(), AT_, "rcvBuffSize");
6067
6068 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6069 MPI_Irecv(&rcvSize[i], 1, MPI_INT, grid().azimuthalNeighborDomain(i), 2, grid().mpiComm(), &mpi_recv_req[i], AT_,
6070 "rcvSize[i]");
6071 }
6072 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6073 MPI_Isend(&sndSize[i], 1, MPI_INT, grid().azimuthalNeighborDomain(i), 2, grid().mpiComm(), &mpi_send_req[i], AT_,
6074 "sndSize[i]");
6075 }
6076 MPI_Waitall(grid().noAzimuthalNeighborDomains(), &mpi_recv_req[0], MPI_STATUSES_IGNORE, AT_);
6077 MPI_Waitall(grid().noAzimuthalNeighborDomains(), &mpi_send_req[0], MPI_STATUSES_IGNORE, AT_);
6078
6079 MInt sndNodeCnt = 0;
6080 MInt rcvNodeCnt = 0;
6081 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6082 sndNodeCnt += sndSize[i];
6083 rcvNodeCnt += rcvSize[i];
6084 }
6085
6086 MInt fac = mMax((nDim + 1), m_noLevelSetsUsedForMb);
6087 MFloatScratchSpace rcvBuffers(mMax(sndNodeCnt, rcvNodeCnt) * fac, AT_, "rcvBuffers");
6088 MFloatScratchSpace sndBuffers(rcvNodeCnt * m_noLevelSetsUsedForMb, AT_, "sndBuffers");
6089
6090 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6091 mpi_send_req[i] = MPI_REQUEST_NULL;
6092 mpi_recv_req[i] = MPI_REQUEST_NULL;
6093 }
6094
6095 MInt offset = 0;
6096 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6097 if(rcvSize[i] > 0) {
6098 MInt bufSize = (nDim + 1) * rcvSize[i];
6099 MPI_Irecv(&rcvBuffers[offset], bufSize, MPI_DOUBLE, grid().azimuthalNeighborDomain(i), 2, grid().mpiComm(),
6100 &mpi_recv_req[i], AT_, "rcvBuffers[offset]");
6101 offset += bufSize;
6102 }
6103 }
6104
6105 offset = 0;
6106 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6107 if(sndSize[i] > 0) {
6108 MInt bufSize = (nDim + 1) * sndSize[i];
6109 MPI_Isend(&outerNodes[offset], bufSize, MPI_DOUBLE, grid().azimuthalNeighborDomain(i), 2, grid().mpiComm(),
6110 &mpi_send_req[i], AT_, "outerNodes[offset]");
6111 offset += bufSize;
6112 }
6113 }
6114
6115 MPI_Waitall(grid().noAzimuthalNeighborDomains(), &mpi_recv_req[0], MPI_STATUSES_IGNORE, AT_);
6116 MPI_Waitall(grid().noAzimuthalNeighborDomains(), &mpi_send_req[0], MPI_STATUSES_IGNORE, AT_);
6117
6118 std::function<MBool(const MInt, const MInt)> neighborCheck = [&](const MInt cellId, const MInt id) {
6119 return static_cast<MBool>(grid().tree().hasNeighbor(cellId, id));
6120 };
6121 std::function<MFloat(const MInt, const MInt)> coordinate = [&](const MInt cellId, const MInt id) {
6122 return static_cast<MFloat>(c_coordinate(cellId, id));
6123 };
6124
6125 offset = 0;
6126 MFloat eps = F1 + pow(10, -12);
6127 MInt interpolationCells[8] = {0, 0, 0, 0, 0, 0, 0, 0};
6128 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6129 for(MInt j = 0; j < rcvSize[i]; j++) {
6130 MInt cellId = m_azimuthalMaxLevelWindowCells[i][(MInt)rcvBuffers[(offset + j) * (nDim + 1)]];
6131 for(MInt d = 0; d < nDim; d++) {
6132 corner[d] = rcvBuffers[(offset + j) * (nDim + 1) + 1 + d];
6133 }
6134 if(!this->inCell(cellId, corner, eps)) {
6135 MInt counter = grid().getAdjacentGridCells(cellId, 1, nghbrList, a_level(cellId), 2);
6136 for(MInt n = 0; n < counter; n++) {
6137 MInt nghbrId = nghbrList[n];
6138 if(this->inCell(nghbrId, corner, eps)) {
6139 cellId = nghbrId;
6140 break;
6141 }
6142 }
6143 }
6144 ASSERT(this->inCell(cellId, corner, eps), "Coordindate not in cell!");
6145 MInt position = -1;
6146 position = this->setUpInterpolationStencil(cellId, interpolationCells, corner, neighborCheck, false);
6147 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6148 if(position > -1) {
6149 MFloat phi = interpolateLevelSet(interpolationCells, corner, set);
6150 sndBuffers[(offset + j) * m_noLevelSetsUsedForMb + set] = phi;
6151 } else {
6152 sndBuffers[(offset + j) * m_noLevelSetsUsedForMb + set] = a_levelSetValuesMb(cellId, set);
6153 }
6154 }
6155 }
6156 offset += rcvSize[i];
6157 }
6158
6159 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6160 mpi_send_req[i] = MPI_REQUEST_NULL;
6161 mpi_recv_req[i] = MPI_REQUEST_NULL;
6162 }
6163
6164
6165 offset = 0;
6166 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6167 if(sndSize[i] > 0) {
6168 MInt bufSize = m_noLevelSetsUsedForMb * sndSize[i];
6169 MPI_Irecv(&rcvBuffers[offset], bufSize, MPI_DOUBLE, grid().azimuthalNeighborDomain(i), 2, grid().mpiComm(),
6170 &mpi_recv_req[i], AT_, "rcvBuffers[offset]");
6171 offset += bufSize;
6172 }
6173 }
6174
6175 offset = 0;
6176 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
6177 if(rcvSize[i] > 0) {
6178 MInt bufSize = m_noLevelSetsUsedForMb * rcvSize[i];
6179 MPI_Isend(&sndBuffers[offset], bufSize, MPI_DOUBLE, grid().azimuthalNeighborDomain(i), 2, grid().mpiComm(),
6180 &mpi_send_req[i], AT_, "sndBuffers[offset]");
6181 offset += bufSize;
6182 }
6183 }
6184
6185 MPI_Waitall(grid().noAzimuthalNeighborDomains(), &mpi_recv_req[0], MPI_STATUSES_IGNORE, AT_);
6186 MPI_Waitall(grid().noAzimuthalNeighborDomains(), &mpi_send_req[0], MPI_STATUSES_IGNORE, AT_);
6187
6188 for(MInt i = 0; i < notGradientCntr; i++) {
6189 MInt cellId = notGradientCells[i];
6190 MInt cndId = candidateIds[cellId];
6191 for(MInt node = 0; node < m_noCorners; node++) {
6192 if(notGradientCorners[i * m_noCorners + node] < 0) continue;
6193 offset = notGradientCorners[i * m_noCorners + node];
6194 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
6195 candidates[cndId].nodalValues[set][node] = rcvBuffers[offset * m_noLevelSetsUsedForMb + set];
6196 }
6197 }
6198 }
6199}
6200
6201
6202template <MInt nDim, class SysEqn>
6204 cerr0 << "initialize " << m_noPointParticles << " point particles." << endl;
6205
6206 MIntScratchSpace particleCheck(m_noPointParticles, AT_, "particleCheck");
6207 MFloat diameter = F1;
6208 MFloat beta = F1;
6220 diameter = Context::getSolverProperty<MFloat>("pointParticleDiameter", m_solverId, AT_);
6221 if(m_pointParticleType == 3) {
6233 beta = Context::getSolverProperty<MFloat>("pointParticleAspectRatio", m_solverId, AT_);
6234 }
6243 const int64_t seed0 = (int64_t)((Context::propertyExists("randomDeviceSeed", m_solverId))
6244 ? Context::getSolverProperty<MFloat>("randomDeviceSeed", m_solverId, AT_)
6245 : -1);
6246 const MUlong seed = (MUlong)((seed0 > -1) ? seed0 : std::random_device()());
6247 MUlong seed1 = seed;
6248 MPI_Bcast(&seed1, 1, MPI_UNSIGNED_LONG, 0, mpiComm(), AT_, "seed1");
6249 std::mt19937_64 gen(seed1);
6250 std::mt19937_64 gen2(seed1);
6251 // std::mt19937 gen(seed1);
6252 std::uniform_real_distribution<> distr(-F1B2, F1B2);
6253 std::uniform_real_distribution<> distr2(F0, F1);
6254 m_noPointParticlesLocal = 0;
6255 particleCheck.fill(0);
6256 unordered_map<MLong, MInt> hilbertToLocal;
6257 hilbertToLocal.reserve(noMinCells());
6258 MFloat sr = F0;
6259 MFloat tt1 = F0;
6260 MFloat tt2 = F0;
6261 MFloat coords[3] = {F0, F0, F0};
6262 for(MInt c = 0; c < noMinCells(); c++) {
6263 const MInt cellId = minCell(c);
6264 if(a_isHalo(cellId)) continue;
6265 MLong hilbertId = grid().raw().generateHilbertIndex(cellId);
6266 hilbertToLocal[hilbertId] = cellId;
6267 }
6268 for(MInt p = 0; p < m_noPointParticles; p++) {
6269 MBool outside = false;
6270 sr = distr2(gen2);
6271 tt1 = F2 * PI * distr2(gen2);
6272 tt2 = F2 * PI * distr2(gen2);
6273 for(MInt i = 0; i < nDim; i++) {
6274 coords[i] = distr(gen) * (m_bbox[nDim + i] - m_bbox[i]);
6275 if(coords[i] < m_bboxLocal[i] || coords[i] > m_bboxLocal[nDim + i]) outside = true;
6276 }
6277 if(outside) continue;
6278 const MFloat delta = c_cellLengthAtLevel(minLevel());
6279 MFloat projCords[3] = {F0, F0, F0};
6280 for(MInt i = 0; i < nDim; i++) {
6281 MInt div = (MInt)(coords[i] / delta);
6282 projCords[i] = (div > 0) ? (F1B2 + ((MFloat)div)) * delta : (-F1B2 + ((MFloat)div)) * delta;
6283 }
6284 MLong hilbertId = grid().raw().hilbertIndexGeneric(&projCords[0]);
6285 MInt linkedCell = -1;
6286 if(hilbertToLocal.count(hilbertId) > 0) {
6287 MInt cellId = hilbertToLocal[hilbertId];
6288 const MFloat cellHalfLength = F1B2 * c_cellLengthAtCell(cellId);
6289 MBool found = true;
6290 for(MInt i = 0; i < nDim; i++) {
6291 if((coords[i] < a_coordinate(cellId, i) - cellHalfLength)
6292 || (coords[i] > a_coordinate(cellId, i) + cellHalfLength)) {
6293 found = false;
6294 }
6295 }
6296 if(found) {
6297 linkedCell = cellId;
6298 }
6299 }
6300 if(linkedCell < 0) {
6301 for(MInt c = 0; c < noMinCells(); c++) {
6302 const MInt cellId = minCell(c);
6303 if(a_isHalo(cellId)) continue;
6304 const MFloat cellHalfLength = F1B2 * c_cellLengthAtCell(cellId);
6305 MBool found = true;
6306 for(MInt i = 0; i < nDim; i++) {
6307 if((coords[i] < a_coordinate(cellId, i) - cellHalfLength)
6308 || (coords[i] > a_coordinate(cellId, i) + cellHalfLength)) {
6309 found = false;
6310 }
6311 }
6312 if(found) {
6313 linkedCell = cellId;
6314 break;
6315 }
6316 }
6317 }
6318 if(linkedCell > -1) {
6319 for(MInt i = 0; i < 3; i++)
6320 m_particleCoords.push_back(coords[i]);
6321 for(MInt i = 0; i < 3; i++)
6322 m_particleVelocity.push_back(F0);
6323 for(MInt i = 0; i < 3; i++)
6324 m_particleVelocityFluid.push_back(F0);
6325 m_particleTemperature.push_back(F0);
6326 m_particleFluidTemperature.push_back(F0);
6327 m_particleHeatFlux.push_back(F0);
6328 for(MInt i = 0; i < 3; i++)
6329 m_particleAcceleration.push_back(F0);
6330 for(MInt i = 0; i < 3; i++)
6331 m_particleAngularVelocity.push_back(F0);
6332 for(MInt i = 0; i < 3; i++)
6333 m_particleAngularAcceleration.push_back(F0);
6334 for(MInt i = 0; i < 9; i++)
6335 m_particleVelocityGradientFluid.push_back(F0);
6336
6337 // use this for a truly uniform distribution!!!!!!!!!!!!!!!
6338 MFloat ew = cos(tt2) * sqrt(sr);
6339 MFloat ex = sin(tt1) * sqrt(F1 - sr);
6340 MFloat ey = cos(tt1) * sqrt(F1 - sr);
6341 MFloat ez = sin(tt2) * sqrt(sr);
6342
6343 m_particleQuaternions.push_back(ew / sqrt(ew * ew + ex * ex + ey * ey + ez * ez));
6344 m_particleQuaternions.push_back(ex / sqrt(ew * ew + ex * ex + ey * ey + ez * ez));
6345 m_particleQuaternions.push_back(ey / sqrt(ew * ew + ex * ex + ey * ey + ez * ez));
6346 m_particleQuaternions.push_back(ez / sqrt(ew * ew + ex * ex + ey * ey + ez * ez));
6347
6348 if(m_pointParticleType == 1) {
6349 for(MInt i = 0; i < 3; i++)
6350 m_particleRadii.push_back(F1B2 * diameter);
6351 for(MInt i = 0; i < 4; i++)
6352 m_particleShapeParams.push_back(F0);
6353 } else if(m_pointParticleType == 3) {
6354 MFloat a = F1B2 * diameter * pow(beta, -F1B3);
6355 MFloat beta2 = POW2(beta);
6356 m_particleRadii.push_back(a);
6357 m_particleRadii.push_back(a);
6358 m_particleRadii.push_back(beta * a);
6359 if(fabs(beta - F1) < 1e-14) {
6360 m_particleShapeParams.push_back(F2 * POW2(a));
6361 m_particleShapeParams.push_back(F2B3);
6362 m_particleShapeParams.push_back(F2B3);
6363 m_particleShapeParams.push_back(F2B3);
6364 } else if(beta < F0) {
6365 // general triaxial ellipsoid
6366 } else if(beta > F1) {
6367 MFloat kappa = log((beta - sqrt(beta2 - F1)) / (beta + sqrt(beta2 - F1)));
6368 m_particleShapeParams.push_back(-beta * POW2(a) * kappa / sqrt(beta2 - F1));
6369 m_particleShapeParams.push_back(beta2 / (beta2 - F1) + beta * kappa / (F2 * pow(beta2 - F1, F3B2)));
6370 m_particleShapeParams.push_back(beta2 / (beta2 - F1) + beta * kappa / (F2 * pow(beta2 - F1, F3B2)));
6371 m_particleShapeParams.push_back(-F2 / (beta2 - F1) - beta * kappa / (pow(beta2 - F1, F3B2)));
6372 } else if(beta < F1) {
6373 // MFloat kappa = F2*atan( beta/sqrt(F1-beta2) );
6374 MFloat kappa = F2 * atan2(beta, sqrt(F1 - beta2));
6375 m_particleShapeParams.push_back(beta * POW2(a) * (PI - kappa) / sqrt(F1 - beta2));
6376 m_particleShapeParams.push_back(-beta * (kappa - PI + F2 * beta * sqrt(F1 - beta2))
6377 / (F2 * pow(F1 - beta2, F3B2)));
6378 m_particleShapeParams.push_back(-beta * (kappa - PI + F2 * beta * sqrt(F1 - beta2))
6379 / (F2 * pow(F1 - beta2, F3B2)));
6380 m_particleShapeParams.push_back((beta * kappa - beta * PI + F2 * sqrt(F1 - beta2)) / (pow(F1 - beta2, F3B2)));
6381 }
6382 if(domainId() == 0 && m_noPointParticlesLocal == 0) {
6383 cerr << "ellipsoid: " << diameter << " " << beta << " / " << a << " " << a << " " << beta * a << " ("
6384 << pow(a * a * a * beta, F1B3) << ")" << endl;
6385 MFloat tst0 = F0;
6386 MFloat tst1 = F0;
6387 MFloat tst2 = F0;
6388 MFloat tst3 = F0;
6389 MFloat dlt = F1;
6390 const MFloat dx = 1e-6;
6391 const MFloat b = a;
6392 const MFloat c = beta * a;
6393 MFloat x = F1B2 * dx;
6394 while(fabs(dlt) > 1e-8) {
6395 dlt = a * b * c / sqrt((a * a + x) * (b * b + x) * (c * c + x));
6396 tst0 += dx * dlt;
6397 tst1 += dx * dlt / (a * a + x);
6398 tst2 += dx * dlt / (b * b + x);
6399 tst3 += dx * dlt / (c * c + x);
6400 x += dx;
6401 }
6402 cerr << "value 0: " << tst0 << " " << m_particleShapeParams[0] << endl;
6403 cerr << "value 1: " << tst1 << " " << m_particleShapeParams[1] << endl;
6404 cerr << "value 2: " << tst2 << " " << m_particleShapeParams[2] << endl;
6405 cerr << "value 3: " << tst3 << " " << m_particleShapeParams[3] << endl;
6406 }
6407 } else {
6408 mTerm(1, AT_, "point particle type");
6409 }
6410 m_particleCellLink.push_back(linkedCell);
6411 particleCheck(p)++;
6412 m_noPointParticlesLocal++;
6413 m_particleGlobalId.push_back(p);
6414 }
6415 }
6416 MPI_Allreduce(MPI_IN_PLACE, &(particleCheck[0]), m_noPointParticles, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
6417 "(particleCheck[0])");
6418 if(domainId() == 0) {
6419 for(MInt p = 0; p < m_noPointParticles; p++) {
6420 if(particleCheck[p] != 1)
6421 mTerm(1, AT_, "Point particle init failed " + to_string(p) + " " + to_string(particleCheck[p]));
6422 }
6423 }
6424 m_particleCoordsDt1 = m_particleCoords;
6425 m_particleVelocityDt1 = m_particleVelocity;
6426 m_particleTemperatureDt1 = m_particleTemperature;
6427 m_particleAccelerationDt1 = m_particleAcceleration;
6428 m_particleQuaternionsDt1 = m_particleQuaternions;
6429 m_particleAngularVelocityDt1 = m_particleAngularVelocity;
6430 m_particleAngularAccelerationDt1 = m_particleAngularAcceleration;
6431 for(MUint p = 0; p < m_particleCellLink.size(); p++) {
6432 MInt cellId = m_particleCellLink[p];
6433 while(c_noChildren(cellId) > 0) {
6434 MInt child = 0;
6435 for(MUint i = 0; i < nDim; i++) {
6436 if(m_particleCoords[nDim * p + i] > a_coordinate(cellId, i)) child += IPOW2(i);
6437 }
6438 cellId = c_childId(cellId, child);
6439 if(cellId < 0 || cellId >= a_noCells()) mTerm(1, AT_, "Point particle linking failed.");
6440 }
6441 m_particleCellLink[p] = cellId;
6442 }
6443}
6444
6445
6452template <MInt nDim, class SysEqn>
6454 TRACE();
6455
6456 cerr0 << "Init body properties...";
6457
6458 if(m_noEmbeddedBodies == 0) {
6459 cerr0 << " m_noEmbeddedBodies = 0. Body properties will not be initialized." << endl;
6460 if(m_noPointParticles > 0 && noMinCells() > 0) {
6461 initPointParticleProperties();
6462 }
6463 return;
6464 }
6465
6466 if(m_constructGField) updateInfinityVariables();
6467
6479 MFloat bodyTemperatureRatio = 1;
6480 bodyTemperatureRatio =
6481 Context::getSolverProperty<MFloat>("bodyTemperatureRatio", m_solverId, AT_, &bodyTemperatureRatio);
6482
6483 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6484 for(MInt i = 0; i < nDim; i++) {
6485 m_bodyCenter[k * nDim + i] = F0;
6486 m_bodyVelocity[k * nDim + i] = F0;
6487 m_bodyForce[k * nDim + i] = F0;
6488 m_bodyAcceleration[k * nDim + i] = F0;
6489 if(m_motionEquation > 1) {
6490 m_bodyNeutralCenter[k * nDim + i] = F0;
6491 }
6492 }
6493 for(MInt i = 0; i < 3; i++) {
6494 m_bodyAngularVelocity[k * 3 + i] = F0;
6495 m_bodyAngularAcceleration[k * 3 + i] = F0;
6496 m_bodyTorque[k * 3 + i] = F0;
6497 }
6498 for(MInt i = 0; i < 4; i++) {
6499 m_bodyQuaternion[k * 4 + i] = F0;
6500 }
6501 m_bodyTemperature[k] = bodyTemperatureRatio * m_TInfinity;
6502 m_bodyTemperatureDt1[k] = bodyTemperatureRatio * m_TInfinity;
6503 if(m_motionEquation > 1) {
6504 m_bodyReducedVelocity[k] = 9.0;
6505 m_bodyReducedFrequency[k] = m_Ma / m_bodyReducedVelocity[k];
6506 m_bodyReducedMass[k] = F2;
6507 m_bodyDampingCoefficient[k] = F0;
6508 }
6509 m_bodyInCollision[k] = 0;
6510 }
6511
6512 m_log << "Inititial body temperature of body 0 " << m_bodyTemperature[0] << endl;
6513 if(Context::propertyExists("bodyTemperatureRatio", m_solverId) && m_motionEquation == 0 && domainId() == 0) {
6514 cerr << "Warning: Body temperature will not be updated" << endl;
6515 }
6516
6517 // bndryCnd-velocity should resemble body-velocity!
6518 if(m_motionEquation == 0 && !m_constructGField && m_LsMovement) {
6519 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6520 m_bodyEquation[k] = 4520;
6521 }
6522 } else if(m_motionEquation == 0) {
6523 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6524 m_bodyEquation[k] = m_initialCondition;
6525 }
6526 }
6527
6528 m_U2 = F0;
6529 for(MInt i = 0; i < nDim; i++) {
6530 m_U2 += POW2(m_VVInfinity[i]);
6531 }
6532 m_rhoU2 = m_U2 * m_rhoInfinity;
6533
6545 for(MInt i = 0; i < nDim; i++) {
6546 m_fixedBodyComponents[i] = 0;
6547 }
6548 for(MInt i = 0; i < nDim; i++) {
6549 m_fixedBodyComponents[i] =
6550 Context::getSolverProperty<MInt>("fixedBodyComponents", m_solverId, AT_, &m_fixedBodyComponents[i], i);
6551 }
6563 for(MInt i = 0; i < 3; i++) {
6564 m_fixedBodyComponentsRotation[i] = Context::getSolverProperty<MInt>("fixedBodyComponentsRotation", m_solverId, AT_,
6565 &m_fixedBodyComponentsRotation[i], i);
6566 }
6567
6568 if(m_motionEquation > 1 && m_noEmbeddedBodies > 0) {
6579 MFloat reducedMass = Context::getSolverProperty<MFloat>("reducedMass", m_solverId, AT_, &m_bodyReducedMass[0]);
6580 MFloat dampCoeff =
6581 Context::getSolverProperty<MFloat>("dampingCoefficient", m_solverId, AT_, &m_bodyDampingCoefficient[0]);
6582 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6583 m_bodyReducedMass[k] = reducedMass;
6584 m_bodyDampingCoefficient[k] = dampCoeff;
6585 if(Context::propertyExists("reducedVelocity", m_solverId)) {
6586 m_bodyReducedVelocity[k] =
6587 Context::getSolverProperty<MFloat>("reducedVelocity", m_solverId, AT_, &m_bodyReducedVelocity[0]);
6588 m_bodyReducedFrequency[k] = m_Ma / m_bodyReducedVelocity[k];
6589 }
6590 if(fabs(m_bodyReducedVelocity[k]) < m_eps) {
6591 mTerm(1, AT_, "Division by zero in FvMbCartesianSolverXD::initBodyProperties(). Quit.");
6592 }
6593 }
6594 }
6595
6607 MFloat bodyRadius = F1B2;
6608 bodyRadius = Context::getSolverProperty<MFloat>("bodyRadius", m_solverId, AT_, &bodyRadius);
6609 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6610 m_bodyRadius[k] = bodyRadius;
6611 m_bodyDiameter[k] = F2 * bodyRadius;
6612 }
6613
6625 if(Context::propertyExists("bodyDiameters", m_solverId)) {
6626 if(Context::propertyLength("bodyDiameters", m_solverId) == m_noEmbeddedBodies) {
6627 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6628 m_bodyDiameter[k] = Context::getSolverProperty<MFloat>("bodyDiameters", m_solverId, AT_, k);
6629 m_bodyRadius[k] = F1B2 * m_bodyDiameter[k];
6630 }
6631 } else
6632 mTerm(1, AT_, "bodyDiameters wrong dimension " + to_string(m_noEmbeddedBodies));
6633 }
6634
6647 if(m_noEmbeddedBodies > 0) {
6648 if(m_bodyTypeMb == 3) {
6649 if(Context::propertyLength("bodyRadii", m_solverId) == 3) {
6650 for(MInt i = 0; i < 3; i++) {
6651 m_bodyRadii[i] = Context::getSolverProperty<MFloat>("bodyRadii", m_solverId, AT_, i);
6652 }
6653 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6654 for(MInt i = 0; i < 3; i++) {
6655 m_bodyRadii[k * 3 + i] = m_bodyRadii[i];
6656 }
6657 }
6658 } else {
6659 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6660 for(MInt i = 0; i < 3; i++) {
6661 m_bodyRadii[k * 3 + i] = Context::getSolverProperty<MFloat>("bodyRadii", m_solverId, AT_, k * 3 + i);
6662 }
6663 }
6664 }
6665 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6666 m_bodyRadius[k] = F0;
6667 for(MInt i = 0; i < 3; i++) {
6668 // m_bodyRadius[ k ] = mMax( m_bodyRadius[ k ], m_bodyRadii[ k*3+i ] );
6669 }
6670 m_bodyRadius[k] = pow(m_bodyRadii[k * 3 + 0] * m_bodyRadii[k * 3 + 1] * m_bodyRadii[k * 3 + 2], F1B3);
6671 m_bodyDiameter[k] = F2 * m_bodyRadius[k];
6672 }
6673 } else {
6674 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6675 for(MInt i = 0; i < 3; i++) {
6676 m_bodyRadii[k * 3 + i] = m_bodyRadius[k];
6677 }
6678 }
6679 }
6680 }
6681
6682
6683 if(m_motionEquation > 1) {
6684 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6685 m_bodyReducedVelocity[k] *= m_bodyDiameter[k];
6686 m_bodyReducedFrequency[k] /= m_bodyDiameter[k];
6687 for(MInt i = 0; i < nDim; i++) {
6688 m_bodyReducedMass[k] *= m_bodyDiameter[k];
6689 }
6690 }
6691 }
6692
6704 m_densityRatio = F1;
6705 m_densityRatio = Context::getSolverProperty<MFloat>("densityRatio", m_solverId, AT_, &m_densityRatio);
6706 m_log << "density ratio: " << m_densityRatio << endl;
6707
6708
6716 m_capacityConstantVolumeRatio =
6717 (Context::propertyExists("capacityConstantVolumeRatio", m_solverId))
6718 ? Context::getSolverProperty<MFloat>("capacityConstantVolumeRatio", m_solverId, AT_)
6719 : F1;
6720
6721 if(domainId() == 0) {
6722 m_log << "Heat capacity at constant volume Cv_particle/Cv_fluid: " << m_capacityConstantVolumeRatio << endl;
6723 }
6724
6725 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6726 m_bodyDensity[k] = m_densityRatio * m_rhoInfinity;
6727 m_bodyVolume[k] = F4B3 * PI;
6728 m_projectedArea[k] = PI;
6729 MFloat tmp = F0;
6730 for(MInt i = 0; i < nDim; i++) {
6731 m_bodyVolume[k] *= m_bodyRadii[k * nDim + i];
6732 m_projectedArea[k] *= m_bodyRadii[k * nDim + i];
6733 tmp += m_bodyRadii[k * nDim + i] * fabs(m_VVInfinity[i]) / sqrt(m_U2);
6734 }
6735 m_projectedArea[k] /= tmp;
6736 m_bodyMass[k] = m_bodyDensity[k] * m_bodyVolume[k];
6737 }
6738
6739
6740 IF_CONSTEXPR(nDim == 2) {
6741 m_addedMassCoefficient = F1;
6742 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6743 m_projectedArea[k] = F2 * m_bodyRadius[k];
6744 }
6745 }
6746 IF_CONSTEXPR(nDim == 3) {
6747 MFloat F2B5 = 2.0 / 5.0;
6748 if(m_bodyTypeMb == 1) {
6749 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6750 for(MInt i = 0; i < 3; i++) {
6751 m_bodyMomentOfInertia[3 * k + i] = F2B5 * m_bodyMass[k] * POW2(m_bodyRadius[k]);
6752 }
6753 }
6754 } else if(m_bodyTypeMb == 3) {
6755 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6756 const MFloat a = m_bodyRadii[k * nDim + 0];
6757 const MFloat b = m_bodyRadii[k * nDim + 1];
6758 const MFloat c = m_bodyRadii[k * nDim + 2];
6759 m_bodyMomentOfInertia[3 * k + 0] = (4.0 / 15.0) * (b * b + c * c) * PI * m_bodyDensity[k] * a * b * c;
6760 m_bodyMomentOfInertia[3 * k + 1] = (4.0 / 15.0) * (a * a + c * c) * PI * m_bodyDensity[k] * a * b * c;
6761 m_bodyMomentOfInertia[3 * k + 2] = (4.0 / 15.0) * (a * a + b * b) * PI * m_bodyDensity[k] * a * b * c;
6762 }
6763 }
6764 m_addedMassCoefficient = F1B2;
6765 }
6766
6767 if(m_noEmbeddedBodies > 1 || m_initialCondition == 471) {
6768 MFloat VVInf = F0;
6769 for(MInt i = 0; i < nDim; i++) {
6770 VVInf += POW2(m_VVInfinity[i]);
6771 }
6772 VVInf = sqrt(VVInf);
6773 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6774 m_bodyDensity[k] = m_densityRatio * m_rhoInfinity;
6775 m_bodyVolume[k] = F4B3 * PI;
6776 m_projectedArea[k] = PI;
6777 MFloat tmp = F0;
6778 for(MInt i = 0; i < nDim; i++) {
6779 m_bodyVolume[k] *= m_bodyRadii[k * nDim + i];
6780 m_projectedArea[k] *= m_bodyRadii[k * nDim + i];
6781 tmp += m_bodyRadii[k * nDim + i] * fabs(m_VVInfinity[i]) / VVInf;
6782 }
6783 m_projectedArea[k] /= tmp;
6784 m_bodyMass[k] = m_bodyDensity[k] * m_bodyVolume[k];
6785 }
6786
6787 if(m_initialCondition == 471) {
6788 // m_g = F3B4*POW2(m_Ma)*m_TInfinity*26.7644/m_densityRatio;
6789 m_g = F3B4 * CdLaw(m_Re) * POW2(m_Ma) / (m_referenceLength * m_densityRatio);
6790 m_log << "g=" << m_g << ", Fr=" << m_Ma / sqrt(m_g) << endl;
6791 }
6792 }
6793
6794 m_minBodyRadius = numeric_limits<MFloat>::max();
6795 m_maxBodyRadius = F0;
6796 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6797 m_maxBodyRadius = mMax(m_maxBodyRadius, m_bodyRadius[k]);
6798 m_minBodyRadius = mMin(m_minBodyRadius, m_bodyRadius[k]);
6799 for(MInt i = 0; i < 3; i++) {
6800 m_maxBodyRadius = mMax(m_maxBodyRadius, m_bodyRadii[k * 3 + i]);
6801 m_minBodyRadius = mMin(m_minBodyRadius, m_bodyRadii[k * 3 + i]);
6802 }
6803 }
6804
6805 if(!m_restart) {
6806 MFloat VVInf = F0;
6807 for(MInt i = 0; i < nDim; i++) {
6808 VVInf += POW2(m_VVInfinity[i]);
6809 }
6810 VVInf = sqrt(VVInf);
6811
6812 if(m_initialCondition != 45299 && m_initialCondition != 45300 && m_initialCondition != 45301
6813 && m_initialCondition != 45302 && m_initialCondition != 4520
6814 && (m_noEmbeddedBodies > 1 || m_initialCondition == 471)) {
6815 for(MInt i = 0; i < nDim; i++) {
6816 m_bodyVelocity[i] = F0;
6817
6829 if(Context::propertyExists("initialBodyVelocity", m_solverId)) {
6830 m_bodyVelocity[i] = Context::getSolverProperty<MFloat>("initialBodyVelocity", m_solverId, AT_, i);
6831 }
6832 }
6833 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6834 if(Context::propertyExists("initialBodyVelocity", m_solverId)) {
6835 for(MInt i = 0; i < nDim; i++) {
6836 m_bodyVelocity[k * nDim + i] = m_bodyVelocity[i];
6837 }
6838 for(MInt i = 0; i < nDim; i++) {
6839 m_bodyVelocity[k * nDim + i] *= m_UInfinity;
6840 }
6841 }
6842
6922 if(!Context::propertyExists("xBodyCenter", m_solverId)) continue;
6923
6924 m_bodyCenter[k * nDim] = Context::getSolverProperty<MFloat>("xBodyCenter", m_solverId, AT_, k);
6925 m_bodyCenter[k * nDim + 1] = Context::getSolverProperty<MFloat>("yBodyCenter", m_solverId, AT_, k);
6926 if(Context::propertyExists("xBodyVelocity", m_solverId))
6927 m_bodyVelocity[k * nDim] = Context::getSolverProperty<MFloat>("xBodyVelocity", m_solverId, AT_, k) * VVInf;
6928 if(Context::propertyExists("yBodyVelocity", m_solverId))
6929 m_bodyVelocity[k * nDim + 1] =
6930 Context::getSolverProperty<MFloat>("yBodyVelocity", m_solverId, AT_, k) * VVInf;
6931 if(m_initialCondition == 450) {
6932 if(m_motionEquation > 1) {
6933 if(m_restart) cerr << "consider" << endl;
6934 m_bodyNeutralCenter[k * nDim] =
6935 Context::getSolverProperty<MFloat>("xBodyNeutralCenter", m_solverId, AT_, k);
6936 m_bodyNeutralCenter[k * nDim + 1] =
6937 Context::getSolverProperty<MFloat>("yBodyNeutralCenter", m_solverId, AT_, k);
6938 }
6939 }
6940 IF_CONSTEXPR(nDim == 3) {
6941 m_bodyCenter[k * nDim + 2] = Context::getSolverProperty<MFloat>("zBodyCenter", m_solverId, AT_, k);
6942 if(Context::propertyExists("zBodyVelocity", m_solverId))
6943 m_bodyVelocity[k * nDim + 2] =
6944 Context::getSolverProperty<MFloat>("zBodyVelocity", m_solverId, AT_, k) * VVInf;
6945 if(m_initialCondition == 450) {
6946 if(m_motionEquation > 1) {
6947 if(m_restart) cerr << "consider" << endl;
6948 m_bodyNeutralCenter[k * nDim + 2] =
6949 Context::getSolverProperty<MFloat>("zBodyNeutralCenter", m_solverId, AT_, k);
6950 }
6951 }
6952 }
6953 if(m_initialCondition == 450) {
6954 if(m_motionEquation > 1) {
6955 if(Context::propertyExists("bodyReducedVelocity", m_solverId)) {
6956 m_bodyReducedVelocity[k] = Context::getSolverProperty<MFloat>("bodyReducedVelocity", m_solverId, AT_, k);
6957 m_bodyReducedFrequency[k] = m_Ma / m_bodyReducedVelocity[k];
6958 }
6959 }
6960 }
6961 }
6962 } else {
6974 if(m_noEmbeddedBodies > 0) {
6975 if(Context::propertyExists("initialBodyCenter", m_solverId)) {
6976 for(MInt i = 0; i < nDim; i++) {
6977 m_bodyCenter[i] =
6978 Context::getSolverProperty<MFloat>("initialBodyCenter", m_solverId, AT_, i) * m_bodyDiameter[0];
6979 }
6980 }
6981 if(Context::propertyExists("initialBodyVelocity", m_solverId)) {
6982 for(MInt i = 0; i < nDim; i++) {
6983 m_bodyVelocity[i] = Context::getSolverProperty<MFloat>("initialBodyVelocity", m_solverId, AT_, i);
6984 }
6985 for(MInt i = 0; i < nDim; i++) {
6986 m_bodyVelocity[i] *= m_UInfinity;
6987 }
6988 }
6989 }
6990 }
6991
6992 // reset intial orientation, different initial values below
6993 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
6994 m_bodyQuaternion[k * 4 + 0] = F1;
6995 m_bodyQuaternion[k * 4 + 1] = F0;
6996 m_bodyQuaternion[k * 4 + 2] = F0;
6997 m_bodyQuaternion[k * 4 + 3] = F0;
6998 }
6999
7000 if((m_initialCondition == 15 || m_initialCondition == 16) && m_noEmbeddedBodies > 0) {
7001 MString fileName = "out/bodyData_init.Netcdf";
7002 MBool foundFile = false;
7003 cerr0 << endl;
7004 if(!m_restart && ParallelIo::fileExists(fileName, mpiComm())) {
7005 cerr0 << "Loading initial body distribution from file " << fileName << endl;
7006 using namespace maia::parallel_io;
7007 ParallelIo parallelIo(fileName, PIO_READ, mpiComm());
7008
7009 ParallelIo::size_type start = 0;
7010 ParallelIo::size_type count = 0;
7011
7012 const MLong DOF = m_noEmbeddedBodies;
7013 const MLong DOF_TRANS = nDim * m_noEmbeddedBodies;
7014 const MLong DOF_ROT = 3 * m_noEmbeddedBodies;
7015 const MLong DOF_QUAT = 4 * m_noEmbeddedBodies;
7016 MInt noBodies = -1;
7017 MFloat radii[3];
7018 parallelIo.getAttribute(&noBodies, "noBodies");
7019 parallelIo.getAttribute(radii, "bodyRadii", 3);
7020
7021 foundFile = true;
7022 if(noBodies < DOF) {
7023 foundFile = false;
7024 cerr0 << "Not enough embedded bodies in file " << fileName << endl;
7025 }
7026 if(fabs(m_bodyRadii[0] - radii[0]) > 1e-12 || fabs(m_bodyRadii[1] - radii[1]) > 1e-12
7027 || fabs(m_bodyRadii[2] - radii[2]) > 1e-12) {
7028 foundFile = false;
7029 cerr0 << "Body radii mismatch in file " << fileName << endl;
7030 }
7031 if(foundFile) {
7032 count = DOF;
7033 parallelIo.setOffset(count, start);
7034 parallelIo.readArray(m_bodyTemperature, "bodyTemperature");
7035
7036 count = DOF_TRANS;
7037 parallelIo.setOffset(count, start);
7038 parallelIo.readArray(m_bodyCenter, "bodyCenter");
7039 if(parallelIo.hasDataset("bodyVelocity")) {
7040 parallelIo.readArray(m_bodyVelocity, "bodyVelocity");
7041 }
7042
7043 count = DOF_ROT;
7044 parallelIo.setOffset(count, start);
7045 if(parallelIo.hasDataset("bodyAngularVelocity")) {
7046 parallelIo.readArray(m_bodyAngularVelocity, "bodyAngularVelocity");
7047 }
7048
7049 count = DOF_QUAT;
7050 parallelIo.setOffset(count, start);
7051 parallelIo.readArray(m_bodyQuaternion, "bodyQuaternion");
7052 }
7053 }
7054 if(!foundFile) {
7055 const MFloat dist0 = 3.0 * c_cellLengthAtLevel(maxRefinementLevel());
7056 const MFloat dist1 = F2 * m_maxBodyRadius + dist0;
7057 const MBool storeBodyDistribution =
7058 (Context::propertyExists("storeBodyDistribution", m_solverId))
7059 ? Context::getSolverProperty<MBool>("storeBodyDistribution", m_solverId, AT_)
7060 : 1;
7061
7062 if(domainId() == 0) {
7071 const int64_t seed0 = (int64_t)((Context::propertyExists("randomDeviceSeed", m_solverId))
7072 ? Context::getSolverProperty<MFloat>("randomDeviceSeed", m_solverId, AT_)
7073 : -1);
7074 const MUlong seed = (MUlong)((seed0 > -1) ? seed0 : std::random_device()());
7075 const MUlong seed1 = seed;
7076
7077 std::mt19937_64 gen(seed);
7078 std::mt19937_64 gen2(seed1);
7079 std::mt19937_64 gen3(seed1);
7080
7081 std::uniform_real_distribution<> distr(-F1B2, F1B2);
7082 std::uniform_real_distribution<> distr2(F0, F1);
7083 std::uniform_real_distribution<> distr3(0.25, 1.75);
7084
7085 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
7086 for(MInt i = 0; i < nDim; i++) {
7087 m_bodyCenter[k * nDim + i] = m_bbox[nDim + i] + 1000000.0 * (m_bbox[nDim + i] - m_bbox[i]);
7088 }
7089 }
7090
7091 MFloatScratchSpace maxRadius(m_noEmbeddedBodies, AT_, "maxRadius");
7092 MFloat dx[3]{};
7093 MFloat bboxThreshold[6]{};
7094 MFloat bboxThreshold2[6]{};
7095 for(MInt i = 0; i < nDim; i++) {
7096 dx[i] = m_bbox[nDim + i] - m_bbox[i];
7097 bboxThreshold[i] = m_bbox[i] + dist1;
7098 bboxThreshold2[i] = m_bbox[i] - dist1;
7099 bboxThreshold[nDim + i] = m_bbox[nDim + i] - dist1;
7100 bboxThreshold2[nDim + i] = m_bbox[nDim + i] + dist1;
7101 }
7102 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
7103 maxRadius[k] = mMax(m_bodyRadii[k * 3 + 0], mMax(m_bodyRadii[k * 3 + 1], m_bodyRadii[k * 3 + 2]));
7104 }
7105 const MInt statFac = (m_noEmbeddedBodies > 100000) ? 100 : ((m_noEmbeddedBodies > 10000) ? 10 : -1);
7106 const MFloat time0 = MPI_Wtime();
7107 cerr << "No body distribution file found. Creating new distribution for " << m_noEmbeddedBodies << " bodies."
7108 << endl;
7109
7110 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
7111 if(statFac > -1
7112 && (MInt)(k / (m_noEmbeddedBodies / statFac)) < (MInt)((k + 1) / (m_noEmbeddedBodies / statFac))) {
7113 cerr << "body init completed: " << (MInt)(100 * (k + 1) / (m_noEmbeddedBodies)) << "%" << endl;
7114 }
7115 MBool keep = false;
7116 while(!keep) {
7117 for(MInt i = 0; i < nDim; i++) {
7118 m_bodyCenter[k * nDim + i] = distr(gen) * (m_bbox[nDim + i] - m_bbox[i]);
7119 }
7120 keep = true;
7121
7122 for(MInt s = 0; s < 4; s++) {
7123 distr2(gen2); // throw away some random numbers (for whatever reason required to get uniform
7124 // distribution below)
7125 }
7126
7127 for(MInt p = 0; p < k; p++) {
7128 const MFloat dkp = maxRadius[k] + maxRadius[p];
7129 if(
7130 (POW2(m_bodyCenter[k * nDim] - m_bodyCenter[p * nDim])
7131 + POW2(m_bodyCenter[k * nDim + 1] - m_bodyCenter[p * nDim + 1])
7132 + POW2(m_bodyCenter[k * nDim + 2] - m_bodyCenter[p * nDim + 2]))
7133 < POW2(dist0 + dkp)) {
7134 keep = false;
7135 break;
7136 }
7137 if(!keep) break;
7138
7139 MBool isOutsideThreshold = false;
7140 IF_CONSTEXPR(nDim == 2) {
7141 if(m_bodyCenter[p * nDim] < bboxThreshold[0] || m_bodyCenter[p * nDim] > bboxThreshold[3]
7142 || m_bodyCenter[p * nDim + 1] < bboxThreshold[1]
7143 || m_bodyCenter[p * nDim + 1] > bboxThreshold[4]) {
7144 isOutsideThreshold = true;
7145 }
7146 }
7147 IF_CONSTEXPR(nDim == 3) {
7148 if(m_bodyCenter[p * nDim] < bboxThreshold[0] || m_bodyCenter[p * nDim] > bboxThreshold[3]
7149 || m_bodyCenter[p * nDim + 1] < bboxThreshold[1] || m_bodyCenter[p * nDim + 1] > bboxThreshold[4]
7150 || m_bodyCenter[p * nDim + 2] < bboxThreshold[2]
7151 || m_bodyCenter[p * nDim + 2] > bboxThreshold[5]) {
7152 isOutsideThreshold = true;
7153 }
7154 }
7155
7156 if(isOutsideThreshold) {
7157 MFloat coords[3][3]{};
7158 for(MInt i = 0; i < nDim; i++) {
7159 coords[1][i] = m_bodyCenter[p * nDim + i];
7160 coords[0][i] = coords[1][i] - dx[i];
7161 coords[2][i] = coords[1][i] + dx[i];
7162 }
7163 for(MInt s0 = -1; s0 <= 1; s0++) {
7164 if(s0 != 0 && !grid().periodicCartesianDir(0)) continue;
7165 for(MInt s1 = -1; s1 <= 1; s1++) {
7166 if(s1 != 0 && !grid().periodicCartesianDir(1)) continue;
7167 for(MInt s2 = -1; s2 <= 1; s2++) {
7168 if(s0 == 0 && s1 == 0 && s2 == 0) continue;
7169 if(s2 != 0 && !grid().periodicCartesianDir(2)) continue;
7170
7171 if(coords[1 + s0][0] < bboxThreshold2[0] || coords[1 + s0][0] > bboxThreshold2[3]) continue;
7172 if(coords[1 + s1][1] < bboxThreshold2[1] || coords[1 + s1][1] > bboxThreshold2[4]) continue;
7173 if(coords[1 + s2][2] < bboxThreshold2[2] || coords[1 + s2][2] > bboxThreshold2[5]) continue;
7174
7175 if(
7176 (POW2(m_bodyCenter[k * nDim] - coords[1 + s0][0])
7177 + POW2(m_bodyCenter[k * nDim + 1] - coords[1 + s1][1])
7178 + POW2(m_bodyCenter[k * nDim + 2] - coords[1 + s2][2]))
7179 < POW2(dist0 + dkp)) {
7180 keep = false;
7181 break;
7182 }
7183 }
7184 if(!keep) break;
7185 }
7186 if(!keep) break;
7187 }
7188 }
7189 if(!keep) break;
7190 }
7191 }
7192
7193 if(m_bodyTypeMb == 3 || m_bodyTypeMb == 1 || m_bodyTypeMb == 7) {
7194 MFloat sr = distr2(gen2);
7195 MFloat tt1 = F2 * PI * distr2(gen2);
7196 MFloat tt2 = F2 * PI * distr2(gen2);
7197 MFloat ew = cos(tt2) * sqrt(sr);
7198 MFloat ex = sin(tt1) * sqrt(F1 - sr);
7199 MFloat ey = cos(tt1) * sqrt(F1 - sr);
7200 MFloat ez = sin(tt2) * sqrt(sr);
7201 m_bodyQuaternion[4 * k + 0] = ew / sqrt(ew * ew + ex * ex + ey * ey + ez * ez);
7202 m_bodyQuaternion[4 * k + 1] = ex / sqrt(ew * ew + ex * ex + ey * ey + ez * ez);
7203 m_bodyQuaternion[4 * k + 2] = ey / sqrt(ew * ew + ex * ex + ey * ey + ez * ez);
7204 m_bodyQuaternion[4 * k + 3] = ez / sqrt(ew * ew + ex * ex + ey * ey + ez * ez);
7205 }
7206
7207 if(m_movingBndryCndId == 3008) {
7208 m_bodyTemperature[k] = distr3(gen3) * m_TInfinity;
7209 }
7210 }
7211 const MFloat time1 = MPI_Wtime();
7212 cerr << "body init time: " << time1 - time0 << "s." << endl;
7213 }
7214
7215 MPI_Bcast(&m_bodyCenter[0], nDim * m_noEmbeddedBodies, MPI_DOUBLE, 0, mpiComm(), AT_, "m_bodyCenter[0]");
7216 MPI_Bcast(&m_bodyQuaternion[0], 4 * m_noEmbeddedBodies, MPI_DOUBLE, 0, mpiComm(), AT_, "m_bodyQuaternion[0]");
7217 MPI_Bcast(&m_bodyTemperature[0], m_noEmbeddedBodies, MPI_DOUBLE, 0, mpiComm(), AT_, "m_bodyTemperature[0]");
7218
7219 if(storeBodyDistribution) {
7220 cerr0 << "Storing initial body distribution to file " << fileName << endl;
7221 const MLong DOF = m_noEmbeddedBodies;
7222 const MLong DOF_TRANS = nDim * m_noEmbeddedBodies;
7223 const MLong DOF_QUAT = 4 * m_noEmbeddedBodies;
7224
7225 ParallelIo::size_type start = 0;
7226 ParallelIo::size_type count = 0;
7227 using namespace maia::parallel_io;
7228 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
7229
7230 // Creating file header.
7231 parallelIo.setAttributes(&m_noEmbeddedBodies, "noBodies", 1);
7232 parallelIo.setAttributes(m_bodyRadii, "bodyRadii", 3);
7233 count = DOF;
7234 parallelIo.defineArray(PIO_FLOAT, "bodyTemperature", count);
7235 count = DOF_TRANS;
7236 parallelIo.defineArray(PIO_FLOAT, "bodyCenter", count);
7237 count = DOF_QUAT;
7238 parallelIo.defineArray(PIO_FLOAT, "bodyQuaternion", count);
7239 start = 0;
7240 count = DOF;
7241 parallelIo.setOffset(count, start);
7242 parallelIo.writeArray(m_bodyTemperature, "bodyTemperature");
7243 count = DOF_TRANS;
7244 parallelIo.setOffset(count, start);
7245 parallelIo.writeArray(m_bodyCenter, "bodyCenter");
7246 count = DOF_QUAT;
7247 parallelIo.setOffset(count, start);
7248 parallelIo.writeArray(m_bodyQuaternion, "bodyQuaternion");
7249 }
7250 }
7251
7252 createPeriodicGhostBodies();
7253 memset(m_bodyVelocity, 0, m_noEmbeddedBodies * nDim * sizeof(MFloat));
7254 }
7255
7256
7268 if(Context::propertyExists("initialBodyQuaternion", m_solverId)) {
7269 for(MInt i = 0; i < m_noEmbeddedBodies * 4; i++) {
7270 m_bodyQuaternion[i] = Context::getSolverProperty<MFloat>("initialBodyQuaternion", m_solverId, AT_, i);
7271 }
7272 }
7273
7286 if(Context::propertyExists("initialBodyRotation", m_solverId)) {
7287 MFloatScratchSpace bodyRotation(m_noEmbeddedBodies, 3, AT_, "bodyRotation");
7288 if(Context::propertyLength("initialBodyRotation", m_solverId) == 3) {
7289 for(MInt i = 0; i < m_noEmbeddedBodies; i++) {
7290 for(MInt j = 0; j < 3; j++) {
7291 bodyRotation[3 * i + j] =
7292 Context::getSolverProperty<MFloat>("initialBodyRotation", m_solverId, AT_, j) * PI / 180.0;
7293 }
7294 }
7295 } else {
7296 for(MInt i = 0; i < m_noEmbeddedBodies * nDim; i++) {
7297 bodyRotation[i] = Context::getSolverProperty<MFloat>("initialBodyRotation", m_solverId, AT_, i) * PI / 180.0;
7298 }
7299 }
7300 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
7301 setBodyQuaternions(k, &bodyRotation[k * 3]);
7302 }
7303 }
7304
7305 }
7306
7319 if(Context::propertyExists("bodyTerminalVelocity", m_solverId) && m_noEmbeddedBodies > 0) {
7320 const MFloat radius = pow(m_bodyRadii[0] * m_bodyRadii[1] * m_bodyRadii[2], F1B3);
7321 const MFloat FAC0 =
7322 (9.0 / 2.0) * sysEqn().m_muInfinity / (sysEqn().m_Re0 * m_densityRatio * m_rhoInfinity * POW2(radius));
7323 for(MInt dir = 0; dir < nDim; dir++) {
7324 m_bodyTerminalVelocity[dir] = Context::getSolverProperty<MFloat>("bodyTerminalVelocity", m_solverId, AT_,
7325 &m_bodyTerminalVelocity[dir], dir);
7326 }
7327 for(MInt dir = 0; dir < nDim; dir++) {
7328 m_gravity[dir] = FAC0 * m_bodyTerminalVelocity[dir];
7329 }
7330 for(MInt k = 0; k < m_noEmbeddedBodies + m_noPeriodicGhostBodies; k++) {
7331 for(MInt dir = 0; dir < nDim; dir++) {
7332 m_bodyVelocity[nDim * k + dir] += m_bodyTerminalVelocity[dir];
7333 }
7334 }
7335 }
7336
7337
7338 if(m_trackMovingBndry && !m_restart && (m_motionEquation == 0)) {
7339 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
7340 for(MInt i = 0; i < nDim; i++) {
7341 m_bodyCenterDt1[k * nDim + i] = m_bodyCenter[k * nDim + i];
7342 }
7343 }
7344 if(!m_LsMovement) {
7345 updateBodyProperties();
7346 }
7347 }
7348
7349 if(m_restart) {
7350 loadBodyRestartFile(0);
7351 }
7352
7353
7354 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
7355 for(MInt i = 0; i < nDim; i++) {
7356 m_bodyVelocityDt1[k * nDim + i] = m_bodyVelocity[k * nDim + i];
7357 m_bodyCenterDt1[k * nDim + i] = m_bodyCenter[k * nDim + i];
7358 m_bodyAccelerationDt1[k * nDim + i] = m_bodyAcceleration[k * nDim + i];
7359 if(m_motionEquation > 1) {
7360 m_bodyVelocityDt2[k * nDim + i] = m_bodyVelocity[k * nDim + i];
7361 m_bodyCenterDt2[k * nDim + i] = m_bodyCenter[k * nDim + i];
7362 m_bodyAccelerationDt2[k * nDim + i] = m_bodyAcceleration[k * nDim + i];
7363 m_bodyAccelerationDt3[k * nDim + i] = m_bodyAcceleration[k * nDim + i];
7364 }
7365 }
7366 for(MInt i = 0; i < 3; i++) {
7367 m_bodyTorqueDt1[k * 3 + i] = m_bodyTorque[k * 3 + i];
7368 m_bodyAngularVelocityDt1[k * 3 + i] = m_bodyAngularVelocity[k * 3 + i];
7369 m_bodyAngularAccelerationDt1[k * 3 + i] = m_bodyAngularAcceleration[k * 3 + i];
7370 }
7371 for(MInt i = 0; i < 4; i++) {
7372 m_bodyQuaternionDt1[k * 4 + i] = m_bodyQuaternion[k * 4 + i];
7373 }
7374 }
7375
7376 if(m_initialCondition == 466) {
7377 MFloat* bbox;
7378 bbox = new MFloat[6];
7379 m_geometry->getBoundingBox(bbox);
7380 const MFloat delta = F2 * m_UInfinity / (bbox[1 + nDim] - bbox[1]);
7381 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
7382 m_log << "Reynolds number "
7383 << F4 * delta
7384 * POW2(mMax(m_bodyRadii[k * nDim + 0], mMax(m_bodyRadii[k * nDim + 1], m_bodyRadii[k * nDim + 2])))
7385 << " "
7386 << sysEqn().m_Re0 * F4 * delta
7387 * POW2(mMax(m_bodyRadii[k * nDim + 0], mMax(m_bodyRadii[k * nDim + 1], m_bodyRadii[k * nDim + 2])))
7388 << endl;
7389 }
7390 delete[] bbox;
7391 }
7392
7393 if(m_adaptation) {
7394 m_periodicGhostBodyDist = 1.1
7395 * (m_outerBandWidth[mMin(maxUniformRefinementLevel(), maxRefinementLevel() - 1)]
7396 + ((MFloat)noHaloLayers()) * c_cellLengthAtLevel(minLevel()) + m_maxBodyRadius);
7397 m_adaptationDampingDistance = m_bodyDiameter[0];
7398 } else {
7399 m_periodicGhostBodyDist = 1.1 * ((MFloat)noHaloLayers()) * c_cellLengthAtLevel(minLevel()) + m_maxBodyRadius;
7400 }
7401
7402 if(grid().periodicCartesianDir(0) + grid().periodicCartesianDir(1) + grid().periodicCartesianDir(2) > 0) {
7403 createPeriodicGhostBodies();
7404 }
7405 IF_CONSTEXPR(nDim == 3) { createBodyTree(); }
7406
7407 cerr0 << "done." << endl;
7408}
7409
7410
7415template <MInt nDim, class SysEqn>
7417 const MBool saffmanLift = false;
7418
7419 if(m_pointParticleType == 1) {
7420 MFloat vrel[3];
7421 MFloat vort[3];
7422 MFloat lift[3];
7423
7424 const MFloat dt = timeStep();
7425 const MFloat Cvp = m_capacityConstantVolumeRatio;
7426
7427 // 1. prediction step
7428 for(MInt p = 0; p < m_noPointParticlesLocal; p++) {
7429 for(MInt i = 0; i < nDim; i++) {
7430 m_particleCoords[nDim * p + i] =
7431 m_particleCoordsDt1[nDim * p + i]
7432 + F1B2 * dt * (m_particleVelocity[nDim * p + i] + m_particleVelocityDt1[nDim * p + i])
7433 + F1B4 * POW2(dt) * (m_particleAcceleration[nDim * p + i] + m_particleAccelerationDt1[nDim * p + i]);
7434 m_particleVelocity[nDim * p + i] =
7435 m_particleVelocityDt1[nDim * p + i] + dt * m_particleAcceleration[nDim * p + i];
7436 }
7437 m_particleTemperature[p] = m_particleTemperatureDt1[p] + dt * m_particleHeatFlux[p];
7438 }
7439
7440 // 2. compute fluid velocity
7441 setParticleFluidVelocities();
7442
7443 // 3. correction step
7444 for(MInt p = 0; p < m_noPointParticlesLocal; p++) {
7445 const MInt cellId = m_particleCellLink[p];
7446 const MFloat diameter =
7447 F2 * pow(m_particleRadii[3 * p] * m_particleRadii[3 * p + 1] * m_particleRadii[3 * p + 2], F1B3);
7448 const MFloat T = sysEqn().temperature_ES(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
7449 const MFloat mue = SUTHERLANDLAW(T);
7450 const MFloat FAC = 18.0 * mue / (sysEqn().m_Re0 * m_densityRatio * m_rhoInfinity * POW2(diameter));
7451 MFloat Rep = F0;
7452 for(MInt i = 0; i < nDim; i++) {
7453 vrel[i] = m_particleVelocityFluid[nDim * p + i] - m_particleVelocity[nDim * p + i];
7454 Rep += POW2(vrel[i]);
7455 }
7456 Rep = sqrt(Rep) * diameter * a_pvariable(cellId, PV->RHO) * sysEqn().m_Re0 / mue;
7457 vort[0] = a_slope(cellId, PV->VV[2], 1) - a_slope(cellId, PV->VV[1], 2);
7458 vort[1] = a_slope(cellId, PV->VV[0], 2) - a_slope(cellId, PV->VV[2], 0);
7459 vort[2] = a_slope(cellId, PV->VV[1], 0) - a_slope(cellId, PV->VV[0], 1);
7460 lift[0] = vort[2] * vrel[1] - vort[1] * vrel[2];
7461 lift[1] = vort[0] * vrel[2] - vort[2] * vrel[0];
7462 lift[2] = vort[1] * vrel[0] - vort[0] * vrel[1];
7463 MFloat Res = a_pvariable(cellId, PV->RHO) * POW2(diameter) * sqrt(POW2(vort[0]) + POW2(vort[1]) + POW2(vort[2]))
7464 * sysEqn().m_Re0 / mue;
7465 MFloat beta = F1B2 * Res / Rep;
7466 MFloat CLS = 4.1126 * ((F1 - 0.3314 * sqrt(beta)) * exp(-0.1 * Rep) + 0.3314 * sqrt(beta)) / sqrt(Res);
7467 if(Rep > 40.0) CLS = 0.0524 * sqrt(beta * Rep);
7468 for(MInt i = 0; i < nDim; i++) {
7469 m_particleAcceleration[nDim * p + i] =
7470 FAC * (F1 + 0.15 * pow(Rep, 0.687)) * vrel[i] + FAC * m_particleTerminalVelocity[i];
7471 if(saffmanLift) m_particleAcceleration[nDim * p + i] += F3B4 * CLS * lift[i] / (m_densityRatio * diameter);
7472 m_particleVelocity[nDim * p + i] =
7473 m_particleVelocityDt1[nDim * p + i]
7474 + dt * F1B2 * (m_particleAcceleration[nDim * p + i] + m_particleAccelerationDt1[nDim * p + i]);
7475 m_particleCoords[nDim * p + i] =
7476 m_particleCoordsDt1[nDim * p + i]
7477 + dt * F1B2 * (m_particleVelocity[nDim * p + i] + m_particleVelocityDt1[nDim * p + i]);
7478 }
7479
7480 // Temperature update
7481 const MFloat particleSurface = PI * POW2(diameter);
7482 const MFloat mass = F1B6 * PI * POW3(diameter) * m_densityRatio * m_rhoInfinity;
7483 // See Whitaker 1972, AIChE Journal, Attention: not validated for Re < 4,
7484 // Nu = 2 for Re -> 0 is a solution of Stokes flow
7485 const MFloat mueParticle = SUTHERLANDLAW(m_particleTemperature[p]);
7486 const MFloat nusselt =
7487 F2
7488 + pow(m_Pr, 2.0 / 5.0) * (2.0 / 5.0 * pow(Rep, F1B2) + 0.06 * pow(Rep, F2B3)) * pow(mue / mueParticle, 0.25);
7489 const MFloat lambdaFluid = (T * sqrt(T) * m_sutherlandPlusOneThermal) / (T + m_sutherlandConstantThermal);
7490 const MFloat alpha = nusselt * lambdaFluid / diameter;
7491 const MFloat deltaT = m_particleFluidTemperature[p] - m_particleTemperature[p];
7492 m_particleHeatFlux[p] = (particleSurface * alpha * m_gamma) / (mass * Cvp * m_Pr * sysEqn().m_Re0) * deltaT;
7493 m_particleTemperature[p] =
7494 F1B2 * (m_particleTemperature[p] + m_particleTemperatureDt1[p] + dt * m_particleHeatFlux[p]);
7495 }
7496 //}
7497 } else if(m_pointParticleType == 3) {
7498 const MFloat dt = timeStep();
7499 const MFloat dt2 = F1B2 * timeStep();
7500 MFloatScratchSpace K(3, 3, AT_, "K");
7501 MFloatScratchSpace R(3, 3, AT_, "R");
7502 MFloatScratchSpace W(4, 4, AT_, "W");
7503 MFloatScratchSpace rhs(4, AT_, "rhs");
7504
7505 MFloat q[3];
7506 MFloat q0[3];
7507 MFloat tq[3];
7508 MFloat tq0[3];
7509 MFloat vrel[3];
7510 MFloat vrelhat[3];
7511 MFloat tmp[3];
7512 MFloat vort[3];
7513 MFloat strain[3];
7514
7515 // 1. predictor step
7516 for(MInt p = 0; p < m_noPointParticlesLocal; p++) {
7517 const MFloat w = m_particleQuaternionsDt1[4 * p + 0];
7518 const MFloat x = m_particleQuaternionsDt1[4 * p + 1];
7519 const MFloat y = m_particleQuaternionsDt1[4 * p + 2];
7520 const MFloat z = m_particleQuaternionsDt1[4 * p + 3];
7521 for(MInt i = 0; i < 3; i++) {
7522 q0[i] = m_particleAngularVelocityDt1[3 * p + i];
7523 }
7524 m_particleQuaternions[4 * p + 0] = w + F1B2 * dt * (-x * q0[0] - y * q0[1] - z * q0[2]);
7525 m_particleQuaternions[4 * p + 1] = x + F1B2 * dt * (w * q0[0] - z * q0[1] + y * q0[2]);
7526 m_particleQuaternions[4 * p + 2] = y + F1B2 * dt * (z * q0[0] + w * q0[1] - x * q0[2]);
7527 m_particleQuaternions[4 * p + 3] = z + F1B2 * dt * (-y * q0[0] + x * q0[1] + w * q0[2]);
7528 for(MInt i = 0; i < 3; i++) {
7529 m_particleAngularVelocity[3 * p + i] =
7530 m_particleAngularVelocityDt1[3 * p + i] + dt * m_particleAngularAccelerationDt1[3 * p + i];
7531 }
7532 for(MInt i = 0; i < nDim; i++) {
7533 m_particleCoords[nDim * p + i] =
7534 m_particleCoordsDt1[nDim * p + i]
7535 + F1B2 * dt * (m_particleVelocity[nDim * p + i] + m_particleVelocityDt1[nDim * p + i])
7536 + F1B4 * POW2(dt) * (m_particleAcceleration[nDim * p + i] + m_particleAccelerationDt1[nDim * p + i]);
7537 m_particleVelocity[nDim * p + i] =
7538 m_particleVelocityDt1[nDim * p + i] + dt * m_particleAcceleration[nDim * p + i];
7539 }
7540
7541 m_particleTemperature[p] = m_particleTemperatureDt1[p] + dt * m_particleHeatFlux[p];
7542 }
7543
7544 // 2. compute fluid velocity
7545 setParticleFluidVelocities();
7546
7547 // 3. correction step
7548 for(MInt p = 0; p < m_noPointParticlesLocal; p++) {
7549 const MInt cellId = m_particleCellLink[p];
7550 const MFloat beta = m_particleRadii[3 * p + 2] / m_particleRadii[3 * p];
7551 const MFloat beta2 = POW2(beta);
7552 const MFloat radius = pow(m_particleRadii[3 * p] * m_particleRadii[3 * p + 1] * m_particleRadii[3 * p + 2], F1B3);
7553 const MFloat diameter = F2 * radius;
7554 const MFloat T = sysEqn().temperature_ES(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
7555 const MFloat mue = SUTHERLANDLAW(T);
7556 const MFloat taup = F2 * m_densityRatio * POW2(radius) / (9.0 * mue / sysEqn().m_Re0);
7557 const MFloat FAC = (8.0 / 3.0) * pow(beta, F2B3) / taup;
7558 const MFloat FAC2 = (40.0 / 9.0) * pow(beta, F2B3) / taup;
7559 const MFloat FAC0 = (9.0 / 2.0) * mue / (sysEqn().m_Re0 * m_densityRatio * m_rhoInfinity * POW2(radius));
7560
7561 // integrate angular velocity
7562 const MInt maxit = 100;
7563 MFloat delta = F1;
7564 MInt it = 0;
7565
7566 W(0, 0) = F1 + dt2 * FAC2 / (m_particleShapeParams[4 * p + 1] + beta2 * m_particleShapeParams[4 * p + 3]);
7567 W(1, 1) = F1 + dt2 * FAC2 / (m_particleShapeParams[4 * p + 1] + beta2 * m_particleShapeParams[4 * p + 3]);
7568 W(2, 2) = F1 + dt2 * FAC2 / (F2 * m_particleShapeParams[4 * p + 1]);
7569 W(2, 0) = F0;
7570 W(2, 1) = F0;
7571 for(MInt i = 0; i < 3; i++) {
7572 tq0[i] = m_particleAngularAccelerationDt1[3 * p + i];
7573 q0[i] = m_particleAngularVelocityDt1[3 * p + i];
7574 tq[i] = tq0[i];
7575 q[i] = q0[i];
7576 }
7577
7578 for(MInt i = 0; i < 3; i++) {
7579 MInt id0 = (i + 1) % 3;
7580 MInt id1 = (id0 + 1) % 3;
7581 strain[i] = F1B2
7582 * (m_particleVelocityGradientFluid[9 * p + 3 * id1 + id0]
7583 + m_particleVelocityGradientFluid[9 * p + 3 * id0 + id1]);
7584 vort[i] = F1B2
7585 * (m_particleVelocityGradientFluid[9 * p + 3 * id1 + id0]
7586 - m_particleVelocityGradientFluid[9 * p + 3 * id0 + id1]);
7587 }
7588
7589 // Newton iterations
7590 while(delta > 1e-10 && it < maxit) {
7591 W(0, 1) = -dt2 * q[2] * (beta2 - F1) / (beta2 + F1);
7592 W(0, 2) = -dt2 * q[1] * (beta2 - F1) / (beta2 + F1);
7593 W(1, 0) = -dt2 * q[2] * (F1 - beta2) / (beta2 + F1);
7594 W(1, 2) = -dt2 * q[0] * (F1 - beta2) / (beta2 + F1);
7595
7596 maia::math::invert(&W(0, 0), 3, 3);
7597
7598 tq[0] = q[1] * q[2] * (beta2 - F1) / (beta2 + F1)
7599 + FAC2 * (((F1 - beta2) / (F1 + beta2)) * strain[0] + vort[0] - q[0])
7600 / (m_particleShapeParams[4 * p + 1] + beta2 * m_particleShapeParams[4 * p + 3]);
7601 tq[1] = q[0] * q[2] * (F1 - beta2) / (beta2 + F1)
7602 + FAC2 * (((beta2 - F1) / (F1 + beta2)) * strain[1] + vort[1] - q[1])
7603 / (m_particleShapeParams[4 * p + 1] + beta2 * m_particleShapeParams[4 * p + 3]);
7604 tq[2] = FAC2 * (vort[2] - q[2]) / (F2 * m_particleShapeParams[4 * p + 1]);
7605
7606 for(MInt i = 0; i < 3; i++)
7607 rhs[i] = q[i] - q0[i] - dt2 * (tq0[i] + tq[i]);
7608
7609 delta = F0;
7610 for(MInt i = 0; i < 3; i++) {
7611 const MFloat qq = q[i];
7612 for(MInt j = 0; j < 3; j++) {
7613 q[i] -= W(i, j) * rhs(j);
7614 }
7615 delta = mMax(delta, fabs(q[i] - qq));
7616 }
7617 it++;
7618 }
7619 if(it >= maxit || it <= 0) {
7620 cerr << "Newton iterations did not converge " << p << endl;
7621 }
7622
7623 m_particleAngularVelocity[3 * p + 0] = q[0];
7624 m_particleAngularVelocity[3 * p + 1] = q[1];
7625 m_particleAngularVelocity[3 * p + 2] = q[2];
7626 m_particleAngularAcceleration[3 * p + 0] = tq[0];
7627 m_particleAngularAcceleration[3 * p + 1] = tq[1];
7628 m_particleAngularAcceleration[3 * p + 2] = tq[2];
7629
7630 // integrate quaternions
7631 const MFloat w = m_particleQuaternionsDt1[4 * p + 0];
7632 const MFloat x = m_particleQuaternionsDt1[4 * p + 1];
7633 const MFloat y = m_particleQuaternionsDt1[4 * p + 2];
7634 const MFloat z = m_particleQuaternionsDt1[4 * p + 3];
7635
7636 W(0, 0) = F0;
7637 W(0, 1) = -q[0];
7638 W(0, 2) = -q[1];
7639 W(0, 3) = -q[2];
7640 W(1, 0) = q[0];
7641 W(1, 1) = F0;
7642 W(1, 2) = q[2];
7643 W(1, 3) = -q[1];
7644 W(2, 0) = q[1];
7645 W(2, 1) = -q[2];
7646 W(2, 2) = F0;
7647 W(2, 3) = q[0];
7648 W(3, 0) = q[2];
7649 W(3, 1) = q[1];
7650 W(3, 2) = -q[0];
7651 W(3, 3) = F0;
7652
7653 for(MInt i = 0; i < 4; i++)
7654 for(MInt j = 0; j < 4; j++)
7655 W(i, j) = -F1B2 * dt2 * W(i, j);
7656 for(MInt i = 0; i < 4; i++)
7657 W(i, i) = F1;
7658
7659 rhs(0) = w + F1B2 * dt2 * (-x * q0[0] - y * q0[1] - z * q0[2]);
7660 rhs(1) = x + F1B2 * dt2 * (w * q0[0] - z * q0[1] + y * q0[2]);
7661 rhs(2) = y + F1B2 * dt2 * (z * q0[0] + w * q0[1] - x * q0[2]);
7662 rhs(3) = z + F1B2 * dt2 * (-y * q0[0] + x * q0[1] + w * q0[2]);
7663
7664 maia::math::invert(&W(0, 0), 4, 4);
7665
7666 for(MInt i = 0; i < 4; i++) {
7667 m_particleQuaternions[4 * p + i] = F0;
7668 for(MInt j = 0; j < 4; j++) {
7669 m_particleQuaternions[4 * p + i] += W(i, j) * rhs(j);
7670 }
7671 }
7672
7673 MFloat abs = F0;
7674 for(MInt i = 0; i < 4; i++)
7675 abs += POW2(m_particleQuaternions[4 * p + i]);
7676 for(MInt i = 0; i < 4; i++)
7677 m_particleQuaternions[4 * p + i] /= sqrt(abs);
7678
7679 // integrate linear motion
7680 K.fill(F0);
7681 K(0, 0) = F1 / (m_particleShapeParams[4 * p] / POW2(m_particleRadii[3 * p]) + m_particleShapeParams[4 * p + 1]);
7682 K(1, 1) = K(0, 0);
7683 K(2, 2) =
7684 F1 / (m_particleShapeParams[4 * p] / POW2(m_particleRadii[3 * p]) + beta2 * m_particleShapeParams[4 * p + 3]);
7685 computeRotationMatrix(R, &(m_particleQuaternions[4 * p]));
7686 for(MInt i = 0; i < nDim; i++) {
7687 vrel[i] = m_particleVelocityFluid[nDim * p + i] - m_particleVelocity[nDim * p + i];
7688 }
7689 matrixVectorProduct(vrelhat, R, vrel); // principal axes frame relative velocity
7690 matrixVectorProduct(tmp, K, vrelhat);
7691 matrixVectorProductTranspose(vrel, R, tmp);
7692
7693 for(MInt i = 0; i < nDim; i++) {
7694 m_particleAcceleration[nDim * p + i] = FAC * vrel[i] + FAC0 * m_particleTerminalVelocity[i];
7695 m_particleVelocity[nDim * p + i] =
7696 m_particleVelocityDt1[nDim * p + i]
7697 + dt * F1B2 * (m_particleAcceleration[nDim * p + i] + m_particleAccelerationDt1[nDim * p + i]);
7698 m_particleCoords[nDim * p + i] =
7699 m_particleCoordsDt1[nDim * p + i]
7700 + dt * F1B2 * (m_particleVelocity[nDim * p + i] + m_particleVelocityDt1[nDim * p + i])
7701 + F1B4 * POW2(dt) * (m_particleAcceleration[nDim * p + i] + m_particleAccelerationDt1[nDim * p + i]);
7702 }
7703
7704 // temperature update
7705 const MFloat mass = F4B3 * PI * m_particleRadii[3 * p] * m_particleRadii[3 * p + 1] * m_particleRadii[3 * p + 2]
7706 * m_densityRatio * m_rhoInfinity;
7707 const MFloat Cvp = m_capacityConstantVolumeRatio;
7708
7709 MFloat particleSurface = 0;
7710 if(fabs(beta - F1) < 1e-14)
7711 particleSurface = 4 * PI * POW2(m_particleRadii[3 * p]);
7712 else {
7713 if(beta < 1) {
7714 const MFloat factor = sqrt(1 - beta2);
7715 particleSurface =
7716 2 * PI * m_particleRadii[3 * p] * m_particleRadii[3 * p + 1] * (1 + (beta2 / factor * atanh(factor)));
7717 } else {
7718 const MFloat factor = sqrt(1 - 1 / beta2);
7719 particleSurface = 2 * PI * m_particleRadii[3 * p] * m_particleRadii[3 * p + 1]
7720 * (1 + m_particleRadii[3 * p + 2] / (m_particleRadii[3 * p] * factor) * asin(factor));
7721 }
7722 }
7723
7724 // nusselt correlation for sphere in Stokesian flow
7725 const MFloat nusselt = 2;
7726 const MFloat lambdaFluid = (T * sqrt(T) * m_sutherlandPlusOneThermal) / (T + m_sutherlandConstantThermal);
7727 const MFloat alpha = nusselt * lambdaFluid / diameter;
7728 const MFloat deltaT = m_particleFluidTemperature[p] - m_particleTemperature[p];
7729 m_particleHeatFlux[p] = (particleSurface * alpha * m_gamma) / (mass * Cvp * m_Pr * sysEqn().m_Re0) * deltaT;
7730 m_particleTemperature[p] =
7731 F1B2 * (m_particleTemperature[p] + m_particleTemperatureDt1[p] + dt * m_particleHeatFlux[p]);
7732 }
7733 } else {
7734 mTerm(1, AT_, "part type.");
7735 }
7736}
7737
7738
7743template <MInt nDim, class SysEqn>
7745 IF_CONSTEXPR(nDim == 2) mTerm(1, AT_, "Go for 3D.");
7746
7747 const MBool fourthOrder = false;
7748 const MInt maxNoNghbrs = 150;
7749 const MInt recDim = fourthOrder ? 19 : 10;
7750
7751 MIntScratchSpace nghbrList(maxNoNghbrs, AT_, "nghbrList");
7752 MIntScratchSpace layerId(maxNoNghbrs, AT_, "layerList");
7753 MFloatScratchSpace mat(maxNoNghbrs, recDim, AT_, "mat");
7754
7755 nghbrList.fill(-1);
7756 for(MUint p = 0; p < m_particleCellLink.size(); p++) {
7757 const MInt cellId = m_particleCellLink[p];
7758 const MFloat normalizationFactor =
7759 F1 / c_cellLengthAtCell(cellId); // scaling factor to reduce the condition number of the resulting eq. sys.
7760 const MInt counter = 1 + this->template getAdjacentLeafCells<2>(cellId, 1, nghbrList, layerId);
7761 for(MInt i = counter - 1; i > 0; i--)
7762 nghbrList[i] = nghbrList[i - 1];
7763 nghbrList[0] = cellId;
7764 mat.fill(F0);
7765 for(MInt c = 0; c < counter; c++) {
7766 const MInt nghbrId = nghbrList(c);
7767 MFloat deltaX[3];
7768
7769 for(MInt i = 0; i < nDim; i++) {
7770 deltaX[i] = (a_coordinate(nghbrId, i) - m_particleCoords[nDim * p + i]) * normalizationFactor;
7771 }
7772
7773 MInt cnt = 0;
7774 mat(c, cnt) = F1;
7775 cnt++;
7776 for(MInt i = 0; i < nDim; i++) {
7777 mat(c, cnt) = deltaX[i];
7778 cnt++;
7779 }
7780 for(MInt i = 0; i < nDim; i++) {
7781 for(MInt j = i; j < nDim; j++) {
7782 const MFloat fac = (i == j) ? F1B2 : F1;
7783 mat(c, cnt) = fac * deltaX[i] * deltaX[j];
7784 cnt++;
7785 }
7786 }
7787 if(fourthOrder) {
7788 for(MInt i = 0; i < nDim; i++) {
7789 for(MInt j = i; j < nDim; j++) {
7790 for(MInt k = j; k < nDim; k++) {
7791 const MFloat fac = (i == j && i == k) ? F1B6 : ((i == j || i == k || j == k) ? F1B2 : F1);
7792 mat(c, cnt) = fac * deltaX[i] * deltaX[j] * deltaX[k];
7793 cnt++;
7794 }
7795 }
7796 }
7797 }
7798 }
7799 maia::math::invert(&mat(0, 0), counter, recDim);
7800
7801 for(MInt c = 0; c < counter; c++) {
7802 MInt cnt = 1;
7803 for(MInt i = 0; i < nDim; i++) {
7804 mat(cnt, c) *= normalizationFactor;
7805 cnt++;
7806 }
7807 for(MInt i = 0; i < nDim; i++) {
7808 for(MInt j = i; j < nDim; j++) {
7809 mat(cnt, c) *= POW2(normalizationFactor);
7810 cnt++;
7811 }
7812 }
7813 if(fourthOrder) {
7814 for(MInt i = 0; i < nDim; i++) {
7815 for(MInt j = i; j < nDim; j++) {
7816 for(MInt k = j; k < nDim; k++) {
7817 mat(cnt, c) *= POW3(normalizationFactor);
7818 cnt++;
7819 }
7820 }
7821 }
7822 }
7823 }
7824
7825 MFloatScratchSpace R(3, 3, AT_, "R");
7826 computeRotationMatrix(R, &(m_particleQuaternions[4 * p]));
7827
7828 for(MInt i = 0; i < nDim; i++) {
7829 m_particleVelocityFluid[nDim * p + i] = F0;
7830 }
7831 m_particleFluidTemperature[p] = F0;
7832 for(MInt c = 0; c < counter; c++) {
7833 for(MInt i = 0; i < nDim; i++) {
7834 m_particleVelocityFluid[nDim * p + i] += mat(0, c) * a_pvariable(nghbrList[c], PV->VV[i]);
7835 }
7836 m_particleFluidTemperature[p] +=
7837 mat(0, c) * sysEqn().temperature_ES(a_pvariable(nghbrList[c], PV->RHO), a_pvariable(nghbrList[c], PV->P));
7838 }
7839
7840 MFloat velGrad[3][3] = {{F0, F0, F0}, {F0, F0, F0}, {F0, F0, F0}};
7841 for(MInt c = 0; c < counter; c++) {
7842 MFloat coeffs0[3] = {mat(1, c), mat(2, c), mat(3, c)};
7843 MFloat vel0[3] = {a_pvariable(nghbrList[c], PV->U), a_pvariable(nghbrList[c], PV->V),
7844 a_pvariable(nghbrList[c], PV->W)};
7845 MFloat coeffs[3];
7846 MFloat vel[3];
7847 matrixVectorProduct(coeffs, R, coeffs0);
7848 matrixVectorProduct(vel, R, vel0);
7849 for(MInt i = 0; i < nDim; i++) {
7850 for(MInt j = 0; j < nDim; j++) {
7851 velGrad[i][j] += coeffs[j] * vel[i];
7852 }
7853 }
7854 }
7855
7856 for(MInt i = 0; i < nDim; i++) {
7857 for(MInt j = 0; j < nDim; j++) {
7858 m_particleVelocityGradientFluid[9 * p + 3 * i + j] = velGrad[i][j];
7859 }
7860 }
7861
7862 if(pressure != nullptr) {
7863 pressure[p] = F0;
7864 for(MInt c = 0; c < counter; c++) {
7865 pressure[p] += mat(0, c) * a_pvariable(nghbrList[c], PV->P);
7866 }
7867 }
7868 }
7869}
7870
7871
7876template <MInt nDim, class SysEqn>
7877template <class _, std::enable_if_t<nDim == 3, _*>>
7879 rebuildKDTree();
7880
7881 if(m_noLevelSetsUsedForMb > 1 && m_buildCollectedLevelSetFunction) {
7882 const MFloat delta0 = F2 * c_cellLengthAtLevel(maxRefinementLevel());
7883 const MFloat deltaMax = F2 * m_maxBodyRadius + delta0;
7884 MIntScratchSpace nearBodies(m_noEmbeddedBodies, AT_, "nearBodies");
7885 MFloatScratchSpace minDist(m_noLevelSetsUsedForMb, AT_, "minDist");
7886
7887 for(MInt i = 0; i < m_noLevelSetsUsedForMb; i++) {
7888 for(MInt j = 0; j < m_maxNoEmbeddedBodiesPeriodic; j++) {
7889 m_setToBodiesTable[i][j] = -1;
7890 }
7891 m_noBodiesInSet[i] = 0;
7892 }
7893 for(MInt i = 0; i < m_maxNoEmbeddedBodiesPeriodic; i++) {
7894 m_bodyToSetTable[i] = -1;
7895 }
7896 if(m_startSet > 0) {
7897 m_noBodiesInSet[0] = 0;
7898 for(MInt i = 0; i < m_noEmbeddedBodies + m_noPeriodicGhostBodies; i++) {
7899 m_setToBodiesTable[0][m_noBodiesInSet[0]] = i;
7900 m_noBodiesInSet[0]++;
7901 }
7902 }
7903 m_noSets = m_startSet;
7904
7905
7906 for(MInt p = 0; p < m_noEmbeddedBodies + m_noPeriodicGhostBodies; p++) {
7907 MInt id = m_startSet;
7908
7909 if(m_noEmbeddedBodies > (m_noLevelSetsUsedForMb - m_startSet)) {
7910 Point<3> pt(m_bodyCenter[p * nDim], m_bodyCenter[p * nDim + 1], m_bodyCenter[p * nDim + 2]);
7911 MInt noNearBodies = locatenear(pt, deltaMax, &nearBodies[0], m_noEmbeddedBodies);
7912 MBool overlap = true;
7913 minDist.fill(c_cellLengthAtLevel(0));
7914
7915 while(overlap && id < m_noLevelSetsUsedForMb) {
7916 overlap = false;
7917 for(MInt b = 0; b < noNearBodies; b++) {
7918 const MInt q = nearBodies[b];
7919 if(p == q) continue;
7920 if(m_bodyToSetTable[q] == id) {
7921 overlap = true;
7922 MFloat dist = sqrt(POW2(m_bodyCenter[p * nDim] - m_bodyCenter[q * nDim])
7923 + POW2(m_bodyCenter[p * nDim + 1] - m_bodyCenter[q * nDim + 1])
7924 + POW2(m_bodyCenter[p * nDim + 2] - m_bodyCenter[q * nDim + 2]))
7925 - F2 * m_maxBodyRadius;
7926 minDist(id) = mMin(minDist(id), dist);
7927 ASSERT(dist < delta0 + m_eps, "");
7928 break;
7929 }
7930 }
7931 if(overlap) id++;
7932 }
7933
7934 if(overlap) {
7935 id = m_startSet;
7936 for(MInt i = m_startSet; i < m_noLevelSetsUsedForMb; i++) {
7937 if(minDist(i) > minDist(id)) id = i;
7938 }
7939
7940 cerr0 << domainId() << ": Not enough level sets to prevent overlap: " << p << " " << id << " "
7941 << minDist(id) / c_cellLengthAtLevel(m_lsCutCellMinLevel) << " " << m_maxBodyRadius << endl;
7942 }
7943
7944 m_bodyToSetTable[p] = id;
7945 m_setToBodiesTable[id][m_noBodiesInSet[id]] = p;
7946 m_noBodiesInSet[id]++;
7947 } else {
7948 id = m_startSet + p % (m_noLevelSetsUsedForMb - 1);
7949 if(id >= m_noLevelSetsUsedForMb) mTerm(1, AT_, "Wrong set handling");
7950 m_bodyToSetTable[p] = id;
7951 m_setToBodiesTable[id][m_noBodiesInSet[id]] = p;
7952 m_noBodiesInSet[id]++;
7953 }
7954 m_noSets = mMax(m_noSets, id + 1);
7955 }
7956 }
7957
7958 updateGeometry();
7959}
7960
7961
7966template <MInt nDim, class SysEqn>
7967template <class _, std::enable_if_t<nDim == 2, _*>>
7969
7970
7975template <MInt nDim, class SysEqn>
7977 TRACE();
7978
7979 m_noPeriodicGhostBodies = 0;
7980 if(grid().periodicCartesianDir(0) + grid().periodicCartesianDir(1) + grid().periodicCartesianDir(2) == 0) return;
7981 if(m_bodyTypeMb == 2) return;
7982 if(grid().azimuthalPeriodicity()) {
7983 return;
7984 }
7985
7986 MFloat dx[3];
7987 for(MInt i = 0; i < nDim; i++) {
7988 dx[i] = m_bbox[nDim + i] - m_bbox[i];
7989 }
7990
7991 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
7992 // 1. periodic correction of internal body
7993 m_internalBodyId[b] = b;
7994 for(MInt i = 0; i < nDim; i++) {
7995 const MFloat displ = m_bodyCenter[b * nDim + i] - m_bodyCenterDt1[b * nDim + i];
7996 const MFloat displ2 = (m_motionEquation > 1) ? m_bodyCenter[b * nDim + i] - m_bodyCenterDt2[b * nDim + i] : F0;
7997 if(m_bodyCenter[b * nDim + i] < m_bbox[i]) {
7998 m_bodyCenter[b * nDim + i] += dx[i];
7999 } else if(m_bodyCenter[b * nDim + i] > m_bbox[nDim + i]) {
8000 m_bodyCenter[b * nDim + i] -= dx[i];
8001 }
8002 m_bodyCenterDt1[b * nDim + i] = m_bodyCenter[b * nDim + i] - displ;
8003 if(m_motionEquation > 1) {
8004 m_bodyCenterDt2[b * nDim + i] = m_bodyCenter[b * nDim + i] - displ2;
8005 }
8006 }
8007
8008 // 2. add periodic ghost bodies if needed
8009 m_periodicGhostBodies[b].clear();
8010 IF_CONSTEXPR(nDim == 2) {
8011 if(m_bodyCenter[b * nDim] > m_bbox[0] + m_periodicGhostBodyDist
8012 && m_bodyCenter[b * nDim] < m_bbox[3] - m_periodicGhostBodyDist
8013 && m_bodyCenter[b * nDim + 1] > m_bbox[1] + m_periodicGhostBodyDist
8014 && m_bodyCenter[b * nDim + 1] < m_bbox[4] - m_periodicGhostBodyDist) {
8015 continue;
8016 }
8017 }
8018 else IF_CONSTEXPR(nDim == 3) {
8019 if(m_bodyCenter[b * nDim] > m_bbox[0] + m_periodicGhostBodyDist
8020 && m_bodyCenter[b * nDim] < m_bbox[3] - m_periodicGhostBodyDist
8021 && m_bodyCenter[b * nDim + 1] > m_bbox[1] + m_periodicGhostBodyDist
8022 && m_bodyCenter[b * nDim + 1] < m_bbox[4] - m_periodicGhostBodyDist
8023 && m_bodyCenter[b * nDim + 2] > m_bbox[2] + m_periodicGhostBodyDist
8024 && m_bodyCenter[b * nDim + 2] < m_bbox[5] - m_periodicGhostBodyDist) {
8025 continue;
8026 }
8027 }
8028 for(MInt s0 = -1; s0 <= 1; s0++) {
8029 if(s0 != 0 && !grid().periodicCartesianDir(0)) continue;
8030 for(MInt s1 = -1; s1 <= 1; s1++) {
8031 if(s1 != 0 && !grid().periodicCartesianDir(1)) continue;
8032 for(MInt s2 = -1; s2 <= 1; s2++) {
8033 if(s2 != 0 && !grid().periodicCartesianDir(2)) continue;
8034 if(s0 == 0 && s1 == 0 && s2 == 0) continue;
8035 MFloat sign[3] = {((MFloat)s0), ((MFloat)s1), ((MFloat)s2)};
8036 MFloat coords[3] = {F0, F0, F0};
8037 MBool tooFar = false;
8038 for(MInt i = 0; i < nDim; i++) {
8039 coords[i] = m_bodyCenter[b * nDim + i] + sign[i] * dx[i];
8040 if(coords[i] < m_bbox[i] - m_periodicGhostBodyDist
8041 || coords[i] > m_bbox[nDim + i] + m_periodicGhostBodyDist)
8042 tooFar = true;
8043 }
8044 if(tooFar) continue;
8045 const MInt k = m_noEmbeddedBodies + m_noPeriodicGhostBodies;
8046 if(k >= m_maxNoEmbeddedBodiesPeriodic)
8047 mTerm(1, AT_,
8048 "Increase m_maxNoEmbeddedBodiesPeriodic " + to_string(m_noEmbeddedBodies) + " "
8049 + to_string(m_noPeriodicGhostBodies));
8050 transferBodyState(k, b);
8051 for(MInt i = 0; i < nDim; i++) {
8052 m_bodyCenter[k * nDim + i] = coords[i];
8053 }
8054 m_internalBodyId[k] = b;
8055 m_periodicGhostBodies[b].push_back(k);
8056 m_noPeriodicGhostBodies++;
8057 }
8058 }
8059 }
8060 }
8061
8062 if(globalTimeStep > m_restartTimeStep && globalTimeStep % m_restartInterval == 0) {
8063 m_log << "No periodic ghost bodies: " << m_noPeriodicGhostBodies << " ("
8064 << 100.0 * ((MFloat)m_noPeriodicGhostBodies) / ((MFloat)m_noEmbeddedBodies) << "%)" << endl;
8065 }
8066}
8067
8068
8073template <MInt nDim, class SysEqn>
8075 // TRACE();
8076
8077 m_bodyRadius[k] = m_bodyRadius[b];
8078 m_bodyDiameter[k] = m_bodyDiameter[b];
8079 for(MInt i = 0; i < nDim; i++) {
8080 m_bodyVelocity[k * nDim + i] = m_bodyVelocity[b * nDim + i];
8081 m_bodyAcceleration[k * nDim + i] = m_bodyAcceleration[b * nDim + i];
8082 }
8083 for(MInt i = 0; i < 3; i++) {
8084 m_bodyRadii[k * 3 + i] = m_bodyRadii[b * 3 + i];
8085 m_bodyAngularVelocity[k * 3 + i] = m_bodyAngularVelocity[b * 3 + i];
8086 m_bodyAngularAcceleration[k * 3 + i] = m_bodyAngularAcceleration[b * 3 + i];
8087 }
8088 for(MInt i = 0; i < 4; i++) {
8089 m_bodyQuaternion[k * 4 + i] = m_bodyQuaternion[b * 4 + i];
8090 }
8091}
8092
8093
8099template <MInt nDim, class SysEqn>
8101 TRACE();
8102
8103 ASSERT(!m_LsMovement, "");
8104
8105 for(MInt body = 0; body < m_noEmbeddedBodies; body++) {
8106 MFloat bodyRotation[3] = {0};
8107 getBodyRotation(body, bodyRotation);
8108
8109 switch(m_bodyEquation[body]) {
8110 // for motionEquation == 0 && !m_constructGField: m_bodyEquation = 4520 !!
8111
8112 // vortex pair-cylinder interaction
8113 case 120: {
8114 MFloat timeOffset = F0;
8115 timeOffset = Context::getSolverProperty<MFloat>("timeOffset", m_solverId, AT_, &timeOffset);
8116 MFloat targetBodyVelocity = F0;
8117 targetBodyVelocity =
8118 Context::getSolverProperty<MFloat>("targetBodyVelocity", m_solverId, AT_, &targetBodyVelocity);
8119
8120 m_bodyCenter[0] += m_bodyVelocity[0] * timeStep();
8121 m_bodyVelocity[0] = targetBodyVelocity * m_UInfinity * F1B2 * (tanh(100.0 * (m_time - timeOffset)) + F1);
8122 m_bodyAcceleration[0] =
8123 targetBodyVelocity * m_UInfinity * F1B2
8124 * (tanh(100.0 * (m_time + 0.0001 - timeOffset)) - tanh(100.0 * (m_time - 0.0001 - timeOffset))) / 0.0002;
8125 cerr << "DEBUG DANIEL " << globalTimeStep << " " << m_time << " " << m_bodyCenter[0] << " " << m_bodyVelocity[0]
8126 << " " << m_bodyAcceleration[0] << endl;
8127
8128 break;
8129 }
8130 case 401: {
8131 // temporal offset
8132 MFloat timeOffset = F0; // 100.;
8133
8134 // transversely oscillating cylinder
8135 // MFloat deltaT = timeStep();
8136 // if ( m_dualTimeStepping ) deltaT = m_physicalTimeStep;
8137 MFloat elapsedTime = m_physicalTime - timeOffset;
8138
8139 const MFloat D = F2 * m_bodyRadius[0];
8151 MFloat amplitudeFactor = 0.1;
8152 amplitudeFactor = Context::getSolverProperty<MFloat>("amplitudeFactor", m_solverId, AT_, &amplitudeFactor);
8153
8165 MFloat freqFactor = F1;
8166 freqFactor = Context::getSolverProperty<MFloat>("freqFactor", m_solverId, AT_, &freqFactor);
8167 MFloat Strouhal = 0.194;
8168 Strouhal = Context::getSolverProperty<MFloat>("Strouhal", m_solverId, AT_, &Strouhal);
8169 const MFloat A = amplitudeFactor * D;
8170 const MFloat freq0 =
8171 Strouhal * m_UInfinity / m_referenceLength; // if integrating with m_timestep*m_timeRef only take Strouhal
8172 const MFloat mu = freqFactor * freq0 * F2 * PI;
8173
8174 if(elapsedTime > F0) {
8175 m_bodyCenter[1] = -A * cos(mu * elapsedTime);
8176 m_bodyVelocity[1] = mu * A * sin(mu * elapsedTime);
8177 m_bodyAcceleration[1] = mu * mu * A * cos(mu * elapsedTime);
8178 } else {
8179 m_bodyCenter[1] = -A;
8180 m_bodyVelocity[1] = F0;
8181 m_bodyAcceleration[1] = F0;
8182 }
8183
8184 break;
8185 }
8186
8187 // startup of a cylinder
8188 case 402: {
8189 MFloat deltaT = timeStep();
8190 if(m_dualTimeStepping) forceTimeStep(m_physicalTimeStep);
8191 for(MInt i = 0; i < nDim; i++) {
8192 m_bodyVelocity[i] = m_VVInfinity[i];
8193 m_bodyCenter[i] += deltaT * m_bodyVelocity[i];
8194 }
8195 break;
8196 }
8197
8198 // inline oscillating cylinder
8199 case 403: {
8200 const MFloat KC = 5.0;
8201 const MFloat frequency = m_UInfinity / KC;
8202
8203 m_bodyVelocity[0] = KC * frequency * cos(F2 * PI * frequency * m_time);
8204 m_bodyVelocity[1] = F0;
8205 m_bodyCenter[0] = KC / (F2 * PI) * sin(F2 * PI * frequency * m_time);
8206 m_bodyCenter[1] = F0;
8207
8208 break;
8209 }
8210
8211
8212 case 466: {
8213 break;
8214 }
8215
8216 default: {
8217 // const MFloat deltaT = m_dualTimeStepping ? m_physicalTimeStep : timeStep();
8218 const MFloat deltaT = m_physicalTime - m_physicalTimeDt1;
8219 for(MInt i = 0; i < nDim; i++) {
8220 m_bodyCenter[nDim * body + i] = m_bodyCenterDt1[nDim * body + i] + deltaT * m_bodyVelocity[nDim * body + i];
8221 }
8222
8223 break;
8224 }
8225
8226 // cylinder drifiting in uniform flow
8227 case 474: {
8228 for(MInt i = 0; i < nDim; i++) {
8229 m_bodyCenter[i] = F0;
8230 m_bodyVelocity[i] = F0;
8231 m_bodyAcceleration[i] = F0;
8232 }
8233 m_bodyCenter[0] = m_UInfinity * m_physicalTime;
8234 m_bodyVelocity[0] = m_UInfinity;
8235 break;
8236 }
8237
8238 // cylinder towed through quiescent fluid
8239 case 475: {
8240 for(MInt i = 0; i < nDim; i++) {
8241 m_bodyCenter[i] = F0;
8242 m_bodyVelocity[i] = F0;
8243 m_bodyAcceleration[i] = F0;
8244 }
8245 const MFloat T1 = 20.0;
8246 const MFloat t = m_physicalTime / T1;
8247 if(t > F1) {
8248 m_bodyCenter[0] = m_UInfinity * (m_physicalTime - F1B2 * T1);
8249 m_bodyVelocity[0] = m_UInfinity;
8250 m_bodyAcceleration[0] = F0;
8251 } else {
8252 m_bodyCenter[0] = m_UInfinity * POW3(t) * T1 * (F1 - F1B2 * t);
8253 m_bodyVelocity[0] = m_UInfinity * POW2(t) * (F3 - F2 * t);
8254 m_bodyAcceleration[0] = m_UInfinity * F6 * t * (F1 - t) / T1;
8255 }
8256 break;
8257 }
8258
8259 case 450: {
8260 // transversely oscillating cylinder
8261 MFloat ddt = F0;
8262 MFloat elapsedTime = m_physicalTime + ddt;
8263 const MFloat D = F2 * m_bodyRadius[0];
8264 MFloat amplitudeFactor = 0.1;
8265 amplitudeFactor = Context::getSolverProperty<MFloat>("amplitudeFactor", m_solverId, AT_, &amplitudeFactor);
8266 MFloat freqFactor = F1;
8267 freqFactor = Context::getSolverProperty<MFloat>("freqFactor", m_solverId, AT_, &freqFactor);
8268 MFloat Strouhal = 0.2;
8269 Strouhal = Context::getSolverProperty<MFloat>("Strouhal", m_solverId, AT_, &Strouhal);
8270 const MFloat A = amplitudeFactor * D;
8271 const MFloat freq0 = Strouhal * m_UInfinity / m_referenceLength;
8272 const MFloat mu = freqFactor * freq0 * F2 * PI;
8273
8274 /*
8275 m_bodyCenter[1] = A * sin( mu * elapsedTime );
8276 m_bodyVelocity[1] = mu * A * cos( mu * elapsedTime );
8277 m_bodyAcceleration[1] = -mu * mu * A * sin( mu * elapsedTime );
8278 */
8279
8280 MFloat dt = timeStep() * ((MFloat)Context::getSolverProperty<MInt>("outputOffset", m_solverId, AT_));
8281 dt = F0;
8282
8283 elapsedTime -= dt;
8284
8285 m_bodyVelocityDt1[1] = m_bodyVelocity[1];
8286 m_bodyCenterDt1[1] = m_bodyCenter[1];
8287
8288 if(elapsedTime > F0) {
8289 m_bodyCenter[1] =
8290 -A * cos(mu * elapsedTime); // cerr << globalTimeStep<< " " << m_RKStep << " " << m_bodyCenter[1] << endl;
8291 m_bodyVelocity[1] = mu * A * sin(mu * elapsedTime);
8292 m_bodyAcceleration[1] = mu * mu * A * cos(mu * elapsedTime);
8293 } else {
8294 m_bodyCenter[1] = -A;
8295 m_bodyVelocity[1] = F0;
8296 m_bodyAcceleration[1] = F0;
8297 }
8298
8299 break;
8300 }
8301
8302 case 451:
8303 case 470:
8304 case 471: {
8305 ScratchSpace<MFloat> globalMI(3 * m_noEmbeddedBodies, AT_, "globalMI");
8306 // for ( MInt k = 0; k < m_noEmbeddedBodies; k++ ) {
8307 const MInt k = body;
8308 for(MInt i = 0; i < 3; i++) {
8309 globalMI[3 * k + i] = F0;
8310 m_bodyMomentOfInertia[3 * k + i] = F0;
8311 }
8312 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
8313 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
8314 if(a_associatedBodyIds(cellId, 0) != k) continue;
8315 if(a_isHalo(cellId)) continue;
8316 if(a_isBndryGhostCell(cellId)) continue;
8317 MFloat dx[3] = {F0, F0, F0};
8318 MFloat normal[3] = {F0, F0, F0};
8319 MFloat fac[3] = {F0, F0, F0};
8320 for(MInt i = 0; i < nDim; i++) {
8321 dx[i] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i] - m_bodyCenter[nDim * k + i];
8322 normal[i] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i];
8323 }
8324 IF_CONSTEXPR(nDim == 3) {
8325 fac[0] = normal[1] * POW3(dx[1]) + normal[2] * POW3(dx[2]);
8326 fac[1] = normal[0] * POW3(dx[0]) + normal[2] * POW3(dx[2]);
8327 }
8328 fac[2] = normal[0] * POW3(dx[0]) + normal[1] * POW3(dx[1]);
8329 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_area;
8330 for(MInt i = 0; i < 3; i++) {
8331 m_bodyMomentOfInertia[3 * k + i] += area * fac[i];
8332 }
8333 }
8334 for(MInt i = 0; i < 3; i++) {
8335 m_bodyMomentOfInertia[3 * k + i] *= F1B3 * m_bodyDensity[k];
8336 m_log << "BMI " << k << " " << i << " " << m_bodyMomentOfInertia[3 * k + i] << endl;
8337 /* MFloat momi = F2/F5*POW2(0.5)*m_rhoInfinity*PI*F1B6;
8338 cerr << "MOMI: " << k << " " << i << " " << m_bodyMomentOfInertia[ 3*k+i ] << " " << momi << " " <<
8339 m_bodyMomentOfInertia[ 3*k+i ]/momi
8340 //<< " " << m_fvBndryCnd->m_bndryCells->size() << " " << F1B3*test << " " << F1B6*PI
8341 << endl;
8342 */
8343 }
8344 //}
8345 // MPI_Allreduce( m_bodyMomentOfInertia, globalMI.begin(), 3*m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(),
8346 // AT_, "m_bodyMomentOfInertia", "globalMI.begin()" ); for ( MInt k = 0; k < m_noEmbeddedBodies; k++ ) {
8347 // for( MInt i = 0; i < 3; i++ ) {
8348 // m_bodyMomentOfInertia[ 3*k+i ] = globalMI[ 3*k+i ];
8349 // }
8350 MPI_Allreduce(MPI_IN_PLACE, &(m_bodyMomentOfInertia[3 * k]), 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
8351 "MPI_IN_PLACE", "(m_bodyMomentOfInertia[3*k])");
8352
8353 break;
8354 }
8355
8356
8357 case 452: {
8358 // inline oscillating sphere in stratified fluid
8359
8360 MFloat KC = F0;
8371 KC = Context::getSolverProperty<MFloat>("KeuleganCarpenter", m_solverId, AT_, &KC);
8372
8384 MFloat Sf = F0;
8385 Sf = Context::getSolverProperty<MFloat>("nonDimensionalFreq", m_solverId, AT_, &Sf);
8386
8387 const MFloat elapsedTime = m_physicalTime;
8388 const MFloat freq = Sf * m_UInfinity / m_referenceLength;
8389 const MFloat mu = F2 * PI * freq;
8390 const MFloat A = m_referenceLength * KC;
8391
8392 m_bodyCenter[0] = A * sin(mu * elapsedTime);
8393 m_bodyVelocity[0] = mu * A * cos(mu * elapsedTime);
8394 m_bodyAcceleration[0] = -mu * mu * A * sin(mu * elapsedTime);
8395
8396 break;
8397 }
8398
8399
8400 case 453: {
8401 IF_CONSTEXPR(nDim == 2) {
8402 const MFloat t = m_time + timeStep() * m_timeRef;
8403 m_bodyCenter[0] = -0.125 * cos(F2 * PI * t);
8404 m_bodyVelocity[0] = m_timeRef * 0.25 * PI * sin(F2 * PI * t);
8405 m_bodyAcceleration[0] = m_timeRef * m_timeRef * 0.5 * PI * PI * cos(F2 * PI * t);
8406 /*
8407 const MFloat A = amplitudeFactor * D;
8408 const MFloat freq0 = Strouhal * m_UInfinity / m_referenceLength;
8409 const MFloat mu = freqFactor * freq0 * F2 * PI;
8410 m_bodyCenter[1] = -A * cos( mu * elapsedTime );
8411 m_bodyVelocity[1] = mu * A * sin( mu * elapsedTime );
8412 m_bodyAcceleration[1] = mu * mu * A * cos( mu * elapsedTime );
8413 */
8414 break;
8415 }
8416
8417 // inline oscillating sphere, quiescent flow
8434 MFloat StokesNumber = F4;
8435 StokesNumber = Context::getSolverProperty<MFloat>("StokesNumber", m_solverId, AT_, &StokesNumber);
8436
8437 const MFloat Strouhal = F4 * POW2(StokesNumber) / m_Re;
8438
8439 // const MFloat elapsedTime = m_physicalTime+timeStep();
8440 const MFloat elapsedTime = m_physicalTime;
8441 const MFloat freq = F2 * Strouhal * m_UInfinity / m_referenceLength;
8442
8443 MBool& firstRun = m_static_updateBodyProperties_c453_firstRun;
8444 if(firstRun) {
8445 cerr << StokesNumber << " " << Strouhal << " " << m_Re << " " << sysEqn().m_Re0 << endl;
8446 firstRun = false;
8447 }
8448
8449 m_bodyCenter[0] = -m_UInfinity * cos(freq * elapsedTime) / freq;
8450 m_bodyVelocity[0] = m_UInfinity * sin(freq * elapsedTime);
8451 m_bodyAcceleration[0] = freq * m_UInfinity * cos(freq * elapsedTime);
8452
8453 const MFloat t = m_physicalTime;
8454 const MFloat w = F2 * m_Ma * F4 * POW2(StokesNumber) / m_Re;
8455 m_bodyCenter[0] = -m_Ma * cos(w * t) / w;
8456 m_bodyVelocity[0] = m_Ma * sin(w * t);
8457 m_bodyAcceleration[0] = m_Ma * w * cos(w * t);
8458
8459 /*
8460 //m_bodyCenter[0] = 0.5 - m_UInfinity * sin( freq * elapsedTime ) / freq;
8461 m_bodyCenter[0] = - m_UInfinity * sin( freq * elapsedTime ) / freq;
8462 m_bodyVelocity[0] = - m_UInfinity * cos( freq * elapsedTime );
8463 m_bodyAcceleration[0] = freq * m_UInfinity * sin( freq * elapsedTime );
8464 */
8465 break;
8466 }
8467
8468
8469 case 458: {
8470 // instantaneously accelerated sphere, inviscid flow
8471 const MFloat speedOfSoundInf = sysEqn().speedOfSound(m_rhoInfinity, m_PInfinity);
8472 const MFloat T0 = 100;
8473 const MFloat T1 = T0 + 20.0 * m_bodyRadius[0] / speedOfSoundInf;
8474 const MFloat elapsedTime = m_physicalTime + timeStep();
8475 const MFloat alpha = 6e-4;
8476 const MFloat accel = -alpha * POW2(speedOfSoundInf) / m_bodyRadius[0];
8477
8478 if(elapsedTime < T0) {
8479 m_bodyCenter[0] = F0;
8480 m_bodyVelocity[0] = F0;
8481 m_bodyAcceleration[0] = F0;
8482 } else if(elapsedTime < T1) {
8483 m_bodyAcceleration[0] = accel;
8484 m_bodyVelocity[0] = accel * (elapsedTime - T0);
8485 m_bodyCenter[0] = F1B2 * accel * POW2(elapsedTime - T0);
8486 } else {
8487 m_bodyAcceleration[0] = F0;
8488 m_bodyCenter[0] = F1B2 * accel * POW2(T1 - T0) + m_bodyVelocity[0] * (elapsedTime - T1);
8489 }
8490
8491 break;
8492 }
8493
8494
8495 case 460: {
8496 // instantaneously accelerated sphere in quiescent flow
8497
8498 const MFloat elapsedTime = m_physicalTime + timeStep();
8499 m_bodyAcceleration[0] = F0;
8500 m_bodyVelocity[0] = m_Ma;
8501 m_bodyCenter[0] = elapsedTime * m_Ma;
8502
8503 break;
8504 }
8505
8506 case 461: {
8507 MBool oscil = false;
8508
8509 // pitching NACA0012
8510
8511 // const MFloat t = m_physicalTime + timeStep();
8512 if(m_euler) {
8513 /*
8514 const MFloat t0 = F0;
8515 const MFloat t = mMax( F0, m_time + (timeStep()*m_timeRef) - t0 );
8516 MFloat f = 0.0814*m_UInfinity/PI; //62.5
8517 MFloat w = F2*PI*f;
8518 m_bodyAngularVelocity[2] = -m_timeRef*( 2.51*w*cos(w*t) )*PI/180.0;
8519 m_bodyAngularAcceleration[2] = -m_timeRef*m_timeRef*( -2.51*w*w*sin(w*t) )*PI/180.0;
8520 */
8521 const MFloat degToRad = -PI / 180.0;
8522 const MFloat t = m_physicalTime + timeStep();
8523 // const MFloat ainf = sqrt( m_TInfinity );
8524 MFloat f = 0.0814;
8525 // MFloat w = F2*f*m_Ma;
8526 MFloat w = F2 * f * m_UInfinity;
8527 MFloat a0 = 0.016;
8528 MFloat a1 = 2.51;
8529 /*
8530 a0 = 2.0;
8531 a1 = 2.5;
8532 w = F2*PI*0.05*ainf;
8533 */
8534 bodyRotation[2] = (a0 + a1 * sin(w * t)) * degToRad;
8535 m_bodyAngularVelocity[2] = (a1 * w * cos(w * t)) * degToRad;
8536 m_bodyAngularAcceleration[2] = (-a1 * w * w * sin(w * t)) * degToRad;
8537 } else if(oscil) {
8538 /*
8539 const MFloat t0 = 2.5;
8540 const MFloat t = mMax( F0, m_time + (timeStep()*m_timeRef) - t0 );
8541 const MFloat f = 0.25;
8542 const MFloat a0 = 10.0;
8543 const MFloat a1 = 10.0;
8544 const MFloat w = F2*f*m_UInfinity/m_referenceLength;
8545 m_bodyAngularVelocity[2] = -m_timeRef*( w*a1*sin(w*t) )*PI/180.0;
8546 m_bodyAngularAcceleration[2] = -m_timeRef*m_timeRef*( w*w*a1*cos(w*t) )*PI/180.0;
8547 */
8548 const MFloat degToRad = -PI / 180.0;
8549 const MFloat t0 = 12.5;
8550 const MFloat t = mMax(F0, m_physicalTime + timeStep() - t0);
8551 const MFloat f = 0.25;
8552 const MFloat a0 = 10.0;
8553 // const MFloat a1 = 10.0;
8554 const MFloat w = F2 * m_UInfinity * f;
8555 /*
8556 m_bodyAngularVelocity[2] = -( w*a1*sin(w*t) )*PI/180.0;
8557 m_bodyAngularAcceleration[2] = -( w*w*a1*cos(w*t) )*PI/180.0;
8558 */
8559 bodyRotation[2] = (a0 * (F1 - cos(w * t))) * degToRad;
8560 m_bodyAngularVelocity[2] = (a0 * w * sin(w * t)) * degToRad;
8561 m_bodyAngularAcceleration[2] = (a0 * w * w * cos(w * t)) * degToRad;
8562 } else {
8563 const MFloat degToRad = -PI / 180.0;
8564 const MFloat fac = m_UInfinity / m_Ma;
8565 const MFloat b = 2.2918312 * fac;
8566 const MFloat c = 1.84 * fac;
8567 const MFloat a = -b / c;
8568 const MFloat t0 = 15.0; // 20.12;//15.0;//20.0;//15.32;//62.8;//25.0;
8569 const MFloat t = mMax(F0, m_physicalTime + timeStep() - t0);
8570
8571 // see Visbal and Shang 1989.
8572 MFloat factor = 0.2;
8573 factor = Context::getSolverProperty<MFloat>("freqFactor", m_solverId, AT_, &factor);
8574 MFloat t0p = 0.5;
8575 t0p = Context::getSolverProperty<MFloat>("amplitudeFactor", m_solverId, AT_, &t0p);
8576
8577 if((t < m_eps) || (fabs(factor) < m_eps)) {
8578 bodyRotation[2] = F0;
8579 m_bodyAngularVelocity[2] = F0;
8580 m_bodyAngularAcceleration[2] = F0;
8581 break;
8582 }
8583
8584 bodyRotation[2] = (b * t + a * (F1 - exp(-c * t))) * degToRad;
8585 m_bodyAngularVelocity[2] = (b + a * c * exp(-c * t)) * degToRad;
8586 m_bodyAngularAcceleration[2] = (-a * c * c * exp(-c * t)) * degToRad;
8587
8588 const MFloat omega0 = -factor * m_UInfinity;
8589 const MFloat it0 = 4.6 * m_UInfinity / t0p;
8590 const MFloat et = exp(-it0 * t);
8591
8592 bodyRotation[2] = omega0 * (t + (et - F1) / it0);
8593 m_bodyAngularVelocity[2] = omega0 * (F1 - et);
8594 m_bodyAngularAcceleration[2] = omega0 * it0 * et;
8595 }
8596
8597 if(globalTimeStep % 100 == 0)
8598 cerr << globalTimeStep << " alpha " << -bodyRotation[2] * 180 / PI
8599 << " deg, TE:" << cos(bodyRotation[2]) * 0.75 << "/" << sin(bodyRotation[2]) * 0.75 << endl;
8600
8601 break;
8602 }
8603
8604
8605 case 455: {
8606 MFloat A = 0.1 * (F2 * m_bodyRadius[0]);
8607 MFloat f = 1.0;
8608 MFloat C = f * F2 * PI * m_UInfinity;
8609 // const MFloat t = m_time + timeStep()*m_timeRef;
8610 const MFloat t = m_physicalTime + timeStep();
8611 m_bodyCenter[0] = -A * cos(C * t);
8612 m_bodyVelocity[0] = A * C * sin(C * t);
8613 m_bodyAcceleration[0] = A * POW2(C) * cos(C * t);
8614 break;
8615
8616
8617 // inline oscillating cylinder, quiescent flow
8618 MFloat elapsedTime = m_physicalTime;
8619 // const MFloat D = F2 * m_bodyRadius;
8620 // const MFloat A = m_UInfinity;//0.05 * D;
8621 MFloat freq0 = F2 * PI * m_UInfinity; // F1;// * m_UInfinity / m_referenceLength;
8622 // const MFloat mu = F1;//freq0 * F2 * PI;
8623
8624 /*
8625 m_bodyCenter[0] = A * sin( mu * elapsedTime );
8626 m_bodyVelocity[0] = mu * A * cos( mu * elapsedTime );
8627 m_bodyAcceleration[0] = -mu * mu * A * sin( mu * elapsedTime );
8628 */
8629 /*
8630 m_bodyCenter[0] = -A * cos( mu * elapsedTime );
8631 m_bodyVelocity[0] = mu * A * sin( mu * elapsedTime );
8632 m_bodyAcceleration[0] = mu * mu * A * cos( mu * elapsedTime );
8633 */
8634
8635 freq0 = m_UInfinity / 0.1;
8636 m_bodyCenter[0] = -m_UInfinity * cos(freq0 * elapsedTime) / freq0;
8637 m_bodyVelocity[0] = m_UInfinity * sin(freq0 * elapsedTime);
8638 m_bodyAcceleration[0] = freq0 * m_UInfinity * cos(freq0 * elapsedTime);
8639
8640
8641 MFloat a = F1 / (F2 * PI);
8642 MFloat w = F2 * PI * m_Ma;
8643 m_bodyCenter[0] = -a * cos(w * m_physicalTime);
8644 m_bodyVelocity[0] = a * w * sin(w * m_physicalTime);
8645 m_bodyAcceleration[0] = a * w * w * cos(w * m_physicalTime);
8646 // cerr << m_physicalTime * m_UInfinity<< " " << m_time << endl;
8647
8648
8649 MFloat factor = 1.0;
8650 factor = Context::getSolverProperty<MFloat>("freqFactor", m_solverId, AT_, &factor);
8651
8652 freq0 = factor * F2 * PI * m_Ma;
8653 MBool& firstRun = m_static_updateBodyProperties_c455_firstRun;
8654 if(firstRun) {
8655 cerr << "maximum cylinder offset: " << m_Ma / freq0 << endl;
8656 cerr << "maximum drag coeff: " << F1B2 * PI * freq0 / m_Ma << endl;
8657 cerr << m_globalUpwindCoefficient << " " << m_Ma << endl;
8658 firstRun = false;
8659 }
8660 m_bodyCenter[0] = -m_Ma / freq0 * cos(freq0 * m_physicalTime);
8661 m_bodyVelocity[0] = m_Ma * sin(freq0 * m_physicalTime);
8662 m_bodyAcceleration[0] = freq0 * m_Ma * cos(freq0 * m_physicalTime);
8663
8664
8665 const MFloat t0 = m_physicalTime + timeStep();
8666 MFloat f0 = 1.0;
8667 MFloat w0 = F2 * PI * f0 * m_Ma / m_referenceLength;
8668 MFloat a0 = 0.1 * m_referenceLength;
8669 m_bodyCenter[0] = -a0 * cos(w0 * t0);
8670 m_bodyVelocity[0] = a0 * w0 * sin(w0 * t0);
8671 m_bodyAcceleration[0] = a0 * w0 * w0 * cos(w0 * t0);
8672
8673
8674 break;
8675 }
8676
8677
8678 case 456: {
8679 // translating cylinder, quiescent flow
8680
8681 MFloat deltaT = 10.0;
8682
8683 m_bodyCenter[0] = F1B2 * m_Ma / deltaT * POW2(m_physicalTime);
8684 m_bodyVelocity[0] = m_Ma * mMin(F1, m_physicalTime / deltaT);
8685 m_bodyAcceleration[0] = m_Ma / deltaT;
8686
8687 if(m_physicalTime / deltaT >= F1) {
8688 m_bodyCenter[0] = (F1B2 * m_Ma * deltaT) + m_Ma * (m_physicalTime - deltaT);
8689 m_bodyVelocity[0] = m_Ma;
8690 m_bodyAcceleration[0] = F0;
8691 }
8692 /*
8693 m_bodyCenter[0] = - m_Ma * sin( PI * mMin( F1, m_physicalTime/deltaT ) );
8694 m_bodyVelocity[0] = - m_Ma * cos( PI * mMin( F1, m_physicalTime/deltaT ) );
8695 m_bodyAcceleration[0] = m_Ma / deltaT;
8696 */
8697
8698 m_bodyCenter[0] = m_Ma * m_physicalTime;
8699 m_bodyVelocity[0] = m_Ma;
8700 m_bodyAcceleration[0] = F0;
8701
8702 break;
8703 }
8704
8705
8706 case 457: {
8707 // translating cylinder, quiescent flow
8708
8709 MFloat deltaT = 250.0;
8710
8711 // const MFloat x0 = -0.001430000000000000000;//-0.001429640000000000000;
8712 // const MFloat x1 = -0.001429600000000000000;
8713
8714 // small<->regular cell
8715 // 1e-12
8716 const MFloat x0 = 0.002332491063; // 0.002332491; //regular 31366
8717 const MFloat x1 = 0.002332491064; // 0.002332492; //small
8718
8719 // emerging/submerging cell
8720 // const MFloat x0 = -0.00168832 ; //cell 31502 present;
8721 // const MFloat x1 = -0.00168826 ; // cell absent
8722
8723
8724 m_bodyVelocity[0] = F0;
8725 m_bodyAcceleration[0] = F0;
8726 m_bodyCenter[0] = x0;
8727
8728 if(m_time / deltaT >= F1) {
8729 m_bodyCenter[0] = x1;
8730
8731 MBool& firstTime = m_static_updateBodyProperties_firstTime;
8732 if(firstTime) {
8733 cerr << "switch applied now (delta_x=" << x1 - x0 << ", u/u_0=" << (x1 - x0) / (timeStep() * m_UInfinity)
8734 << ", delta_x/h=" << (x1 - x0) / (c_cellLengthAtLevel(m_lsCutCellBaseLevel))
8735 << ", accel=" << (x1 - x0) * m_referenceLength / POW2(timeStep() * m_UInfinity) << ")" << endl;
8736 m_bodyVelocity[0] = (x1 - x0) / timeStep();
8737 m_bodyAcceleration[0] = (m_bodyVelocity[0] - m_bodyVelocityDt1[0]) / timeStep();
8738
8739 MFloat Cd = F1B4 * PI * m_referenceLength * (x1 - x0) / POW2(timeStep() * m_UInfinity);
8740 cerr << "C_d: " << Cd << endl;
8741 firstTime = false;
8742 }
8743 }
8744
8745
8746 break;
8747 }
8748 }
8749
8750 // update rotation
8751 setBodyQuaternions(body, bodyRotation);
8752 }
8753}
8754
8755
8760template <MInt nDim, class SysEqn>
8762 TRACE();
8763
8764 ScratchSpace<MFloat> globalMI(3 * m_noEmbeddedBodies, AT_, "globalMI");
8765
8766 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
8767 for(MInt i = 0; i < 3; i++) {
8768 globalMI[3 * k + i] = F0;
8769 m_bodyMomentOfInertia[3 * k + i] = F0;
8770 }
8771
8772 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
8773 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
8774 if(a_associatedBodyIds(cellId, 0) != k) continue;
8775 if(a_isHalo(cellId)) continue;
8776 if(a_isBndryGhostCell(cellId)) continue;
8777 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
8778 MFloat dx[3] = {F0, F0, F0};
8779 MFloat normal[3] = {F0, F0, F0};
8780 MFloat fac[3] = {F0, F0, F0};
8781 for(MInt i = 0; i < nDim; i++) {
8782 dx[i] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i] - m_bodyCenter[nDim * k + i];
8783 normal[i] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
8784 }
8785 IF_CONSTEXPR(nDim == 3) {
8786 fac[0] = normal[1] * POW3(dx[1]) + normal[2] * POW3(dx[2]);
8787 fac[1] = normal[0] * POW3(dx[0]) + normal[2] * POW3(dx[2]);
8788 }
8789 fac[2] = normal[0] * POW3(dx[0]) + normal[1] * POW3(dx[1]);
8790 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
8791
8792 for(MInt i = 0; i < 3; i++) {
8793 m_bodyMomentOfInertia[3 * k + i] += area * fac[i];
8794 }
8795 }
8796
8797 for(MInt i = 0; i < 3; i++) {
8798 m_bodyMomentOfInertia[3 * k + i] *= F1B3 * m_bodyDensity[k];
8799 }
8800 }
8801 }
8802 MPI_Allreduce(m_bodyMomentOfInertia, globalMI.begin(), 3 * m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
8803 "m_bodyMomentOfInertia", "globalMI.begin()");
8804
8805 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
8806 for(MInt i = 0; i < 3; i++) {
8807 m_bodyMomentOfInertia[3 * k + i] = globalMI[3 * k + i];
8808 }
8809 }
8810}
8811
8812
8817template <MInt nDim, class SysEqn>
8819 TRACE();
8820
8821 if(m_timeStepAdaptationStart < 0 || m_timeStepAdaptationEnd < 0) return;
8822
8823 if(globalTimeStep > m_timeStepAdaptationEnd) {
8824 m_cfl = m_cflTarget;
8825 } else if(globalTimeStep < m_timeStepAdaptationStart) {
8826 m_cfl = m_cflInitial;
8827 } else {
8828 const MFloat t = (MFloat)globalTimeStep;
8829 const MFloat t0 = (MFloat)m_timeStepAdaptationStart;
8830 const MFloat t1 = (MFloat)m_timeStepAdaptationEnd;
8831 m_cfl = m_cflInitial + (t - t0) * (m_cflTarget - m_cflInitial) / (t1 - t0);
8832 m_log << "Adapted CFL number: " << m_cfl << " at time step " << globalTimeStep << ";" << endl;
8833 }
8834}
8835
8836
8841template <MInt nDim, class SysEqn>
8843 c[0] = a[1] * b[2] - a[2] * b[1];
8844 c[1] = a[2] * b[0] - a[0] * b[2];
8845 c[2] = a[0] * b[1] - a[1] * b[0];
8846}
8847
8848
8858template <MInt nDim, class SysEqn>
8860 TRACE();
8861
8862 ASSERT(a_noCells() == c_noCells(), "");
8863 ASSERT(m_fvBndryCnd->m_bndryCells->size() == m_noOuterBndryCells, "");
8864
8865 NEW_SUB_TIMER_STATIC(tInit, "init", m_tCutGroup);
8866 NEW_SUB_TIMER_STATIC(tCutFaceNew, "cutFaceNew", m_tCutGroup);
8867 NEW_SUB_TIMER_STATIC(tCutPointNew, "cutPoint", m_tCutGroup);
8868 NEW_SUB_TIMER_STATIC(tReinit, "reinit", m_tCutGroup);
8869 NEW_SUB_TIMER_STATIC(tMassRedist, "massRedist", m_tCutGroup);
8870 RECORD_TIMER_START(tInit);
8871
8872 // reset the states if we are doing FSI iterations
8873 if(m_structureStep > 0 && mode != 2) {
8874 for(map<MInt, vector<MFloat>>::iterator it = m_nearBoundaryBackup.begin(); it != m_nearBoundaryBackup.end(); it++) {
8875 const MInt cellId = it->first;
8876 a_cellVolume(cellId) = (it->second)[0];
8877 m_cellVolumesDt1[cellId] = (it->second)[0];
8878 for(MInt v = 0; v < m_noCVars; v++) {
8879 a_oldVariable(cellId, v) = (it->second)[1 + v];
8880 }
8881 for(MInt v = 0; v < m_noFVars; v++) {
8882 m_rhs0[cellId][v] = (it->second)[1 + m_noCVars + v];
8883 }
8884 }
8885 }
8886
8887 if(m_bodyTypeMb && m_constructGField) {
8888 setupBoundaryCandidatesAnalytical();
8889 } else {
8890 determineBndryCandidates();
8891 computeNodalLSValues();
8892 checkCellState(); // sets isInactice property correctly based on nodal Ls-values:
8893 }
8894 RECORD_TIMER_STOP(tInit);
8895
8896 // add moving-bndry bndry-Cells
8897 RECORD_TIMER_START(tCutPointNew);
8898 computeCutPointsMb_MGC();
8899 RECORD_TIMER_STOP(tCutPointNew);
8900
8901 // check CutPoints and remove cutCells with less than 3 CutPoints
8902 m_fvBndryCnd->checkCutPointsValidity();
8903
8904 // check bndryCells and candidateNodeSet
8905 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
8906 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
8907 const MInt cndId = m_bndryCandidateIds[cellId];
8908 ASSERT(cndId >= 0, "ERROR: cutCell is not a bndryCandidate? ");
8909 for(MInt p = 0; p < m_noCellNodes; p++) {
8910 ASSERT(m_candidateNodeSet[cndId * m_noCellNodes + p], "ERROR: nodeValue not set for bndryCel!");
8911 }
8912 }
8913
8914 // set pointIsInside based on the corner levelSet values for all mb-bndry-Cells and
8915 // set/correct CellProperties for all mb-bndryCells
8916 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
8917 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
8918 const MInt cndId = m_bndryCandidateIds[cellId];
8919 ASSERT(cndId >= 0, "ERROR: cutCell is not a bndryCandidate? ");
8920 ASSERT(a_hasProperty(cellId, SolverCell::IsMovingBnd), "");
8921 MInt startSet = 0;
8922 MInt endSet = 1;
8923 if(m_noLevelSetsUsedForMb > 1 && m_complexBoundary && !a_isGapCell(cellId)) {
8924 startSet = 1;
8925 endSet = m_noLevelSetsUsedForMb;
8926 }
8927
8928 // For all bndryCells IsInactive is set to false!
8929 if(a_hasProperty(cellId, SolverCell::IsInactive)) {
8930 cerr << "Unusual, mb-bndryCell was inactive: react " << c_globalId(cellId) << endl;
8931 }
8932 a_hasProperty(cellId, SolverCell::IsInactive) = false;
8933
8934 if(c_noChildren(cellId) == 0 && (a_hasProperty(cellId, SolverCell::IsSplitChild) || c_isLeafCell(cellId))) {
8935 if(!a_hasProperty(cellId, SolverCell::IsNotGradient)) {
8936 a_hasProperty(cellId, SolverCell::IsFlux) = true;
8937 a_hasProperty(cellId, SolverCell::IsActive) = true;
8938 }
8939 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = true;
8940 }
8941 a_isBndryGhostCell(cellId) = false;
8942
8943 for(MInt p = 0; p < m_noCellNodes; p++) {
8944 m_pointIsInside[bndryId][IDX_LSSETMB(p, 0)] = false;
8945
8946 for(MInt set = startSet; set < endSet; set++) {
8947 m_pointIsInside[bndryId][IDX_LSSETMB(p, set)] = (m_candidateNodeValues[IDX_LSSETNODES(cndId, p, set)] < F0);
8948 m_pointIsInside[bndryId][IDX_LSSETMB(p, 0)] =
8949 (m_pointIsInside[bndryId][IDX_LSSETMB(p, 0)] || m_pointIsInside[bndryId][IDX_LSSETMB(p, set)]);
8950 }
8951 }
8952 }
8953
8954 m_gapOpened = false;
8955 if(m_levelSet && m_closeGaps && m_gapInitMethod == 0) setGapOpened();
8956
8957
8958 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
8959 restoreSurfaces(m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId);
8960 }
8961
8962 // add split-childs if necessary!
8963 RECORD_TIMER_START(tCutFaceNew);
8964 createCutFaceMb_MGC();
8965 RECORD_TIMER_STOP(tCutFaceNew);
8966
8967#if defined _MB_DEBUG_ || !defined NDEBUG
8968 MInt noSplitChilds = m_totalnosplitchilds;
8969 MPI_Allreduce(MPI_IN_PLACE, &noSplitChilds, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noSplitChilds");
8970
8971 if(noSplitChilds > 0 && domainId() == 0) {
8972 cerr << "Global-Number of Split-Childs are " << noSplitChilds << endl;
8973 }
8974#endif
8975
8976 // set cutFaceArea and wasInactive for splitChilds
8977 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
8978 const MInt cellId = m_splitCells[sc];
8979 for(MInt dir = 0; dir < m_noDirs; dir++) {
8980 m_cutFaceArea[a_bndryId(cellId)][dir] = F0;
8981 }
8982 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
8983 const MInt splitChildId = m_splitChilds[sc][ssc];
8984 for(MInt dir = 0; dir < m_noDirs; dir++) {
8985 m_cutFaceArea[a_bndryId(cellId)][dir] += m_cutFaceArea[a_bndryId(splitChildId)][dir];
8986 }
8987 a_hasProperty(splitChildId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::WasInactive);
8988 }
8989 }
8990
8991
8992 // ensure the same cutFaceArea at neighboring boundary-Cells
8993 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
8994 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
8995 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
8996 for(MInt dir = 0; dir < m_noDirs; dir++) {
8997 if(a_hasNeighbor(cellId, dir) == 0) continue;
8998 const MInt nghbrId = c_neighborId(cellId, dir);
8999 if(a_bndryId(nghbrId) > -1) {
9000 const MFloat a0 = m_cutFaceArea[a_bndryId(cellId)][dir];
9001 const MFloat a1 = m_cutFaceArea[a_bndryId(nghbrId)][m_revDir[dir]];
9002 m_cutFaceArea[a_bndryId(cellId)][dir] = mMax(a0, a1);
9003 m_cutFaceArea[a_bndryId(nghbrId)][m_revDir[dir]] = mMax(a0, a1);
9004 }
9005 }
9006 }
9007
9008 {
9009 ASSERT(!m_fvBndryCnd->m_cellCoordinatesCorrected, "");
9010 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
9011 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9012 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9013 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance = F0;
9014 for(MInt i = 0; i < nDim; i++) {
9015 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i] =
9016 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
9017 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance +=
9018 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
9019 * (a_coordinate(cellId, i) + m_bndryCells->a[bndryId].m_coordinates[i]
9020 - m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]);
9021 }
9022 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance =
9023 mMax(F0, m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance);
9024 }
9025 }
9026
9027 constexpr MFloat dirStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
9028 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
9029
9030 MFloatScratchSpace levelSets(m_noLevelSetsUsedForMb, AT_, "levelSets");
9031 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
9032 // set m_gapDistance, m_centroidDistance and m_normalVectorCentroid for bndry-Cells
9033 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9034 levelSets.fill(std::numeric_limits<MFloat>::max());
9035 std::array<MFloat, nDim> coordsBak{};
9036 if(m_constructGField) {
9037 std::copy_n(&a_coordinate(cellId, 0), nDim, coordsBak.data());
9038 std::transform(&a_coordinate(cellId, 0), &a_coordinate(cellId, 0) + nDim,
9039 &m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[0], &a_coordinate(cellId, 0),
9040 std::plus<MFloat>());
9041 }
9042 const MInt startSet = 0;
9043 const MInt endSet = (m_complexBoundary && m_noLevelSetsUsedForMb > 1) ? m_noLevelSetsUsedForMb : 1;
9044 for(MInt set = startSet; set < endSet; set++) {
9045 if(a_associatedBodyIds(cellId, set) < 0) continue;
9046 if(m_constructGField && (m_bodyTypeMb == 1 || m_bodyTypeMb == 3)) {
9047 levelSets(set) = getDistance(cellId, a_associatedBodyIds(cellId, set));
9048 } else {
9049 MFloat coord[3] = {F0, F0, F0};
9050 for(MInt i = 0; i < nDim; i++) {
9051 coord[i] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[i] / c_cellLengthAtCell(cellId);
9052 }
9053 MInt cndId = (a_hasProperty(cellId, SolverCell::IsSplitChild))
9054 ? m_bndryCandidateIds[getAssociatedInternalCell(cellId)]
9055 : m_bndryCandidateIds[cellId];
9056 if(cndId < 0) mTerm(1, AT_, "candidate not found");
9057 for(MInt node = 0; node < m_noCellNodes; node++) {
9058 if(!m_candidateNodeSet[cndId * m_noCellNodes + node]) {
9059 mTerm(1, AT_, "candidate node not set");
9060 }
9061 }
9062 MFloat phi = F0;
9063 for(MInt node = 0; node < m_noCellNodes; node++) {
9064 IF_CONSTEXPR(nDim == 2) {
9065 phi += (F1B2 + dirStencil[node][0] * coord[0]) * (F1B2 + dirStencil[node][1] * coord[1])
9066 * m_candidateNodeValues[IDX_LSSETNODES(cndId, node, set)];
9067 }
9068 else IF_CONSTEXPR(nDim == 3) {
9069 phi += (F1B2 + dirStencil[node][0] * coord[0]) * (F1B2 + dirStencil[node][1] * coord[1])
9070 * (F1B2 + dirStencil[node][2] * coord[2])
9071 * m_candidateNodeValues[IDX_LSSETNODES(cndId, node, set)];
9072 }
9073 }
9074 levelSets(set) = phi;
9075 }
9076 levelSets(set) = mMax(F0, levelSets(set));
9077 }
9078
9079 MFloat phiSum = m_bndryCells->a[bndryId].m_gapDistance = std::numeric_limits<MFloat>::max();
9080 for(MInt p = 1; p < m_noLevelSetsUsedForMb - 1; p++) {
9081 for(MInt q = p + 1; q < m_noLevelSetsUsedForMb; q++) {
9082 phiSum = mMin(phiSum, levelSets(p) + levelSets(q));
9083 }
9084 }
9085 m_bndryCells->a[bndryId].m_gapDistance = phiSum;
9086
9087
9088 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9089 MInt set = -1;
9090 for(MInt s = m_startSet; s < m_noSets; s++) {
9091 if(a_associatedBodyIds(cellId, s) == m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0]) {
9092 set = s;
9093 break;
9094 }
9095 }
9096 if(set < 0) mTerm(1, AT_, "set not found.");
9097
9098 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance = levelSets(set);
9099
9100 MFloat normal[3];
9101 getNormal(cellId, set, normal);
9102
9103 if(bndryId > -1 && srfc > -1) {
9104 const MFloat vfrac = mMax(m_volumeThreshold, m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume)
9105 / grid().gridCellVolume(a_level(cellId));
9106 const MFloat fac = maia::math::deltaFun(vfrac, 0.0, 1.0);
9107 MFloat cnt = F0;
9108 for(MInt i = 0; i < nDim; i++) {
9109 normal[i] = fac * normal[i] + (F1 - fac) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
9110 cnt += POW2(normal[i]);
9111 }
9112 cnt = sqrt(cnt);
9113 for(MInt i = 0; i < nDim; i++) {
9114 normal[i] /= cnt;
9115 }
9116 for(MInt i = 0; i < nDim; i++) {
9117 m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i] = normal[i];
9118 }
9119 }
9120 }
9121 if(m_constructGField) {
9122 std::copy_n(coordsBak.data(), nDim, &a_coordinate(cellId, 0));
9123 }
9124 }
9125 }
9126
9127 // read the cellVolume of bndry-Cells from the body-restart-File
9128 if((mode > 0) && m_restart) {
9129 RECORD_TIMER_STOP(m_tCutGroup);
9130 RECORD_TIMER_STOP(m_tCutGroupTotal);
9131 const MFloat time0 = MPI_Wtime();
9132 if(m_geometryChange == nullptr) {
9133 loadBodyRestartFile(1);
9134 } else {
9135 setOldGeomBndryCellVolume();
9136 }
9137 const MFloat time1 = MPI_Wtime();
9138 if(domainId() == 0) m_log << "loadBodyRestartFile time " << time1 - time0 << endl;
9139 RECORD_TIMER_START(m_tCutGroupTotal);
9140 RECORD_TIMER_START(m_tCutGroup);
9141 }
9142
9143 RECORD_TIMER_START(tReinit);
9144
9145 // update oldBndryCells after adaptation if they are no longer leaf cells
9146 // this needs to be done before deleteNeighbourLinks and after computeCutPoints
9147 if(mode == 0) {
9148 correctRefinedBndryCell();
9149 }
9150
9151 // NOTE: the new gapInitMethod uses the minimum velocity of the two bodies which
9152 // is zero for current applications!
9153 if(m_closeGaps && m_gapInitMethod == 0) {
9154 setGapCellId();
9155 interpolateGapBodyVelocity();
9156 }
9157
9158 deleteNeighbourLinks();
9159 computeVolumeFraction();
9160
9161 // determines gap-Cell-Types
9162 // needs the nodalLsValues to determine GapCell-States
9163 // at this point isactive is set correctly and neighborLinks are deleted :)
9164 // all cell volumes are initialised und must be updated
9165 //(a_cellVolume, a_FcellVolume, m_volumeFraction)
9166 // but split-cells are already included
9167 if(m_levelSet && m_closeGaps && m_gapInitMethod > 0) {
9168 gapHandling();
9169 }
9170
9171 m_fvBndryCnd->createSortedBndryCellList(); // TODO labels:FVMB only update
9172
9173 // Call initCutOffBC because MB bndryCells are not set in initSolutionStep
9174 if(mode >= 0) {
9175 initCutOffBoundaryCondition();
9176 }
9177 if(m_fvBndryCnd->m_createBoundaryAtCutoff && m_alwaysResetCutOff) {
9178 resetCutOffCells();
9179 m_fvBndryCnd->createBoundaryAtCutoff();
9180 m_fvBndryCnd->initBndryCommunications();
9181 }
9182
9183 m_fvBndryCnd->setBCTypes(m_movingBndryCndId);
9184 determineNearBndryCells();
9185 initSpongeLayer();
9186
9187 IF_CONSTEXPR(nDim == 3) {
9188 const MFloat deltaDomain = mMin(F1B2 * (m_bbox[nDim + 1] - m_bbox[1]), F1B2 * (m_bbox[nDim + 2] - m_bbox[2]));
9189 const MFloat deltaSpongePart = (Context::propertyExists("deltaSpongePart", m_solverId))
9190 ? Context::getSolverProperty<MFloat>("deltaSpongePart", m_solverId, AT_)
9191 : F0;
9192 const MFloat deltaSponge = mMax(F0, deltaDomain - deltaSpongePart);
9193 if(deltaSpongePart > F0 && deltaSponge > F0) {
9194 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
9195 if(a_isBndryGhostCell(cellId)) continue;
9196 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
9197 // MFloat dist = sqrt( POW2(a_coordinate( cellId , 1)-m_bodyCenter[1]) + POW2(a_coordinate( cellId ,
9198 // 2)-m_bodyCenter[2]) );
9199 MFloat dist =
9200 mMax(fabs(a_coordinate(cellId, 1) - m_bodyCenter[1]), fabs(a_coordinate(cellId, 2) - m_bodyCenter[2]));
9201 for(MUint i = 0; i < m_periodicGhostBodies[0].size(); i++) {
9202 MInt l = m_periodicGhostBodies[0][i];
9203 dist = mMin(dist, mMax(fabs(a_coordinate(cellId, 1) - m_bodyCenter[nDim * l + 1]),
9204 fabs(a_coordinate(cellId, 2) - m_bodyCenter[nDim * l + 2])));
9205 }
9206 MFloat constant = m_sigmaSponge * mMin(F1, mMax(F0, (dist - deltaSponge) / (deltaDomain - deltaSponge)));
9207 if(a_hasProperty(cellId, SolverCell::IsInSpongeLayer)) {
9208 a_spongeFactor(cellId) = mMax(a_spongeFactor(cellId), constant);
9209 } else if(constant > 1e-12) {
9210 m_cellsInsideSpongeLayer[m_noCellsInsideSpongeLayer] = cellId;
9211 m_noCellsInsideSpongeLayer++;
9212 a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = true;
9213 a_spongeFactor(cellId) = constant;
9214 }
9215 }
9216 }
9217 }
9218
9219 if(m_createSpongeBoundary) m_fvBndryCnd->createSpongeAtSpongeBndryCnds();
9220
9221#ifdef _MB_DEBUG_
9222 checkBoundaryCells();
9223
9224 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
9225 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9226 const MFloat cellHalfLength = F1B2 * c_cellLengthAtCell(cellId);
9227 const MFloat deltaMax = (sqrt((MFloat)nDim) + 0.1) * cellHalfLength;
9228 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9229 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0] < 0) {
9230 cerr << ": " << domainId() << " " << srfc << " " << m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0] << " "
9231 << a_associatedBodyIds(cellId, srfc) << " " << cellId << " " << c_globalId(cellId) << endl;
9232 mTerm(1, AT_, "body id mismatch.");
9233 } else if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0]
9234 != a_associatedBodyIds(cellId, m_bodyToSetTable[m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0]])) {
9235 cerr << ": " << domainId() << " " << srfc << " " << m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0] << " "
9236 << " " << cellId << " " << c_globalId(cellId) << endl;
9237 mTerm(1, AT_, "body id mismatch2.");
9238 }
9239 if(m_bodyTypeMb == 1) {
9240 MInt k = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0];
9241 MFloat dist = F0;
9242 for(MInt i = 0; i < nDim; i++) {
9243 dist += POW2(a_coordinate(cellId, i) - m_bodyCenter[nDim * k + i]);
9244 }
9245 dist = sqrt(dist) - m_bodyRadius[k];
9246 if(dist > deltaMax) {
9247 cerr << "distance check: " << domainId() << " " << srfc << " "
9248 << m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0] << " "
9249 << " " << cellId << " " << c_globalId(cellId) << " / " << dist << " " << deltaMax << " / "
9250 << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, 2) << " / "
9251 << m_bodyCenter[nDim * k + 0] << " " << m_bodyCenter[nDim * k + 1] << " " << m_bodyCenter[nDim * k + 2]
9252 << endl;
9253 cerr << "body too far away, body id might be wrong." << endl;
9254 // mTerm(1,AT_,"body too far away, body id might be wrong.");
9255 }
9256 }
9257 }
9258 }
9259#endif
9260
9261 // set factor and deltaX for bndry-Surfaces
9262 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
9263 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9264 for(MInt dir = 0; dir < m_noDirs; dir++) {
9265 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
9266 if(srfcId > -1) {
9267 MInt nghbrId0 = a_surfaceNghbrCellId(srfcId, 0);
9268 MInt nghbrId1 = a_surfaceNghbrCellId(srfcId, 1);
9269 ASSERT(nghbrId0 > -1 && nghbrId1 > -1, "");
9270 a_surfaceFactor(srfcId, 0) = F0;
9271 MFloat tmp = F0;
9272 for(MInt i = 0; i < nDim; i++) {
9273 a_surfaceFactor(srfcId, 0) += POW2(a_surfaceCoordinate(srfcId, i) - a_coordinate(nghbrId0, i));
9274 tmp += POW2(a_surfaceCoordinate(srfcId, i) - a_coordinate(nghbrId1, i));
9275 }
9276 a_surfaceFactor(srfcId, 0) = sqrt(a_surfaceFactor(srfcId, 0));
9277 tmp = sqrt(tmp);
9278 a_surfaceFactor(srfcId, 0) = tmp / (a_surfaceFactor(srfcId, 0) + tmp);
9279 a_surfaceFactor(srfcId, 1) = F1 - a_surfaceFactor(srfcId, 0);
9280 for(MInt i = 0; i < nDim; i++) {
9281 a_surfaceDeltaX(srfcId, i) =
9282 a_surfaceCoordinate(srfcId, i) - a_coordinate(a_surfaceNghbrCellId(srfcId, 0), i);
9283 a_surfaceDeltaX(srfcId, nDim + i) =
9284 a_surfaceCoordinate(srfcId, i) - a_coordinate(a_surfaceNghbrCellId(srfcId, 1), i);
9285 }
9286 }
9287 }
9288 }
9289 RECORD_TIMER_STOP(tReinit);
9290
9291
9292 RECORD_TIMER_START(tMassRedist);
9293
9294 m_temporarilyLinkedCells.clear();
9295 for(MInt i = 0; i < noNeighborDomains(); i++) {
9296 m_linkedWindowCells[i].clear();
9297 m_linkedHaloCells[i].clear();
9298 }
9299
9300 const MInt noBCells = m_fvBndryCnd->m_bndryCells->size();
9301 // NOTE: first right Hand side specialty:
9302 if(mode == 1) { // firstRun => first right hand side
9303 // set wasInactive just as isInactive as no information of previous timestep is available
9304 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
9305 MInt cellId = m_bndryLayerCells[c];
9306 a_hasProperty(cellId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::IsInactive);
9307 }
9308
9309 // set volume purely based on bndryCell-volume which was previously set from file the restartFile!
9310 for(MInt bndryId = 0; bndryId < noBCells; bndryId++) {
9311 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9312 a_cellVolume(cellId) = mMax(m_volumeThreshold, m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume);
9313 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
9314 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
9315 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = a_cellVolume(cellId);
9316 }
9317
9318 } else if(mode == 2) {
9319 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
9320 MInt cellId = m_bndryLayerCells[c];
9321 a_hasProperty(cellId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::IsInactive);
9322 }
9323 for(MInt bndryId = 0; bndryId < noBCells; bndryId++) {
9324 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9325 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
9326 }
9327 } else { // mode == 0 || mode == -1
9328
9329#if defined _MB_DEBUG_ || !defined NDEBUG
9330 checkHaloBndryCells(false);
9331 // m_sweptVolume is beeing updated and checked below!
9332#endif
9333
9334 linkBndryCells();
9335
9336 // initialize bndry-Cells
9337 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
9338 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9339 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
9340 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
9341 // a) new boundary cell: was inactive before and is active now:
9342
9343 // no mass at the previous time step, this is conservative
9344 m_cellVolumesDt1[cellId] = F0;
9345 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = F0;
9346 m_sweptVolumeDt1[bndryId] = F0;
9347 for(MInt v = 0; v < m_noFVars; v++) {
9348 a_rightHandSide(cellId, v) = F0;
9349 m_rhs0[cellId][v] = F0;
9350 }
9351
9352 } else { // was-active
9353 if(m_oldBndryCells.count(cellId)) continue;
9354 // b) cell which was an internal-Cell before
9355
9356 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
9357 // if ( a_isHalo( cellId ) ) continue;
9358 if(m_cellVolumesDt1[cellId] < grid().gridCellVolume(a_level(cellId))) {
9359 // if the cell wasn't a boundary-cell before,
9360 // it can't have been a cut cell and its volume
9361 // should equal the grid-volume!
9362
9363
9364 cerr << endl
9365 << "*************** Strange behavior " << domainId() << " " << globalTimeStep << " " << cellId << " "
9366 << c_globalId(cellId) << " /wi " << a_hasProperty(cellId, SolverCell::WasInactive) << " /ii "
9367 << a_hasProperty(cellId, SolverCell::IsInactive) << " /l " << a_level(cellId) << " /v "
9368 << m_cellVolumesDt1[cellId] / grid().gridCellVolume(a_level(cellId)) << " "
9369 << (grid().gridCellVolume(a_level(cellId)) - m_cellVolumesDt1[cellId])
9370 / grid().gridCellVolume(a_level(cellId))
9371 << " " << m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume / grid().gridCellVolume(a_level(cellId))
9372 << " /h " << a_hasProperty(cellId, Cell::IsHalo) << " /sl "
9373 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " /sd "
9374 << a_hasProperty(cellId, SolverCell::IsSplitChild) << " " << m_sweptVolumeDt1[bndryId] << " "
9375 << a_bndryId(cellId) << " " << globalTimeStep << " " << a_levelSetValuesMb(cellId, 0) << " "
9376 << m_oldBndryCells.size() << " " << m_oldBndryCells.count(cellId) << " "
9377 << m_nearBoundaryBackup.count(cellId) << endl
9378 << endl;
9379 if(m_cellVolumesDt1[cellId] < 0.9 * grid().gridCellVolume(a_level(cellId))) {
9380 mTerm(1, AT_, "strange behavior.");
9381 }
9382 }
9383 m_sweptVolumeDt1[bndryId] = F0;
9384 // cellVolumeDt1 should be gridCellVolume
9385 }
9386 }
9387 }
9388
9389#if defined _MB_DEBUG_ || !defined NDEBUG
9390 if(noNeighborDomains() > 0) {
9391 ScratchSpace<MLong> gid(a_noCells(), AT_, "gid");
9392 gid.fill((MLong)-2);
9393 for(MInt i = 0; i < noNeighborDomains(); i++) {
9394 for(MInt j = 0; j < (signed)m_linkedHaloCells[i].size(); j++) {
9395 MInt cellId = m_linkedHaloCells[i][j];
9396 gid(cellId) = c_globalId(cellId);
9397 }
9398 }
9399 MUint recvSize = maia::mpi::getBufferSize(grid().windowCells());
9400 ScratchSpace<MLong> recvBuffer(mMax(1u, recvSize), AT_, "recvBuffer");
9401 maia::mpi::reverseExchangeData(grid().neighborDomains(), grid().haloCells(), grid().windowCells(), mpiComm(),
9402 &gid(0), &recvBuffer[0]);
9403 recvSize = 0;
9404
9405 for(MInt i = 0; i < noNeighborDomains(); i++) {
9406 MUint commCnt = 0;
9407 for(MInt j = 0; j < noWindowCells(i); j++) {
9408 MInt cellId = windowCellId(i, j);
9409 if(recvBuffer(recvSize) != -2 && c_globalId(cellId) != recvBuffer(recvSize))
9410 cerr << c_globalId(cellId) << " " << recvBuffer(recvSize) << endl;
9411 if(recvBuffer(recvSize) != -2 && c_globalId(cellId) != recvBuffer(recvSize))
9412 mTerm(1, AT_, "linked halo cell connection failed.");
9413 if(recvBuffer(recvSize) != -2) {
9414 ASSERT(recvBuffer(recvSize) > -1, "");
9415 // Same window can be used as master more than once
9416 for(MInt p = 0; p < (signed)m_linkedWindowCells[i].size(); p++) {
9417 if(c_globalId(m_linkedWindowCells[i][p]) == recvBuffer(recvSize)) commCnt++;
9418 }
9419 }
9420 recvSize++;
9421 }
9422 if(commCnt != m_linkedWindowCells[i].size()) {
9423 cerr << domainId() << ": ERR LINK " << neighborDomain(i) << " " << commCnt << " "
9424 << m_linkedWindowCells[i].size() << endl;
9425 for(MInt j = 0; j < (signed)m_linkedWindowCells[i].size(); j++) {
9426 cerr << domainId() << " LW " << j << " " << m_linkedWindowCells[i][j] << " "
9427 << c_globalId(m_linkedWindowCells[i][j]) << endl;
9428 }
9429 for(MInt j = 0; j < (signed)m_linkedHaloCells[i].size(); j++) {
9430 cerr << domainId() << " LH " << j << " " << m_linkedHaloCells[i][j] << " "
9431 << c_globalId(m_linkedHaloCells[i][j]) << endl;
9432 }
9433 // mTerm(1,AT_, "linked halo cell connection failed (2).");
9434 }
9435 }
9436 }
9437
9438#endif
9439
9440 // a) initialise swetVolumeDt for all bndryCells with 0
9441 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
9442 m_sweptVolumeDt1[bndryId] = F0;
9443 }
9444
9445 // b) restore swetVolumeDt from oldBndryCells
9446 for(map<MInt, MFloat>::iterator it = m_oldBndryCells.begin(); it != m_oldBndryCells.end(); it++) {
9447 if(a_bndryId(it->first) > -1) {
9448 m_sweptVolumeDt1[a_bndryId(it->first)] = it->second;
9449 }
9450 }
9451
9452 // c) initialise swetVolume for all bndryCells with 0
9453 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
9454 m_sweptVolume[bndryId] = F0;
9455 }
9456
9457 // d) initialise CellVolumes for splitChilds, based on split-Cell Volumes
9458 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
9459 const MInt cellId = m_splitCells[sc];
9460 MFloat cvol = F0;
9461 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
9462 const MInt splitChildId = m_splitChilds[sc][ssc];
9463 MFloat vol = m_fvBndryCnd->m_bndryCells->a[a_bndryId(splitChildId)].m_volume;
9464 cvol += vol;
9465 a_cellVolume(splitChildId) = vol * a_cellVolume(cellId);
9466 m_cellVolumesDt1[splitChildId] = vol * m_cellVolumesDt1[cellId];
9467 m_sweptVolume[a_bndryId(splitChildId)] = vol * m_sweptVolume[a_bndryId(cellId)];
9468 m_sweptVolumeDt1[a_bndryId(splitChildId)] = vol * m_sweptVolumeDt1[a_bndryId(cellId)];
9469 for(MInt v = 0; v < m_noFVars; v++) {
9470 m_rhs0[splitChildId][v] = vol * m_rhs0[cellId][v];
9471 }
9472 }
9473 cvol = mMax(1e-15, cvol);
9474 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
9475 const MInt splitChildId = m_splitChilds[sc][ssc];
9476 a_cellVolume(splitChildId) /= cvol;
9477 m_cellVolumesDt1[splitChildId] /= cvol;
9478 m_sweptVolume[a_bndryId(splitChildId)] /= cvol;
9479 m_sweptVolumeDt1[a_bndryId(splitChildId)] /= cvol;
9480 for(MInt v = 0; v < m_noFVars; v++) {
9481 m_rhs0[splitChildId][v] /= cvol;
9482 }
9483 }
9484 }
9485
9486
9487#ifdef GEOM_CONS_LAW
9488
9490 if(m_levelSet && m_closeGaps && m_gapInitMethod > 0) {
9491 updateGapBoundaryCells();
9492 }
9493
9494 if(mode == 0) {
9495 correctRefinedBndryCellVolume();
9496 correctCoarsenedBndryCellVolume();
9497 }
9498
9499 // e) update CellVolume of bndryCells (mode-dependand!)
9500 // default(-1): update according to the GCL-Function
9501 // firt-step : initialise Dt-Variables using dV
9502 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
9503 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9504 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
9505
9506 const MFloat vol0 = a_cellVolume(cellId);
9507 const MFloat deltaVol = updateCellVolumeGCL(bndryId); // dV
9508
9509 // old gapInitMethod: change cellVolume of all Cells if gapOpened! (not mass-conservative!)
9510 if((mode == 1) || (m_gapInitMethod == 0 && m_gapOpened)) {
9511 // call before first right Hand Side (or old gap-opening method)
9512 a_cellVolume(cellId) = mMax(m_volumeThreshold, m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume);
9513 m_cellVolumesDt1[cellId] = a_cellVolume(cellId) - deltaVol;
9514 m_sweptVolumeDt1[bndryId] = m_sweptVolume[bndryId];
9515
9516 // set static volume for geometry-change in cells with large volume dif
9517 // from the original geometry cell volume!
9518 if(m_geometryChange != nullptr) {
9519 auto it0 = m_oldGeomBndryCells.find(cellId);
9520 if(it0 != m_oldGeomBndryCells.end()) {
9521 m_sweptVolumeDt1[bndryId] = 0;
9522 m_sweptVolume[bndryId] = 0;
9523 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
9524 m_cellVolumesDt1[cellId] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
9525 }
9526 }
9527
9528 } else if(mode == 2) {
9529 /*m_sweptVolumeDt1[bndryId] = F2*dV0 - m_sweptVolume[bndryId];
9530 MFloat deltaVol = F0;
9531 if ( m_gclIntermediate ) {
9532 if ( m_levelSetMb ) {
9533 deltaVol = ( m_RKStep == 0 ) ? m_sweptVolumeDt1[ bndryId ] : m_RKalpha[ m_RKStep-1 ] * m_sweptVolume[ bndryId
9534 ] + (F1-m_RKalpha[ m_RKStep-1 ]) * m_sweptVolumeDt1[ bndryId ] ;
9535 }
9536 } else {
9537 deltaVol = ( m_levelSetMb ) ? F1B2 * ( m_sweptVolume[ bndryId ] + m_sweptVolumeDt1[ bndryId ] ) : m_sweptVolume[
9538 bndryId ];
9539 }
9540 a_cellVolume( cellId ) = m_cellVolumesDt1[ cellId ] + deltaVol;*/
9541 m_sweptVolumeDt1[bndryId] = m_sweptVolume[bndryId]; // F0;
9542 a_cellVolume(cellId) = vol0;
9543 m_cellVolumesDt1[cellId] = vol0 - m_sweptVolume[bndryId];
9544 } else if(a_cellVolume(cellId) < m_volumeThreshold && !a_isPeriodic(cellId) && !a_isHalo(cellId)) {
9545 /* //const MFloat deltaVol = m_cellVolumesDt1[cellId] - (a_cellVolume( cellId ) - dV);
9546 const MFloat deltaVol = m_cellVolumesDt1[cellId] - (m_volumeThreshold - dV);
9547 const MFloat fac = deltaVol / m_cellVolumesDt1[cellId];
9548 m_cellVolumesDt1[ cellId ] = a_cellVolume( cellId ) - dV;
9549 if ( fabs(deltaVol) > 1e-16 ) {
9550 cerr << globalTimeStep << setprecision(16) << " cell vol dropped below zero " << cellId << " " << a_cellVolume(
9551 cellId ) << " (" << m_cellVolumesDt1[ cellId ] << " / " << dV << ")" << endl;
9552 m_massRedistributionIds.push_back(cellId);
9553 m_massRedistributionVariables.resize(m_massRedistributionIds.size()*noVars);
9554 m_massRedistributionRhs.resize(m_massRedistributionIds.size()*noVars);
9555 m_massRedistributionVolume.resize(m_massRedistributionIds.size());
9556 m_massRedistributionSweptVol.resize(m_massRedistributionIds.size());
9557 for ( MUint v = 0; v < noVars; v++ ) {
9558 m_massRedistributionVariables[(m_massRedistributionIds.size()-1)*noVars + v ] = a_oldVariable( cellId , v );
9559 m_massRedistributionRhs[(m_massRedistributionIds.size()-1)*noVars + v ] = fac * m_rhs0[ cellId ][ v ];
9560 m_rhs0[ cellId ][ v ] *= (F1-fac);
9561 }
9562 m_massRedistributionVolume[m_massRedistributionIds.size()-1] = deltaVol;
9563 m_massRedistributionSweptVol[m_massRedistributionIds.size()-1] = fac * m_sweptVolumeDt1[ bndryId ];
9564 m_sweptVolumeDt1[ bndryId ] *= (F1-fac);
9565 //cerr << "exceed " << a_oldVariable( cellId , CV->RHO ) *deltaVol << endl;
9566 }*/
9567 // if ( !a_hasProperty(cellId, SolverCell::WasInactive ) ) cerr << domainId() << ": cell volume below threshold "
9568 // << c_globalId(cellId) << " " << a_cellVolume( cellId ) << " " << m_volumeThreshold << " " << m_cellVolumesDt1[
9569 // cellId ] << endl;
9570 }
9571 if(a_cellVolume(cellId) < F0 && !a_isPeriodic(cellId) && !a_isHalo(cellId)) {
9572 // cerr << domainId() << ": " << globalTimeStep << " cell vol dropped below zero " << cellId << " " <<
9573 // a_cellVolume( cellId ) << " (" << m_cellVolumesDt1[ cellId ] << " / " << dV << ")" << endl;
9574 }
9575
9576 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
9577 m_volumeFraction[bndryId] = a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId));
9578 }
9579#else
9580 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
9581 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9582 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
9583 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
9584 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
9585 m_volumeFraction[bndryId] = a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId));
9586 }
9587#endif
9588
9589#if defined _MB_DEBUG_ || !defined NDEBUG
9590 MFloatScratchSpace testvol(m_noEmbeddedBodies + 1, 4, AT_, "testvol");
9591 testvol.fill(F0);
9592 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
9593 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9594 if(a_isHalo(cellId)) continue;
9595 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) {
9596 ASSERT(m_bndryCells->a[bndryId].m_noSrfcs == 0, "");
9597 continue;
9598 }
9599 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
9600 MInt body = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0];
9601 MInt bodyId = m_internalBodyId[body];
9602 MFloat dV = F0;
9603 MFloat dt = timeStep(true);
9604 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
9605 for(MInt i = 0; i < nDim; i++) {
9606 MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
9607 dV -= dt * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] * nml * area;
9608 testvol(bodyId, i) += nml * area;
9609 }
9610 testvol(bodyId, nDim) += dV;
9611 }
9612 testvol(m_noEmbeddedBodies, 0) += m_sweptVolume[bndryId];
9613 testvol(m_noEmbeddedBodies, 1) += m_sweptVolumeDt1[bndryId];
9614 }
9615 MPI_Allreduce(MPI_IN_PLACE, &testvol(0), testvol.size(), MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
9616 "testvol(0)");
9617 if(domainId() == 0) {
9618 for(MInt b = 0; b < mMin(4, m_noEmbeddedBodies); b++) {
9619 cerr << b << " " << testvol(b, 0) << " " << testvol(b, 1) << " " << testvol(b, 2) << " " << testvol(b, 3) << endl;
9620 }
9621 cerr << "VOL CHECK -- " << testvol(m_noEmbeddedBodies, 0) << " " << testvol(m_noEmbeddedBodies, 1) << endl << endl;
9622 }
9623#endif
9624
9625 // f) set massRedistribution-Info for oldBndryCells
9626 for(map<MInt, MFloat>::iterator it = m_oldBndryCells.begin(); it != m_oldBndryCells.end(); it++) {
9627 // ASSERT(mode != 2, "");
9628 MInt cellId = it->first;
9629
9630 // skip old Bndry-Cells which are still a bndry-Cell!
9631 if(a_bndryId(cellId) > -1) continue;
9632
9633
9634 MBool conserveMass1 = true;
9635 MBool conserveMass2 = true;
9636 if(m_levelSet && m_closeGaps && m_gapInitMethod == 0) {
9637 MBool isGapCell = (a_hasProperty(cellId, SolverCell::IsGapCell));
9638 MBool wasGapCell = (a_hasProperty(cellId, SolverCell::WasGapCell));
9639
9640 if(isGapCell || wasGapCell) conserveMass1 = false;
9641 if(wasGapCell) conserveMass2 = false;
9642
9643 // The conserveMass-triggers are used to prevent the
9644 // direct-mass conservation of the 2 types of cut-Cell changes (submerging && becoming internal)
9645 // only used in the old Methode, in the new method the mass is conserved during gap-Widening
9646 // and -shrinking. And for initGapOpeing and initGapClosure the conservation is handeled in
9647 // in gapHandling()
9648
9649 } else if(m_levelSet && m_closeGaps && m_gapInitMethod > 0 && (a_isGapCell(cellId) || a_wasGapCell(cellId))
9650 && !a_isHalo(cellId) && !a_isPeriodic(cellId)) {
9651 // this should now already been done in gapHandling-where these cells are either
9652 // removed from the oldBndryCell-List or the mass is truely conserved!
9653 const MInt regionId = m_gapCells[m_gapCellId[cellId]].region;
9654 if(regionId <= m_noGapRegions) {
9655 /*
9656 if(m_gapState[regionId] == -2) {
9657 cerr << "Stopped massRedistribution of Cell " << c_globalId(cellId)
9658 << " Type: " << m_gapCells[m_gapCellId[cellId]].status << endl;
9659 conserveMass1 = false;
9660 } else if (m_gapState[regionId] == 2) {
9661 cerr << "Stopped massRedistribution of Cell " << c_globalId(cellId)
9662 << " Type: " << m_gapCells[m_gapCellId[cellId]].status << endl;
9663 conserveMass1 = false;
9664 //this part should not be necessary for gap-Opening:
9665 // there shouldn't be a any submerging gap-Cells. Change to always set true and a check
9666 // in the according if-statement below!
9667
9668 //only for GapOpening!
9669 if(a_wasGapCell(cellId)) {
9670 conserveMass2 = false;
9671 cerr << "Stopped massRedistribution-2 of Cell " << c_globalId(cellId)
9672 << m_gapCells[m_gapCellId[cellId]].status << endl;
9673 }
9674
9675 }
9676 */
9677
9678 if(m_gapState[regionId] == 2) {
9679 // only for GapOpening!
9680 if(a_wasGapCell(cellId)) {
9681 // should be of Type 23, change to ASSERT!
9682 cerr << "Trying massRedistribution-2 of Cell " << c_globalId(cellId) << " "
9683 << m_gapCells[m_gapCellId[cellId]].status << endl;
9684 //}
9685 }
9686 }
9687 }
9688 }
9689
9690 for(MInt v = 0; v < m_noFVars; v++) {
9691 a_rightHandSide(cellId, v) = F0;
9692 }
9694 if(a_hasProperty(cellId, SolverCell::IsInactive) && a_bndryId(cellId) < 0
9695 && !a_hasProperty(cellId, SolverCell::WasInactive)) {
9696 if(!a_isPeriodic(cellId) && !a_isHalo(cellId) && conserveMass1) {
9697 if(m_levelSet && m_closeGaps && m_gapInitMethod > 0 && (a_isGapCell(cellId) || a_wasGapCell(cellId))) {
9698 MInt regionId = m_gapCells[m_gapCellId[cellId]].region;
9699 if(regionId < m_noGapRegions && (m_gapState[regionId] == -2 || m_gapState[regionId] == 2)) {
9700 cerr << "Trying massRedistribution of GapCell" << c_globalId(cellId)
9701 << " Type: " << m_gapCells[m_gapCellId[cellId]].status
9702 << " This should not happen during Opening or Closing!" << endl;
9703 }
9704 }
9705
9706 m_massRedistributionIds.push_back(cellId);
9707 m_massRedistributionVariables.resize(m_massRedistributionIds.size() * m_noCVars);
9708 m_massRedistributionRhs.resize(m_massRedistributionIds.size() * m_noFVars);
9709 m_massRedistributionVolume.resize(m_massRedistributionIds.size());
9710 m_massRedistributionSweptVol.resize(m_massRedistributionIds.size());
9711 for(MInt v = 0; v < m_noCVars; v++) {
9712 m_massRedistributionVariables[(m_massRedistributionIds.size() - 1) * m_noCVars + v] =
9713 a_oldVariable(cellId, v);
9714 }
9715 for(MInt v = 0; v < m_noFVars; v++) {
9716 m_massRedistributionRhs[(m_massRedistributionIds.size() - 1) * m_noFVars + v] = m_rhs0[cellId][v];
9717 m_rhs0[cellId][v] = F0;
9718 }
9719 m_massRedistributionVolume[m_massRedistributionIds.size() - 1] = m_cellVolumesDt1[cellId];
9720 m_massRedistributionSweptVol[m_massRedistributionIds.size() - 1] = it->second;
9721 }
9722 removeSurfaces(cellId);
9723 a_cellVolume(cellId) = grid().gridCellVolume(a_level(cellId)); // F0;
9724 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId)); // F0;
9725 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = grid().gridCellVolume(a_level(cellId)); // F0;
9726 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
9727 }
9729 else if(a_hasProperty(cellId, SolverCell::WasInactive) && a_bndryId(cellId) > -1) {
9730 m_cellVolumesDt1[cellId] = F0; // had no mass at the previous time step, this is conservative
9731 if(m_dualTimeStepping)
9732 m_cellVolumesDt2[cellId] = F0; // had no mass at the previous time step, this is conservative
9733 for(MInt v = 0; v < m_noFVars; v++) {
9734 m_rhs0[cellId][v] = F0;
9735 }
9736 cerr << "case should not appear " << domainId() << " " << globalTimeStep << " " << cellId << endl;
9737 }
9739 if(!a_hasProperty(cellId, SolverCell::IsInactive) && a_bndryId(cellId) < 0) {
9740 if(!a_isPeriodic(cellId) && !a_isHalo(cellId)) {
9741 // all old-bndry-Cells which are still active, but are not a bndryCell anymore!
9742 const MFloat deltaVol = m_cellVolumesDt1[cellId] - grid().gridCellVolume(a_level(cellId));
9743 if(fabs(deltaVol) > 1e-16 && conserveMass2) {
9744 m_massRedistributionIds.push_back(cellId);
9745 m_massRedistributionVariables.resize(m_massRedistributionIds.size() * m_noCVars);
9746 m_massRedistributionRhs.resize(m_massRedistributionIds.size() * m_noFVars);
9747 m_massRedistributionVolume.resize(m_massRedistributionIds.size());
9748 m_massRedistributionSweptVol.resize(m_massRedistributionIds.size());
9749 for(MInt v = 0; v < m_noCVars; v++) {
9750 m_massRedistributionVariables[(m_massRedistributionIds.size() - 1) * m_noCVars + v] =
9751 a_oldVariable(cellId, v);
9752 }
9753 for(MInt v = 0; v < m_noFVars; v++) {
9754 m_massRedistributionRhs[(m_massRedistributionIds.size() - 1) * m_noFVars + v] =
9755 -it->second * a_oldVariable(cellId, v) / timeStep();
9756 m_rhs0[cellId][v] += it->second * a_oldVariable(cellId, v) / timeStep();
9757 }
9758 m_massRedistributionVolume[m_massRedistributionIds.size() - 1] = deltaVol;
9759 m_massRedistributionSweptVol[m_massRedistributionIds.size() - 1] = it->second;
9760 }
9761 }
9762 {
9763 a_cellVolume(cellId) = grid().gridCellVolume(a_level(cellId));
9764 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId));
9765 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = grid().gridCellVolume(a_level(cellId));
9766 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
9767 }
9768 }
9769 }
9770
9771
9772 // g) update CellVolume for splitCells
9773 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
9774 const MInt cellId = m_splitCells[sc];
9775 MFloat vol = F0;
9776 MFloat vol1 = F0;
9777 MFloat svol = F0;
9778 MFloat svol1 = F0;
9779 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
9780 const MInt splitChildId = m_splitChilds[sc][ssc];
9781 // a_cellVolume( splitChildId ) = m_fvBndryCnd->m_bndryCells->a[ a_bndryId(splitChildId) ].m_volume;
9782 vol += a_cellVolume(splitChildId);
9783 vol1 += m_cellVolumesDt1[splitChildId];
9784 svol += m_sweptVolume[a_bndryId(splitChildId)];
9785 svol1 += m_sweptVolumeDt1[a_bndryId(splitChildId)];
9786 }
9787 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
9788 // const MInt splitChildId = m_splitChilds[sc][ssc];
9789 // m_cellVolumesDt1[splitChildId] = a_cellVolume(splitChildId)*m_cellVolumesDt1[cellId]/mMax(1e-15,vol);
9790 }
9791 a_cellVolume(cellId) = vol;
9792 m_cellVolumesDt1[cellId] = vol1;
9793 m_sweptVolume[a_bndryId(cellId)] = svol;
9794 m_sweptVolumeDt1[a_bndryId(cellId)] = svol1;
9795 }
9796
9797
9798#if defined _MB_DEBUG_ || !defined NDEBUG
9799
9800 checkHaloBndryCells(true);
9801 checkHaloCells();
9802
9803 if(m_levelSet && m_closeGaps && m_gapInitMethod > 0) {
9804 checkGapCells();
9805 }
9806
9807 // check-cell-Volumes
9808 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
9809 if(a_cellVolume(cellId) < 0) {
9810 cerr << "Negative cell-Volume " << c_globalId(cellId) << endl;
9811 }
9812 if(m_cellVolumesDt1[cellId] < 0 && mode != 1) {
9813 MInt status = -1;
9814 if(m_closeGaps && m_gapInitMethod > 0 && m_gapCellId[cellId] > 1) {
9815 status = m_gapCells[m_gapCellId[cellId]].status;
9816 }
9817 cerr << "Negative cell-Volume-Dt1 " << c_globalId(cellId) << " " << m_cellVolumesDt1[cellId] << " " << status
9818 << endl;
9819 }
9820 }
9821
9822#endif
9823
9824 MInt noSplitFaces = 0;
9825 MInt noSplitFacesHalo = 0;
9826 MInt noSplitCells = 0;
9827 MInt noSplitCellsHalo = 0;
9828 for(MInt bndryId = 0; bndryId < noBCells; bndryId++) {
9829 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
9830 if(a_hasProperty(cellId, SolverCell::HasSplitFace)) noSplitFaces++;
9831 if(a_hasProperty(cellId, SolverCell::HasSplitFace) && a_isHalo(cellId)) noSplitFacesHalo++;
9832#ifdef _MB_DEBUG_
9833 if(a_hasProperty(cellId, SolverCell::HasSplitFace) && a_isHalo(cellId))
9834 cerr << domainId() << ": halo split face!" << endl;
9835 if(a_hasProperty(cellId, SolverCell::HasSplitFace) && a_isWindow(cellId))
9836 cerr << domainId() << ": window split face!" << endl;
9837#endif
9838 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
9839 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
9840 ASSERT(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId > -1, "");
9841 }
9842 }
9843 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
9844 const MInt cellId = m_splitCells[sc];
9845 // cerr << domainId() << ": split cell " << cellId << " (";
9846 // for( MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) cerr << m_splitChilds[sc][ssc] << ","; cerr << ")"
9847 // << endl; cerr << domainId() << ": vol " << a_cellVolume( cellId ) / grid().gridCellVolume( a_level(cellId) ) << "
9848 // ("; for( MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) cerr <<
9849 // a_cellVolume(m_splitChilds[sc)[ssc]]/grid().gridCellVolume(a_level(m_splitChilds[sc][ssc])) << ","; cerr << ")"
9850 // << endl; cerr << domainId() << ": vol1 " << m_cellVolumesDt1[ cellId ] / grid().gridCellVolume( a_level(cellId) )
9851 // << "
9852 // ("; for( MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) cerr <<
9853 // m_cellVolumesDt1[m_splitChilds[sc][ssc]]/grid().gridCellVolume(a_level(m_splitChilds[sc][ssc])) << ","; cerr <<
9854 // ")" << endl;
9855 noSplitCells++;
9856 if(a_isHalo(cellId)) noSplitCellsHalo++;
9857#ifdef _MB_DEBUG_
9858 if(a_isHalo(cellId)) cerr << domainId() << ": halo split cell!" << endl;
9859 if(a_isWindow(cellId)) cerr << domainId() << ": window split cell!" << endl;
9860#endif
9861 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
9862 if(a_hasProperty(m_splitChilds[sc][ssc], SolverCell::IsTempLinked))
9863 cerr << domainId() << ": linked split child " << m_splitChilds[sc][ssc] << " (" << cellId << ")" << endl;
9864 }
9865 for(MUint it = 0; it < m_temporarilyLinkedCells.size(); it++) {
9866 if(cellId == get<1>(m_temporarilyLinkedCells[it])) cerr << domainId() << ": master split cell " << cellId << endl;
9867 }
9868 /*
9869 for ( map<MInt,MInt>::iterator it = m_temporarilyLinkedCells.begin(); it != m_temporarilyLinkedCells.end(); it++
9870 ) { if ( cellId == it->second) cerr << domainId() << ": master split cell " << cellId << endl;
9871 }
9872 */
9873 }
9874#ifdef _MB_DEBUG_
9875 if(m_splitCells.size() > 0 || noSplitFaces > 0) {
9876 cerr << domainId() << ": " << noSplitCells << "(" << noSplitCellsHalo << ")"
9877 << " split cells and " << noSplitFaces << "(" << noSplitFacesHalo << ")"
9878 << " split faces at time step " << globalTimeStep << endl;
9879 }
9880#endif
9881
9882 // if ( firstRun ) {
9883 // firstRun = false;
9884 //}
9885
9886 if(mode > 0 && m_massRedistributionIds.size() > 0) {
9887 mTerm(1, AT_, "Not supposed to happen.");
9888 }
9889
9890 if(mode == 1 && m_initialCondition == 16 && !m_restart) {
9891 initBodyVelocities();
9892 }
9904 const MFloat ratio = (Context::propertyExists("particleTemperatureRatio", m_solverId))
9905 ? Context::getSolverProperty<MFloat>("particleTemperatureRatio", m_solverId, AT_)
9906 : F1;
9918 const MFloat initPPVelocitiesFactor =
9919 (Context::propertyExists("initPPVelocitiesFactor", m_solverId))
9920 ? Context::getSolverProperty<MFloat>("initPPVelocitiesFactor", m_solverId, AT_)
9921 : F1;
9922 if(mode == 1 && m_noPointParticles > 0) {
9923 setParticleFluidVelocities();
9924 for(MUint p = 0; p < m_particleCellLink.size(); p++) {
9925 for(MInt i = 0; i < nDim; i++) {
9926 m_particleVelocity[nDim * p + i] =
9927 initPPVelocitiesFactor * m_particleVelocityFluid[nDim * p + i] + m_particleTerminalVelocity[i];
9928 m_particleVelocityDt1[nDim * p + i] = m_particleVelocity[nDim * p + i];
9929 }
9930 m_particleTemperature[p] = ratio * m_particleFluidTemperature[p];
9931 m_particleTemperatureDt1[p] = m_particleTemperature[p];
9932 }
9933 }
9934
9935#ifdef _MB_DEBUG_
9936 MInt noLinked = (signed)m_temporarilyLinkedCells.size();
9937 MPI_Allreduce(MPI_IN_PLACE, &noLinked, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noLinked");
9938 m_log << "no linked cells " << globalTimeStep << ": " << noLinked << endl;
9939#endif
9940
9941 RECORD_TIMER_STOP(tMassRedist);
9942}
9943
9944
9949template <MInt nDim, class SysEqn>
9951 TRACE();
9952
9953 constexpr MFloat eps0 = 1e-12;
9954 constexpr MFloat eps1 = 1e-11;
9955
9956 MFloatScratchSpace cellCheck(a_noCells(), 14, AT_, "cellCheck");
9957 cellCheck.fill(std::numeric_limits<MFloat>::max());
9958
9959 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
9960 cellCheck(cellId, 0) = (MFloat)a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel);
9961 cellCheck(cellId, 1) = a_bndryId(cellId) > -1 ? (MFloat)m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs
9962 : std::numeric_limits<MFloat>::max();
9963 cellCheck(cellId, 2) = a_levelSetValuesMb(cellId, 0);
9964 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
9965 cellCheck(cellId, 3) = (MFloat)a_hasProperty(cellId, SolverCell::IsInactive);
9966 cellCheck(cellId, 4) = (MFloat)a_hasProperty(cellId, SolverCell::WasInactive);
9967 cellCheck(cellId, 5) = (MFloat)a_hasProperty(cellId, SolverCell::IsSplitCell);
9968 cellCheck(cellId, 6) = (MFloat)a_hasProperty(cellId, SolverCell::IsSplitChild);
9969 cellCheck(cellId, 7) = (MFloat)a_hasProperty(cellId, SolverCell::IsGapCell);
9970 cellCheck(cellId, 8) = (MFloat)a_hasProperty(cellId, SolverCell::WasGapCell);
9971 cellCheck(cellId, 9) = a_cellVolume(cellId);
9972 cellCheck(cellId, 10) = m_cellVolumesDt1[cellId];
9973 cellCheck(cellId, 11) =
9974 a_bndryId(cellId) > -1 ? m_sweptVolume[a_bndryId(cellId)] : std::numeric_limits<MFloat>::max();
9975 cellCheck(cellId, 12) =
9976 a_bndryId(cellId) > -1 ? m_sweptVolumeDt1[a_bndryId(cellId)] : std::numeric_limits<MFloat>::max();
9977 cellCheck(cellId, 13) = F1;
9978 }
9979 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
9980 const MInt cellId = m_splitCells[sc];
9981 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
9982 cellCheck(cellId, 9) += a_cellVolume(m_splitChilds[sc][ssc]);
9983 cellCheck(cellId, 10) += m_cellVolumesDt1[m_splitChilds[sc][ssc]];
9984 cellCheck(cellId, 11) += m_sweptVolume[a_bndryId(m_splitChilds[sc][ssc])];
9985 cellCheck(cellId, 12) += m_sweptVolumeDt1[a_bndryId(m_splitChilds[sc][ssc])];
9986 cellCheck(cellId, 13) += F1;
9987 }
9988 }
9989
9990 // exchangeData( &cellCheck(0), (MInt)cellCheck.size1() );
9991 exchangeData(&cellCheck(0), 14);
9992
9993 for(MInt cellId = noInternalCells(); cellId < a_noCells(); cellId++) {
9994 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
9995 // Azimuthal periodic window/halo cells are not identical in the sense of the cartesian grid!
9996 if(grid().azimuthalPeriodicity() && a_isPeriodic(cellId)) continue;
9997
9998 if((MInt)cellCheck(cellId, 0) != a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel))
9999 cerr << domainId() << ": ERR0 generateBndryCellsMb " << globalTimeStep << " " << cellId << " "
10000 << c_globalId(cellId) << " " << cellCheck(cellId, 0) << " "
10001 << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " "
10002 << (((a_hasProperty(cellId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(cellId) : cellId)) << " "
10003 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild)
10004 << " " << a_isHalo(cellId) << " " << a_isWindow(cellId) << " "
10005 << a_levelSetValuesMb(cellId, 0) / c_cellLengthAtCell(cellId) << " " << a_bndryId(cellId) << " "
10006 << a_level(((a_hasProperty(cellId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(cellId) : cellId))
10007 << endl;
10008 if((MInt)cellCheck(cellId, 1)
10009 != (MInt)(a_bndryId(cellId) > -1 ? (MFloat)m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs
10010 : std::numeric_limits<MFloat>::max())) {
10011 MFloat noSurfaces = std::numeric_limits<MFloat>::max();
10012 if(a_bndryId(cellId) > -1) {
10013 noSurfaces = (MFloat)m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs;
10014 }
10015 cerr << domainId() << ": ERR1 generateBndryCellsMb " << globalTimeStep << " " << cellId << " "
10016 << m_noOuterBndryCells << " " << a_bndryId(cellId) << " " << noSurfaces << " " << c_globalId(cellId) << endl;
10017 }
10018 if(fabs(cellCheck(cellId, 2) - a_levelSetValuesMb(cellId, 0)) > eps1)
10019 if(!m_adaptation
10020 || mMin(cellCheck(cellId, 2), a_levelSetValuesMb(cellId, 0)) < m_outerBandWidth[maxUniformRefinementLevel()])
10021 cerr << domainId() << ": ERR2 generateBndryCellsMb " << globalTimeStep << " " << cellId << " "
10022 << cellCheck(cellId, 2) << " " << a_levelSetValuesMb(cellId, 0) << " "
10023 << cellCheck(cellId, 2) - a_levelSetValuesMb(cellId, 0) << " " << c_globalId(cellId) << " "
10024 << m_bodyDistThreshold << endl;
10025 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
10026 if(!a_isHalo(cellId)) continue;
10027 if((MInt)cellCheck(cellId, 3) != a_hasProperty(cellId, SolverCell::IsInactive))
10028 cerr << domainId() << ": ERR3 generateBndryCellsMb " << globalTimeStep << " " << cellId << " "
10029 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild)
10030 << " " << a_isHalo(cellId) << " " << a_isWindow(cellId) << " " << a_levelSetValuesMb(cellId, 0) << endl;
10031 if((MInt)cellCheck(cellId, 4) != a_hasProperty(cellId, SolverCell::WasInactive))
10032 cerr << domainId() << ": ERR4 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10033 if((MInt)cellCheck(cellId, 5) != a_hasProperty(cellId, SolverCell::IsSplitCell))
10034 cerr << domainId() << ": ERR5 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10035 if((MInt)cellCheck(cellId, 6) != a_hasProperty(cellId, SolverCell::IsSplitChild))
10036 cerr << domainId() << ": ERR6 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10037 if((MInt)cellCheck(cellId, 7) != a_hasProperty(cellId, SolverCell::IsGapCell))
10038 cerr << domainId() << ": ERR7 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10039 if((MInt)cellCheck(cellId, 8) != a_hasProperty(cellId, SolverCell::WasGapCell))
10040 cerr << domainId() << ": ERR8 generateBndryCellsMb " << globalTimeStep << " " << c_globalId(cellId) << endl;
10041 if(!a_hasProperty(cellId, SolverCell::IsSplitCell) && !a_hasProperty(cellId, SolverCell::IsSplitCell)) {
10042 if(fabs(cellCheck(cellId, 9) - a_cellVolume(cellId)) > eps0)
10043 cerr << domainId() << ": ERR9 generateBndryCellsMb " << cellId << " " << c_globalId(cellId) << " "
10044 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild)
10045 << " " << a_isHalo(cellId) << " " << a_isWindow(cellId) << " ls " << a_levelSetValuesMb(cellId, 0) << " "
10046 << a_isGapCell(cellId) << " " << a_wasGapCell(cellId) << " " << a_bndryId(cellId) << " " << a_level(cellId)
10047 << " " << a_cellVolume(cellId) << " "
10048 << (cellCheck(cellId, 9) - grid().gridCellVolume(a_level(cellId))) / grid().gridCellVolume(a_level(cellId))
10049 << " "
10050 << (a_cellVolume(cellId) - grid().gridCellVolume(a_level(cellId))) / grid().gridCellVolume(a_level(cellId))
10051 << " " << fabs(cellCheck(cellId, 9) - a_cellVolume(cellId)) / grid().gridCellVolume(a_level(cellId))
10052 << endl;
10053
10054 if(fabs(cellCheck(cellId, 10) - m_cellVolumesDt1[cellId]) > eps0)
10055 cerr << domainId() << ": ERR10 generateBndryCellsMb " << globalTimeStep << " " << cellId << " "
10056 << c_globalId(cellId) << " " << a_isGapCell(cellId) << a_wasGapCell(cellId) << endl;
10057 if(sweptVol) {
10058 if(a_bndryId(cellId) > -1 && fabs(cellCheck(cellId, 11) - m_sweptVolume[a_bndryId(cellId)]) > eps0)
10059 cerr << domainId() << ": ERR11 generateBndryCellsMb " << globalTimeStep << " " << cellId << " "
10060 << c_globalId(cellId) << " " << cellCheck(cellId, 11) << " " << m_sweptVolume[a_bndryId(cellId)] << " "
10061 << a_bndryId(cellId) << " " << m_noOuterBndryCells << " "
10062 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " "
10063 << a_hasProperty(cellId, SolverCell::IsSplitChild) << " " << a_isGapCell(cellId) << " "
10064 << a_wasGapCell(cellId) << endl;
10065 if(a_bndryId(cellId) > -1 && fabs(cellCheck(cellId, 12) - m_sweptVolumeDt1[a_bndryId(cellId)]) > eps0)
10066 cerr << domainId() << ": ERR12 generateBndryCellsMb " << globalTimeStep << " " << cellId << " "
10067 << a_isGapCell(cellId) << " " << a_wasGapCell(cellId) << endl;
10068 }
10069 }
10070 }
10071 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
10072 const MInt cellId = m_splitCells[sc];
10073 if(a_isHalo(cellId)) {
10074 // Azimuthal periodic window/halo cells are not identical in the sense of the cartesian grid!
10075 if(grid().azimuthalPeriodicity() && a_isPeriodic(cellId)) continue;
10076 MFloat test0 = F1;
10077 MFloat test1 = a_cellVolume(cellId);
10078 MFloat test2 = m_cellVolumesDt1[cellId];
10079 MFloat test33 = m_sweptVolume[a_bndryId(cellId)];
10080 MFloat test4 = m_sweptVolumeDt1[a_bndryId(cellId)];
10081 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
10082 test0 += F1;
10083 test1 += a_cellVolume(m_splitChilds[sc][ssc]);
10084 test2 += m_cellVolumesDt1[m_splitChilds[sc][ssc]];
10085 test33 += m_sweptVolume[a_bndryId(m_splitChilds[sc][ssc])];
10086 test4 += m_sweptVolumeDt1[a_bndryId(m_splitChilds[sc][ssc])];
10087 }
10088 if((MInt)test0 != (MInt)cellCheck(cellId, 13))
10089 cerr << domainId() << ": ERR13 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10090 if(fabs(test1 - cellCheck(cellId, 9)) > eps0)
10091 cerr << domainId() << ": ERR14 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10092 if(fabs(test2 - cellCheck(cellId, 10)) > eps0)
10093 cerr << domainId() << ": ERR15 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10094 if(sweptVol) {
10095 if(fabs(test33 - cellCheck(cellId, 11)) > eps0)
10096 cerr << domainId() << ": ERR16 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10097 if(fabs(test4 - cellCheck(cellId, 12)) > eps0)
10098 cerr << domainId() << ": ERR17 generateBndryCellsMb " << globalTimeStep << " " << cellId << endl;
10099 }
10100 }
10101 }
10102}
10103
10104
10109template <MInt nDim, class SysEqn>
10111 TRACE();
10112
10113 MIntScratchSpace haloBufferCnts(mMax(1, noNeighborDomains()), AT_, "haloBufferCnts");
10114 MIntScratchSpace windowBufferCnts(mMax(1, noNeighborDomains()), AT_, "windowBufferCnts");
10115 MIntScratchSpace haloBufferOffsets(noNeighborDomains() + 1, AT_, "haloBufferOffsets");
10116 MIntScratchSpace windowBufferOffsets(noNeighborDomains() + 1, AT_, "windowBufferOffsets");
10117 ScratchSpace<MPI_Request> haloReq(mMax(1, noNeighborDomains()), AT_, "haloReq");
10118 ScratchSpace<MPI_Request> windowReq(mMax(1, noNeighborDomains()), AT_, "windowReq");
10119
10120 MInt haloSize = 0;
10121 MInt windowSize = 0;
10122 haloBufferCnts.fill(0);
10123 windowBufferCnts.fill(0);
10124 haloBufferOffsets.fill(0);
10125 windowBufferOffsets.fill(0);
10126
10127 for(MInt i = 0; i < noNeighborDomains(); i++) {
10128 haloBufferCnts(i) = (m_noCVars + m_noFVars + 3) * (signed)m_fvBndryCnd->m_nearBoundaryHaloCells[i].size();
10129 windowBufferCnts(i) = (m_noCVars + m_noFVars + 3) * (signed)m_fvBndryCnd->m_nearBoundaryWindowCells[i].size();
10130 haloBufferOffsets(i + 1) = haloBufferOffsets(i) + haloBufferCnts(i);
10131 windowBufferOffsets(i + 1) = windowBufferOffsets(i) + windowBufferCnts(i);
10132 haloSize += haloBufferCnts(i);
10133 windowSize += windowBufferCnts(i);
10134 }
10135
10136 MFloatScratchSpace redistVol(a_noCells(), AT_, "redistVol");
10137 MFloatScratchSpace redistSweptVol(a_noCells(), AT_, "redistSweptVol");
10138 MFloatScratchSpace haloBuffer(haloSize, AT_, "haloBuffer");
10139 MFloatScratchSpace windowBuffer(windowSize, AT_, "windowBuffer");
10140 MIntScratchSpace nghbrList(150, AT_, "nghbrList");
10141 MIntScratchSpace layerId(150, AT_, "layerList");
10142 MFloatScratchSpace weights(150, AT_, "layerList");
10143
10144 const MUint noCVars = (MUint)m_noCVars;
10145 const MUint noFVars = (MUint)m_noFVars;
10146 const MUint noPVars = (MUint)m_noPVars;
10147
10148 // redistribute lost mass
10149 // for ( MInt c = 0; c < m_noNearBndryCells; c++ ) {
10150 // MInt cellId = m_nearBndryCells->a[ c ];
10151 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
10152 const MInt cellId = m_bndryLayerCells[c];
10153 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
10154 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10155 for(MUint v = 0; v < noPVars; v++) {
10156 a_slope(cellId, v, 0) = F0;
10157 a_slope(cellId, v, 1) = F0;
10158 }
10159 redistVol(cellId) = F0;
10160 redistSweptVol(cellId) = F0;
10161 }
10162
10163 {
10164 for(MInt i = 0; i < noNeighborDomains(); i++) {
10165 for(MInt j = 0; j < (signed)m_fvBndryCnd->m_nearBoundaryHaloCells[i].size(); j++) {
10166 MInt cellId = m_fvBndryCnd->m_nearBoundaryHaloCells[i][j];
10167 for(MUint v = 0; v < noPVars; v++) {
10168 a_slope(cellId, v, 0) = F0;
10169 a_slope(cellId, v, 1) = F0;
10170 }
10171 redistVol(cellId) = F0;
10172 redistSweptVol(cellId) = F0;
10173 const MInt offset = haloBufferOffsets(i) + (noCVars + noFVars + 3) * j;
10174 haloBuffer(offset + 2) = -F1;
10175 }
10176 for(MInt j = 0; j < (signed)m_fvBndryCnd->m_nearBoundaryWindowCells[i].size(); j++) {
10177 MInt cellId = m_fvBndryCnd->m_nearBoundaryWindowCells[i][j];
10178 for(MUint v = 0; v < noPVars; v++) {
10179 a_slope(cellId, v, 0) = F0;
10180 a_slope(cellId, v, 1) = F0;
10181 }
10182 redistVol(cellId) = F0;
10183 redistSweptVol(cellId) = F0;
10184 }
10185 }
10186 }
10187
10188 for(MUint i = 0; i < m_massRedistributionIds.size(); ++i) {
10189 const MInt cellId = m_massRedistributionIds[i];
10190 ASSERT(!(a_isPeriodic(cellId)), "");
10191 ASSERT(!(a_isHalo(cellId)), "");
10192 if(a_isHalo(cellId)) continue;
10193
10194 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
10195 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
10196
10197 MInt counter = 0;
10198 MFloat volCnt = F0;
10199 for(MInt dir = 0; dir < m_noDirs; dir++) {
10200 if(!checkNeighborActive(cellId, dir) || a_hasNeighbor(cellId, dir) == 0) continue;
10201 const MInt nghbrId = c_neighborId(cellId, dir);
10202 if(nghbrId < 0) continue;
10203 if(!a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) continue;
10204 if(a_bndryId(nghbrId) < 0) continue;
10205 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
10206 // if ( a_hasProperty( nghbrId , SolverCell::WasInactive ) ) continue;
10207 // Do not redistribute into azimuthal periodic cells. This is not handled
10208 if(grid().azimuthalPeriodicity() && a_isPeriodic(nghbrId)) continue;
10209
10210 MInt bndryId = (a_bndryId(cellId) > -1) ? a_bndryId(cellId) : a_bndryId(nghbrId);
10211 if(bndryId < 0) mTerm(1, AT_, "not expected");
10212 // const MFloat nml = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_srfcs[0]->m_normalVector[dir/2];
10213 MFloat normal[3];
10214 for(MInt k = 0; k < nDim; k++) {
10215 normal[k] = m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVectorCentroid[k];
10216 }
10217 const MFloat nml = normal[dir / 2];
10218 const MFloat ncut = 0.01;
10219
10220 weights[counter] = mMax(F0, (POW2(nml) - ncut) / (F1 - ncut))
10221 * mMin(F1, mMax(F0, mMin(a_cellVolume(nghbrId), m_cellVolumesDt1[nghbrId]))
10222 / mMax(0.5 * m_volumeThreshold, fabs(m_massRedistributionVolume[i])));
10223
10224 volCnt += weights[counter];
10225 nghbrList[counter] = nghbrId;
10226 counter++;
10227 }
10228 for(MInt n = 0; n < counter; n++) {
10229 weights[n] /= mMax(1e-14, volCnt);
10230 }
10231
10232 if(true || volCnt < 0.1) {
10233 counter = this->template getAdjacentLeafCells<2, true>(cellId, 1, nghbrList, layerId);
10234 volCnt = F0;
10235 for(MInt n = 0; n < counter; n++) {
10236 weights[n] = F0;
10237 MInt nghbrId = nghbrList[n];
10238 if(nghbrId < 0) continue;
10239 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
10240 if(a_bndryId(nghbrId) < 0) continue;
10241 // Do not redistribute into azimuthal periodic cells. This is not handled
10242 if(grid().azimuthalPeriodicity() && a_isPeriodic(nghbrId)) continue;
10243
10244 if(a_hasProperty(nghbrId, SolverCell::IsSplitCell)) continue;
10245 if(a_hasProperty(nghbrId, SolverCell::IsSplitChild)) continue;
10246
10247 weights[n] = 1e-5
10248 + mMax(F0, (a_cellVolume(nghbrId) + m_cellVolumesDt1[nghbrId]))
10249 / (F2 * grid().gridCellVolume(a_level(cellId)));
10250
10251
10252 MInt bndryId = a_bndryId(nghbrId);
10253 if(bndryId < 0) mTerm(1, AT_, "not expected");
10254 weights[n] = grid().gridCellVolume(a_level(cellId))
10255 / mMax(1e-10, fabs(a_cellVolume(nghbrId) + m_massRedistributionVolume[i]
10256 + m_RKalpha[m_noRKSteps - 2] * m_massRedistributionSweptVol[i]
10257 - m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume));
10258
10259 volCnt += weights[n];
10260 }
10261 for(MInt n = 0; n < counter; n++) {
10262 weights[n] /= mMax(1e-14, volCnt);
10263 }
10264 }
10265
10266 for(MInt n = 0; n < counter; n++) {
10267 MInt nghbrId = nghbrList[n];
10268 if(nghbrId < 0) continue;
10269 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
10270 if(a_bndryId(nghbrId) < 0) continue;
10271
10272 if(a_hasProperty(nghbrId, SolverCell::IsSplitCell)) continue;
10273 if(a_hasProperty(nghbrId, SolverCell::IsSplitChild)) continue;
10274
10275 const MFloat fac = weights[n];
10276
10277 if(!a_hasProperty(nghbrId, SolverCell::NearWall)) {
10278 cerr << "[" << domainId() << "]: "
10279 << " nghbr " << nghbrId << " of cell " << cellId << " does not lie in bndryLayer! " << endl;
10280 cerr << " nghbr is a split cell: " << a_hasProperty(nghbrId, SolverCell::IsSplitCell)
10281 << " is split child: " << a_hasProperty(nghbrId, SolverCell::IsSplitChild) << endl;
10282 }
10283
10284 for(MUint v = 0; v < noPVars; v++) {
10285 a_slope(nghbrId, v, 0) += fac * m_massRedistributionVolume[i] * m_massRedistributionVariables[i * noPVars + v];
10286 a_slope(nghbrId, v, 1) += fac * m_massRedistributionRhs[i * noPVars + v];
10287 }
10288
10289 redistVol(nghbrId) += fac * m_massRedistributionVolume[i];
10290 redistSweptVol(nghbrId) += fac * m_massRedistributionSweptVol[i];
10291 }
10292 m_massRedistributionVolume[i] = F0;
10293 m_massRedistributionSweptVol[i] = F0;
10294 }
10295
10296 m_massRedistributionIds.clear();
10297 m_massRedistributionVolume.clear();
10298 m_massRedistributionSweptVol.clear();
10299 m_massRedistributionVariables.clear();
10300 m_massRedistributionRhs.clear();
10301
10302
10303 {
10304 // 1. send redistributed mass back to window cells
10305 haloReq.fill(MPI_REQUEST_NULL);
10306 windowReq.fill(MPI_REQUEST_NULL);
10307 for(MInt i = 0; i < noNeighborDomains(); i++) {
10308 if(m_fvBndryCnd->m_nearBoundaryHaloCells[i].empty()) continue;
10309 for(MInt j = 0; j < (signed)m_fvBndryCnd->m_nearBoundaryHaloCells[i].size(); j++) {
10310 MInt cellId = m_fvBndryCnd->m_nearBoundaryHaloCells[i][j];
10311 MInt offset = haloBufferOffsets(i) + (noPVars + noFVars + 3) * j;
10312 // ASSERT( a_hasProperty( cellId , SolverCell::NearWall ), "" );
10313 haloBuffer(offset) = redistVol(cellId);
10314 haloBuffer(offset + 1) = redistSweptVol(cellId);
10315 for(MInt v = 0; v < (signed)noPVars; v++) {
10316 haloBuffer(offset + 3 + v) = a_slope(cellId, v, 0);
10317 haloBuffer(offset + 3 + noPVars + v) = a_slope(cellId, v, 1);
10318 }
10319 }
10320 }
10321 MInt haloCnt = 0;
10322 MInt windowCnt = 0;
10323 if(m_nonBlockingComm) {
10324 for(MInt i = 0; i < noNeighborDomains(); i++) {
10325 if(windowBufferCnts(i) == 0) continue;
10326 MPI_Irecv(&windowBuffer[windowBufferOffsets[i]], windowBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 17,
10327 mpiComm(), &windowReq[windowCnt], AT_, "windowBuffer[windowBufferOffsets[i]]");
10328 windowCnt++;
10329 }
10330 for(MInt i = 0; i < noNeighborDomains(); i++) {
10331 if(haloBufferCnts(i) == 0) continue;
10332 MPI_Isend(&haloBuffer[haloBufferOffsets[i]], haloBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 17, mpiComm(),
10333 &haloReq[haloCnt], AT_, "haloBuffer[haloBufferOffsets[i]]");
10334 haloCnt++;
10335 }
10336 if(windowCnt > 0) MPI_Waitall(windowCnt, &windowReq[0], MPI_STATUSES_IGNORE, AT_);
10337 } else {
10338 for(MInt i = 0; i < noNeighborDomains(); i++) {
10339 if(haloBufferCnts(i) == 0) continue;
10340 MPI_Issend(&haloBuffer[haloBufferOffsets[i]], haloBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 17, mpiComm(),
10341 &haloReq[haloCnt], AT_, "haloBuffer[haloBufferOffsets[i]]");
10342 haloCnt++;
10343 }
10344 for(MInt i = 0; i < noNeighborDomains(); i++) {
10345 if(windowBufferCnts(i) == 0) continue;
10346 MPI_Recv(&windowBuffer[windowBufferOffsets[i]], windowBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 17,
10347 mpiComm(), MPI_STATUS_IGNORE, AT_, "windowBuffer[windowBufferOffsets[i]]");
10348 windowCnt++;
10349 }
10350 }
10351
10352 for(MInt i = 0; i < noNeighborDomains(); i++) {
10353 if(m_fvBndryCnd->m_nearBoundaryWindowCells[i].empty()) continue;
10354 for(MInt j = 0; j < (signed)m_fvBndryCnd->m_nearBoundaryWindowCells[i].size(); j++) {
10355 MInt cellId = m_fvBndryCnd->m_nearBoundaryWindowCells[i][j];
10356 MInt offset = windowBufferOffsets(i) + (noCVars + noFVars + 3) * j;
10357 // ASSERT( a_hasProperty( cellId , SolverCell::NearWall ), "" );
10358 redistVol(cellId) += windowBuffer(offset);
10359 redistSweptVol(cellId) += windowBuffer(offset + 1);
10360
10361 for(MInt v = 0; v < (signed)noPVars; v++) {
10362 a_slope(cellId, v, 0) += windowBuffer(offset + 3 + v);
10363 a_slope(cellId, v, 1) += windowBuffer(offset + 3 + noPVars + v);
10364 }
10365 }
10366 }
10367 if(haloCnt > 0) MPI_Waitall(haloCnt, &haloReq[0], MPI_STATUSES_IGNORE, AT_);
10368 }
10369
10370 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
10371 MInt cellId = m_bndryLayerCells[c];
10372 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
10373 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10374 if(a_isPeriodic(cellId)) continue;
10375 if(a_isHalo(cellId)) continue;
10376 if(fabs(redistVol(cellId)) < 1e-12) continue;
10377
10378 MFloat vol = m_cellVolumesDt1[cellId] + redistVol(cellId);
10379 if(fabs(vol) > 1e-14) {
10380 for(MUint v = 0; v < noCVars; v++) {
10381 a_oldVariable(cellId, v) = (a_oldVariable(cellId, v) * m_cellVolumesDt1[cellId] + a_slope(cellId, v, 0))
10382 / (m_cellVolumesDt1[cellId] + redistVol(cellId));
10383 m_rhs0[cellId][v] += a_slope(cellId, v, 1);
10384 }
10385 }
10386 m_cellVolumesDt1[cellId] = vol;
10387#ifdef GEOM_CONS_LAW
10388 if(a_bndryId(cellId) > -1) {
10389 a_cellVolume(cellId) += redistVol(cellId);
10390 m_sweptVolumeDt1[a_bndryId(cellId)] += redistSweptVol(cellId);
10391 if(m_gclIntermediate) {
10392 if(m_levelSetMb) a_cellVolume(cellId) += redistSweptVol(cellId);
10393 } else {
10394 if(m_levelSetMb) a_cellVolume(cellId) += F1B2 * redistSweptVol(cellId);
10395 }
10396 a_cellVolume(cellId) = mMax(m_volumeThreshold, a_cellVolume(cellId));
10397 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
10398 m_volumeFraction[a_bndryId(cellId)] = a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId));
10399 } else {
10400 cerr << "not supposed to happen at redist" << endl;
10401 }
10402#endif
10403 }
10404
10405
10406#ifdef GEOM_CONS_LAW
10407 MBool& firstRun = m_static_redistributeMass_firstRun;
10408
10409 MBool conserveMass = true;
10410 if(m_gapInitMethod == 0 && m_gapOpened) {
10411 conserveMass = false;
10412 } else if(m_gapInitMethod > 0) {
10413 conserveMass = true;
10414 }
10415
10416 if(!firstRun && conserveMass) {
10417 if(m_gclIntermediate) {
10418 // init with the minium volume to increase stability of small cell treatment
10419 const MInt noBCells = m_fvBndryCnd->m_bndryCells->size();
10420 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
10421 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
10422 MFloat dV0 = m_sweptVolumeDt1[bndryId];
10423 MFloat dV1 = m_sweptVolume[bndryId];
10424 MFloat vol = m_cellVolumesDt1[cellId] + dV0;
10425 for(MInt r = 1; r < m_noRKSteps; r++) {
10426 const MFloat deltaVol = m_RKalpha[r - 1] * dV1 + (F1 - m_RKalpha[r - 1]) * dV0;
10427 vol = mMin(m_cellVolumesDt1[cellId] + deltaVol, vol);
10428 }
10429 vol = mMax(F0, vol);
10430 a_cellVolume(cellId) = vol;
10431 a_cellVolume(cellId) = mMax(a_cellVolume(cellId), m_volumeThreshold);
10432 m_volumeFraction[bndryId] = a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId));
10433 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
10434 }
10435 } else {
10436 const MInt noBCells = m_fvBndryCnd->m_bndryCells->size();
10437 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
10438 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
10439 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10440 MFloat dV0 = m_sweptVolumeDt1[bndryId];
10441 MFloat dV1 = m_sweptVolume[bndryId];
10442 a_cellVolume(cellId) =
10443 m_cellVolumesDt1[cellId] + m_RKalpha[m_noRKSteps - 2] * dV1 + (F1 - m_RKalpha[m_noRKSteps - 2]) * dV0;
10444 a_cellVolume(cellId) = mMax(a_cellVolume(cellId), m_volumeThreshold);
10445 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
10446 }
10447 }
10448 }
10449 firstRun = false;
10450#endif
10451
10452
10453 // truncate cell volumes for large deviations due to GCL
10454 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
10455 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
10456 const MFloat V0 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume - 0.1 * grid().gridCellVolume(a_level(cellId));
10457 const MFloat V1 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume + 0.1 * grid().gridCellVolume(a_level(cellId));
10458 a_cellVolume(cellId) = mMin(V1, mMax(V0, a_cellVolume(cellId)));
10459 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
10460 }
10461
10462 {
10463 // 2. synchronize cell volumes
10464 haloReq.fill(MPI_REQUEST_NULL);
10465 windowReq.fill(MPI_REQUEST_NULL);
10466 for(MInt i = 0; i < noNeighborDomains(); i++) {
10467 if(m_fvBndryCnd->m_nearBoundaryWindowCells[i].empty()) continue;
10468 for(MInt j = 0; j < (signed)m_fvBndryCnd->m_nearBoundaryWindowCells[i].size(); j++) {
10469 MInt cellId = m_fvBndryCnd->m_nearBoundaryWindowCells[i][j];
10470 MInt offset = windowBufferOffsets(i) + (noCVars + noFVars + 3) * j;
10471 windowBuffer(offset) = a_cellVolume(cellId);
10472 windowBuffer(offset + 1) = m_cellVolumesDt1[cellId];
10473 windowBuffer(offset + 2) = (a_bndryId(cellId) > -1) ? m_sweptVolumeDt1[a_bndryId(cellId)] : F0;
10474 for(MInt v = 0; v < (signed)noCVars; v++) {
10475 windowBuffer(offset + 3 + v) = a_oldVariable(cellId, v);
10476 }
10477 for(MInt v = 0; v < (signed)noFVars; v++) {
10478 windowBuffer(offset + 3 + noCVars + v) = m_rhs0[cellId][v];
10479 }
10480 }
10481 }
10482 MInt windowCnt = 0;
10483 MInt haloCnt = 0;
10484 if(m_nonBlockingComm) {
10485 for(MInt i = 0; i < noNeighborDomains(); i++) {
10486 if(haloBufferCnts(i) == 0) continue;
10487 MPI_Irecv(&haloBuffer[haloBufferOffsets[i]], haloBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 18, mpiComm(),
10488 &haloReq[haloCnt], AT_, "haloBuffer[haloBufferOffsets[i]]");
10489 haloCnt++;
10490 }
10491 for(MInt i = 0; i < noNeighborDomains(); i++) {
10492 if(windowBufferCnts(i) == 0) continue;
10493 MPI_Isend(&windowBuffer[windowBufferOffsets[i]], windowBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 18,
10494 mpiComm(), &windowReq[windowCnt], AT_, "windowBuffer[windowBufferOffsets[i]]");
10495 windowCnt++;
10496 }
10497 if(haloCnt > 0) MPI_Waitall(haloCnt, &haloReq[0], MPI_STATUSES_IGNORE, AT_);
10498 } else {
10499 for(MInt i = 0; i < noNeighborDomains(); i++) {
10500 if(windowBufferCnts(i) == 0) continue;
10501 MPI_Issend(&windowBuffer[windowBufferOffsets[i]], windowBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 18,
10502 mpiComm(), &windowReq[windowCnt], AT_, "windowBuffer[windowBufferOffsets[i]]");
10503 windowCnt++;
10504 }
10505 for(MInt i = 0; i < noNeighborDomains(); i++) {
10506 if(haloBufferCnts(i) == 0) continue;
10507 MPI_Recv(&haloBuffer[haloBufferOffsets[i]], haloBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 18, mpiComm(),
10508 MPI_STATUS_IGNORE, AT_, "haloBuffer[haloBufferOffsets[i]]");
10509 haloCnt++;
10510 }
10511 }
10512 for(MInt i = 0; i < noNeighborDomains(); i++) {
10513 if(m_fvBndryCnd->m_nearBoundaryHaloCells[i].empty()) continue;
10514 for(MInt j = 0; j < (signed)m_fvBndryCnd->m_nearBoundaryHaloCells[i].size(); j++) {
10515 MInt cellId = m_fvBndryCnd->m_nearBoundaryHaloCells[i][j];
10516 MInt offset = haloBufferOffsets(i) + (noCVars + noFVars + 3) * j;
10517 a_cellVolume(cellId) = haloBuffer(offset);
10518 m_cellVolumesDt1[cellId] = haloBuffer(offset + 1);
10519 for(MInt v = 0; v < (signed)noCVars; v++) {
10520 a_oldVariable(cellId, v) = haloBuffer(offset + 3 + v);
10521 }
10522 for(MInt v = 0; v < (signed)noFVars; v++) {
10523 m_rhs0[cellId][v] = haloBuffer(offset + 3 + noCVars + v);
10524 }
10525 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
10526 if(a_bndryId(cellId) > -1) {
10527 m_volumeFraction[a_bndryId(cellId)] = a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId));
10528 m_sweptVolumeDt1[a_bndryId(cellId)] = haloBuffer(offset + 2);
10529 }
10530 }
10531 }
10532 if(windowCnt > 0) MPI_Waitall(windowCnt, &windowReq[0], MPI_STATUSES_IGNORE, AT_);
10533 }
10534
10535#ifndef GEOM_CONS_LAW
10536 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
10537 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
10538 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
10539 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
10540 m_volumeFraction[a_bndryId(cellId)] = a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId));
10541 }
10542#endif
10543
10544
10545//#define LOG_DELTA_VOL
10546#ifdef LOG_DELTA_VOL
10547 MFloat maxdv = -99999.0;
10548 MFloat mindv = 99999.0;
10549 MFloat avgdv = F0;
10550 MFloat cnt = F0;
10551 MInt maxId = 0;
10552 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
10553 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
10554 if(a_isHalo(cellId)) continue;
10555 MFloat dv = (a_cellVolume(cellId) - m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume)
10556 / grid().gridCellVolume(a_level(cellId));
10557 if(dv > maxdv) maxId = cellId;
10558 maxdv = mMax(maxdv, dv);
10559 mindv = mMin(mindv, dv);
10560 avgdv += fabs(dv);
10561 cnt += F1;
10562 }
10563 MPI_Allreduce(MPI_IN_PLACE, &maxdv, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "maxdv");
10564 MPI_Allreduce(MPI_IN_PLACE, &mindv, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "mindv");
10565 MPI_Allreduce(MPI_IN_PLACE, &avgdv, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "avgdv");
10566 MPI_Allreduce(MPI_IN_PLACE, &cnt, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cnt");
10567 avgdv /= cnt;
10568 if(domainId() == 0) {
10569 cerr << "dv: " << globalTimeStep << " " << avgdv << " " << maxdv << " " << mindv << " -- "
10570 << a_cellVolume(maxId) / grid().gridCellVolume(a_level(maxId)) << " "
10571 << m_fvBndryCnd->m_bndryCells->a[a_bndryId(maxId)].m_volume / grid().gridCellVolume(a_level(maxId)) << " ("
10572 << m_cellVolumesDt1[maxId] / grid().gridCellVolume(a_level(maxId)) << " "
10573 << m_sweptVolume[a_bndryId(maxId)] / grid().gridCellVolume(a_level(maxId)) << " "
10574 << m_sweptVolumeDt1[a_bndryId(maxId)] / grid().gridCellVolume(a_level(maxId)) << " " << maxId << ")" << endl;
10575 ofstream ofl;
10576 ofl.open("vol_err", ios_base::out | ios_base::app);
10577 if(ofl.is_open() && ofl.good()) {
10578 ofl << setprecision(12) << globalTimeStep << " " << avgdv << " " << maxdv << " " << mindv << " "
10579 << a_cellVolume(maxId) / grid().gridCellVolume(a_level(maxId)) << " "
10580 << m_fvBndryCnd->m_bndryCells->a[a_bndryId(maxId)].m_volume / grid().gridCellVolume(a_level(maxId)) << " "
10581 << m_cellVolumesDt1[maxId] / grid().gridCellVolume(a_level(maxId)) << " "
10582 << m_sweptVolume[a_bndryId(maxId)] / grid().gridCellVolume(a_level(maxId)) << " "
10583 << m_sweptVolumeDt1[a_bndryId(maxId)] / grid().gridCellVolume(a_level(maxId)) << " " << maxId << endl;
10584 ofl.close();
10585 }
10586 }
10587#endif
10588
10589 // for ( MInt c = 0; c < m_noNearBndryCells; c++ ) {
10590 // setPrimitiveVariables(m_nearBndryCells->a[c]);
10591 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
10592 const MInt cellId = m_bndryLayerCells[c];
10593 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
10594 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10595 setPrimitiveVariables(cellId);
10596 }
10597
10598
10599#if defined _MB_DEBUG_ || !defined NDEBUG
10600 m_solutionDiverged = false;
10601 MInt cnt = 0;
10602 for(MInt i = a_noCells(); i--;) {
10603 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
10604 if(!a_hasProperty(i, SolverCell::IsOnCurrentMGLevel)) continue;
10605 if(a_isHalo(i)) continue;
10606 if(a_isBndryGhostCell(i)) continue;
10607 if(a_hasProperty(i, SolverCell::IsInactive)) continue;
10608 for(MInt v = 0; v < m_noCVars; v++) {
10609 if(!(a_variable(i, v) >= F0 || a_variable(i, v) < F0) || std::isnan(a_variable(i, v))) {
10610 if(cnt < 10)
10611 cerr << setprecision(12) << domainId() << ": MRED " << i << " " << a_bndryId(i) << " " << v << " "
10612 << a_variable(i, v) << " "
10613 << "cells[i].b_properties.to_string()"
10614 << " " << c_noChildren(i) << " " << a_hasProperty(i, SolverCell::IsInactive) << " "
10615 << a_hasProperty(i, SolverCell::IsSplitCell) << " " << a_hasProperty(i, SolverCell::IsSplitChild) << " "
10616 << a_cellVolume(i) / grid().gridCellVolume(a_level(i)) << " "
10617 << m_cellVolumesDt1[i] / grid().gridCellVolume(a_level(i));
10618 if(i < c_noCells()) cerr << " " << c_globalId(i) << endl;
10619 m_solutionDiverged = true;
10620 cnt++;
10621 }
10622 }
10623 MFloat pres = F0;
10624 IF_CONSTEXPR(nDim == 2) {
10625 pres =
10626 sysEqn().pressure(1.0, a_pvariable(i, PV->RHO) * (POW2(a_pvariable(i, PV->U)) + POW2(a_pvariable(i, PV->V))),
10627 a_variable(i, CV->RHO_E));
10628 }
10629 else IF_CONSTEXPR(nDim == 3) {
10630 pres = sysEqn().pressure(
10631 1.0,
10632 a_pvariable(i, PV->RHO)
10633 * (POW2(a_pvariable(i, PV->U)) + POW2(a_pvariable(i, PV->V)) + POW2(a_pvariable(i, PV->W))),
10634 a_variable(i, CV->RHO_E));
10635 }
10636 if(a_cellVolume(i) / grid().gridCellVolume(a_level(i)) > m_fvBndryCnd->m_volumeLimitWall) {
10637 if(a_variable(i, CV->RHO) < F0 || pres < F0) {
10638 if(cnt < 10)
10639 cerr << domainId() << ": MRED " << i << " " << a_bndryId(i) << " " << a_level(i) << " /r "
10640 << a_variable(i, CV->RHO) << " /p " << pres << " /v "
10641 << a_cellVolume(i) / grid().gridCellVolume(a_level(i)) << " "
10642 << m_cellVolumesDt1[i] / grid().gridCellVolume(a_level(i)) << " "
10643 << "cells[i].b_properties.to_string()"
10644 << " " << a_hasProperty(i, SolverCell::IsSplitCell) << " " << a_hasProperty(i, SolverCell::IsSplitChild)
10645 << " " << a_isPeriodic(i) << " " << a_coordinate(i, 0) << " " << a_coordinate(i, 1) << " "
10646 << a_coordinate(i, mMin((MInt)FD, 2));
10647 if(i < c_noCells()) cerr << " " << c_globalId(i) << endl;
10648 m_solutionDiverged = true;
10649 cnt++;
10650 }
10651 }
10652 }
10653 if(m_solutionDiverged) {
10654 cerr << "Solution diverged after mass redistribution at solver " << domainId() << " " << globalTimeStep << " "
10655 << m_RKStep << endl;
10656 }
10657 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
10658 "m_solutionDiverged");
10659 if(m_solutionDiverged) {
10660 writeVtkXmlFiles("QOUT", "GEOM", false, true);
10661 MPI_Barrier(mpiComm(), AT_);
10662 mTerm(1, AT_, "Solution diverged after mass redistribution.");
10663 }
10664#endif
10665}
10666
10667
10672template <MInt nDim, class SysEqn>
10674 for(MUint it = 0; it < m_temporarilyLinkedCells.size(); it++) {
10675 activeFlag(get<0>(m_temporarilyLinkedCells[it])) = 1;
10676 activeFlag(get<1>(m_temporarilyLinkedCells[it])) = 1;
10677 if(get<2>(m_temporarilyLinkedCells[it]) > 0) {
10678 activeFlag(get<2>(m_temporarilyLinkedCells[it])) = 1;
10679 }
10680 }
10681}
10682
10683
10688template <MInt nDim, class SysEqn>
10690 TRACE();
10691
10692 MInt errorId = 0;
10693 MInt globalErrorId = 0;
10694
10695
10696 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
10697 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
10698
10699 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10700 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
10701 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
10702 errorId = 0;
10703
10704 const MFloat faceArea = (nDim == 3) ? POW2(sqrt(F3) * c_cellLengthAtLevel(a_cutCellLevel(cellId)))
10705 : sqrt(F2) * c_cellLengthAtLevel(a_cutCellLevel(cellId));
10706 const MFloat faceArea0 =
10707 (nDim == 3) ? POW2(c_cellLengthAtLevel(a_cutCellLevel(cellId))) : c_cellLengthAtLevel(a_cutCellLevel(cellId));
10708
10709 ASSERT(m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs > 0, "");
10710
10711 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume < F0)
10712 errorId = 1;
10713 else if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume > (grid().gridCellVolume(a_level(cellId)) + m_eps))
10714 errorId = 1;
10715 else if(std::isnan(m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume))
10716 errorId = 1;
10717 if(errorId == 1) m_log << "BC: " << bndryId << " " << cellId << " " << errorId << endl;
10718
10719 if(m_volumeFraction[bndryId] < F0)
10720 errorId = 2;
10721 else if(m_volumeFraction[bndryId] > (F1 + m_eps))
10722 errorId = 2;
10723 else if(std::isnan(m_volumeFraction[bndryId]))
10724 errorId = 2;
10725 if(errorId == 2) {
10726 m_log << "BC: " << bndryId << " " << cellId << " " << errorId << " " << m_volumeFraction[bndryId] << endl;
10727 // if ( !a_isHalo(cellId) ) cerr << domainId() << ": BC " << bndryId << " " << cellId << " " << errorId << " " <<
10728 // m_volumeFraction[ bndryId ]
10729 // << " " << a_cellVolume(cellId) << " " << m_cellVolumesDt1[cellId]
10730 // << " " << c_globalId(cellId) << endl;
10731 }
10732
10733 for(MInt i = 0; i < nDim; i++)
10734 if(std::isnan(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i])) errorId = 3;
10735 if(errorId == 3) {
10736 m_log << "BC: " << bndryId << " " << cellId << " " << errorId << endl;
10737 }
10738
10739 for(MInt i = 0; i < nDim; i++)
10740 if(fabs(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i]) > (F1 + m_eps)) errorId = 4;
10741 if(errorId == 4) {
10742 IF_CONSTEXPR(nDim == 2) {
10743 m_log << "BC: " << bndryId << " " << cellId << " " << errorId << " "
10744 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0] << " "
10745 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[1] << " " << scientific
10746 << setprecision(16) << m_volumeFraction[bndryId] << endl;
10747 }
10748 else IF_CONSTEXPR(nDim == 3) {
10749 m_log << "BC: " << bndryId << " " << cellId << " " << errorId << " "
10750 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0] << " "
10751 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[1] << " "
10752 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[2] << " " << scientific
10753 << setprecision(16) << m_volumeFraction[bndryId] << endl;
10754 }
10755 }
10756
10757 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_area < F0)
10758 errorId = 5;
10759 else if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_area > (faceArea + m_eps))
10760 errorId = 5;
10761 else if(std::isnan(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_area))
10762 errorId = 5;
10763 if(errorId == 5) m_log << "BC: " << bndryId << " " << cellId << " " << errorId << endl;
10764
10765 if(a_hasProperty(cellId, SolverCell::IsInactive))
10766 errorId = 6;
10767 else if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel))
10768 errorId = 6;
10769 if(errorId == 6) m_log << "BC: " << bndryId << " " << cellId << " " << errorId << endl;
10770
10771 for(MInt i = 0; i < nDim; i++)
10772 if(fabs(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i] - a_coordinate(cellId, i))
10773 > (F1B2 * c_cellLengthAtLevel(a_cutCellLevel(cellId)) + m_eps))
10774 errorId = 7;
10775 for(MInt i = 0; i < nDim; i++)
10776 if(std::isnan(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i])) errorId = 7;
10777 if(errorId == 7) {
10778 // cerr << "error7 " << domainId() << " " << globalTimeStep << " " << cellId << " "
10779 // << m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_noSrfcs << " "
10780 // << fabs( m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_srfcs[0]->m_coordinates[ 0 ] - a_coordinate(cellId, 0)
10781 // ) - ( F1B2 * c_cellLengthAtLevel( a_cutCellLevel(cellId) ) ) << " "
10782 // << fabs( m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_srfcs[0]->m_coordinates[ 1 ] - a_coordinate(cellId, 1)
10783 // ) - ( F1B2 * c_cellLengthAtLevel( a_cutCellLevel(cellId) ) )
10784 // << endl;
10785 // errorId = -1;
10786 m_log << "BC: " << bndryId << " " << cellId << " " << errorId << endl;
10787 }
10788
10789 MFloat ar = -F1;
10790 for(MInt dir = 0; dir < m_noDirs; dir++) {
10791 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
10792 if(srfcId > -1) {
10793 if(a_surfaceArea(srfcId) < F0)
10794 errorId = 8;
10795 else if(a_surfaceArea(srfcId) > (faceArea0 + 100 * m_eps))
10796 errorId = 8;
10797 else if(std::isnan(a_surfaceArea(srfcId)))
10798 errorId = 8;
10799 for(MInt i = 0; i < nDim; i++) {
10800 if(fabs(a_surfaceCoordinate(srfcId, i) - a_coordinate(cellId, i))
10801 > (F1B2 * c_cellLengthAtLevel(a_level(cellId)) + 100 * m_eps))
10802 errorId = 8;
10803 if(std::isnan(a_surfaceCoordinate(srfcId, i))) errorId = 8;
10804 }
10805 if(errorId == 8) m_log << a_surfaceCoordinate(srfcId, 0) << " " << a_surfaceCoordinate(srfcId, 1) << endl;
10806 if(errorId == 8) m_log << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << endl;
10807 ar = a_surfaceArea(srfcId);
10808 }
10809 }
10810 if(errorId == 8) {
10811 m_log << "BC: " << bndryId << " " << cellId << " " << errorId << " " << ar << " " << ar - faceArea0 << endl;
10812 for(MInt i = 0; i < nDim; i++)
10813 m_log << a_coordinate(cellId, i) << " ";
10814 m_log << endl;
10815 MInt cndId = m_bndryCandidateIds[cellId];
10816 if(cndId > -1) {
10817 for(MInt node = 0; node < m_noCellNodes; node++) {
10818 m_log << node << " ";
10819 if(m_candidateNodeSet[cndId * m_noCellNodes + node])
10820 m_log << m_candidateNodeValues[IDX_LSSETNODES(cndId, node, 0)] << ", ";
10821 else
10822 m_log << " -1, ";
10823 }
10824 m_log << endl;
10825 }
10826 for(MInt dir = 0; dir < m_noDirs; dir++) {
10827 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
10828 if(srfcId > -1) {
10829 m_log << setprecision(12) << dir << " " << srfcId << ": " << a_surfaceArea(srfcId) / faceArea0 << " ";
10830 for(MInt i = 0; i < nDim; i++)
10831 m_log << F1B2 * c_cellLengthAtLevel(a_level(cellId))
10832 - fabs(a_surfaceCoordinate(srfcId, i) - a_coordinate(cellId, i))
10833 << " ";
10834 m_log << endl;
10835 }
10836 }
10837 }
10838
10839 for(MInt i = 0; i < nDim; i++) {
10840 if(fabs(m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[i])
10841 > (F1B2 * c_cellLengthAtLevel(a_cutCellLevel(cellId)) + m_eps)) {
10842 m_log << "check BC: " << bndryId << " " << errorId << " " << setprecision(16) << m_volumeFraction[bndryId]
10843 << setprecision(8) << " "
10844 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[i] / c_cellLengthAtLevel(a_cutCellLevel(cellId))
10845 << " " << F1B2 * c_cellLengthAtLevel(a_cutCellLevel(cellId)) << endl;
10846 errorId = 9 + i;
10847 }
10848 if(std::isnan(m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[i])) {
10849 m_log << "check BC: " << bndryId << " " << errorId << " " << setprecision(16) << m_volumeFraction[bndryId]
10850 << setprecision(8) << " "
10851 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[i] / c_cellLengthAtLevel(a_cutCellLevel(cellId))
10852 << " " << F1B2 * c_cellLengthAtLevel(a_cutCellLevel(cellId)) << endl;
10853 errorId = 9 + i;
10854 }
10855 }
10856 globalErrorId = mMax(globalErrorId, errorId);
10857 }
10858
10859 if(globalErrorId > 0) {
10860 m_log << "Warning " << globalErrorId << " in FvMbCartesianSolverXD::checkBoundaryCells at timestep "
10861 << globalTimeStep << endl;
10862 cerr << "Warning " << globalErrorId << " in FvMbCartesianSolverXD::checkBoundaryCells at timestep "
10863 << globalTimeStep << endl;
10864 stringstream GName;
10865 GName.str("");
10866 GName << m_solutionOutput;
10867 GName << "solver_data/GEOM";
10868 GName << "_B" << domainId();
10869 GName << "_00" << globalTimeStep;
10870 GName << "_warning";
10871 GName << ".vtp";
10872 // writeGeometryToVtkXmlFile( GName.str() );
10873 }
10874}
10875
10876
10877template <MInt nDim, class SysEqn>
10879 TRACE();
10880
10881 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
10882
10883 MFloat dV = F0;
10884 if(m_dualTimeStepping) {
10885 mTerm(1, AT_, "TODO DTS");
10886 a_cellVolume(cellId) = F4B3 * m_cellVolumesDt1[cellId] - F1B3 * m_cellVolumesDt2[cellId];
10887 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
10888 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
10889 for(MInt i = 0; i < nDim; i++) {
10890 MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
10891 dV -= F2B3 * m_physicalTimeStep
10892 * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] * nml * area;
10893 }
10894 }
10895 } else {
10896 MFloat dt = timeStep(true);
10897 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
10898 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
10899 for(MInt i = 0; i < nDim; i++) {
10900 MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
10901 dV -= dt * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] * nml * area;
10902 }
10903 }
10904 }
10905
10906
10907 m_sweptVolume[bndryId] = dV;
10908
10909 MFloat deltaVol = dV;
10910 if(m_gclIntermediate) {
10911 if(m_levelSetMb) {
10912 // deltaVol = ( m_RKStep == 0 ) ? m_sweptVolumeDt1[ bndryId ] : m_RKalpha[ m_RKStep-1 ] * m_sweptVolume[ bndryId ]
10913 // + (F1-m_RKalpha[ m_RKStep-1 ]) * m_sweptVolumeDt1[ bndryId ] ;
10914 deltaVol = m_RKalpha[m_noRKSteps - 2] * m_sweptVolume[bndryId]
10915 + (F1 - m_RKalpha[m_noRKSteps - 2]) * m_sweptVolumeDt1[bndryId];
10916 }
10917 } else {
10918 // deltaVol = ( m_levelSetMb ) ? F1B2 * ( m_sweptVolume[ bndryId ] + m_sweptVolumeDt1[ bndryId ] ) : dV;
10919 deltaVol = (m_levelSetMb) ? m_RKalpha[m_noRKSteps - 2] * m_sweptVolume[bndryId]
10920 + (F1 - m_RKalpha[m_noRKSteps - 2]) * m_sweptVolumeDt1[bndryId]
10921 : dV;
10922 }
10923 a_cellVolume(cellId) = m_cellVolumesDt1[cellId] + deltaVol;
10924
10925 const MFloat V0 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume - 0.1 * grid().gridCellVolume(a_level(cellId));
10926 const MFloat V1 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume + 0.1 * grid().gridCellVolume(a_level(cellId));
10927 a_cellVolume(cellId) = mMin(V1, mMax(V0, a_cellVolume(cellId)));
10928
10929 a_cellVolume(cellId) = mMax(a_cellVolume(cellId), m_volumeThreshold);
10930 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
10931
10932 /*
10933 if ( a_hasProperty( cellId , SolverCell::IsSplitCell ) || a_hasProperty( cellId , SolverCell::IsSplitChild ) ) {
10934 a_cellVolume( cellId ) = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_volume;
10935 m_cellVolumesDt1[ cellId ] = a_cellVolume( cellId ) - deltaVol;
10936 }*/
10937 if(m_levelSet && m_closeGaps) {
10938 if(a_wasGapCell(cellId) || a_isGapCell(cellId)) {
10939 // TODO-Timw labels:FVMB set volume of new-Gap-Bndry-Cells!
10940 // only change during initGapOpen
10941 if(m_gapInitMethod > 0) {
10942 MInt regionId = m_gapCells[m_gapCellId[cellId]].region;
10943 ASSERT(regionId > -1, "Negative region in Cell" << to_string(c_globalId(cellId)) << " " << m_gapCellId[cellId]);
10944
10945 // labels:FVMB G0-hack
10946 if(regionId == m_noGapRegions) {
10947 // ASSERT(a_wasGapCell(cellId) == a_isGapCell(cellId ), "");
10948 // zero-volume change in G0-region cells:
10949 a_cellVolume(cellId) = m_cellVolumesDt1[cellId];
10950 m_sweptVolume[bndryId] = 0;
10951 m_sweptVolumeDt1[bndryId] = 0;
10952
10953 } else {
10954 if(m_gapState[regionId] == -2 || m_gapState[regionId] == 3 || m_gapState[regionId] == -1) {
10955 // for gap-Closure, gap-Widening and gap-Shrinking, static initialisation!
10956 // handeled in updateGapBoundaryCells, just some checks here
10957 // for gapCells, not for old gapCells, which are handeled regularly!
10958 if(a_isGapCell(cellId)) {
10959 if(fabs(a_cellVolume(cellId) - m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume)
10960 > m_volumeThreshold * 10) {
10961 // if(a_cellVolume( cellId ) > m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_volume ||
10962 // a_cellVolume( cellId ) < m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_volume) {
10963
10964 // if(a_cellVolume( cellId ) > m_volumeThreshold * 10) {
10965 /*
10966 cerr << "Incorrect Volume-Initialisation " << a_cellVolume(cellId) << " "
10967 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume << " "
10968 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " "
10969 << a_hasProperty(cellId, SolverCell::IsSplitChild) << " " << a_isHalo(cellId) << " "
10970 << m_gapCells[m_gapCellId[cellId]].status << endl;
10971 */
10972 //}
10973 }
10974
10975 if(m_sweptVolume[bndryId] > 0 || m_sweptVolume[bndryId] < 0 || m_sweptVolumeDt1[bndryId] < 0
10976 || m_sweptVolumeDt1[bndryId] < 0) {
10977 cerr << " Incorrect swetVolume-Innitialisation " << m_sweptVolume[bndryId] << m_sweptVolumeDt1[bndryId]
10978 << endl;
10979 }
10980 }
10981
10982 } else if(m_gapState[regionId] == 2) {
10983 ASSERT(a_wasGapCell(cellId) && !a_isGapCell(cellId), "");
10984 MInt status = m_gapCells[m_gapCellId[cellId]].status;
10985 // status 27: former internal, now bndry-Cell -> handeled regularly
10986
10987 if(status != 27) {
10988 if(status != 22 && status != 24 && status != 28 && status != 29 && status != 99 && status != 98) {
10989 cerr << "UnExpected Status for Volume (1) " << c_globalId(cellId) << " " << status << endl;
10990 }
10991
10992 // for gap-Opening, just as a restart!
10993 // THIS IS NOT FULLY WORKING YET!!!!
10994
10995 if(deltaVol > m_sweptVolumeDt1[bndryId] || deltaVol < m_sweptVolumeDt1[bndryId]) {
10996 if(m_gapCells[m_gapCellId[cellId]].status != 98)
10997 cerr << "Incorrect Initialisation " << c_globalId(cellId) << " "
10998 << m_gapCells[m_gapCellId[cellId]].status << endl;
10999 }
11000
11001 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
11002
11003 if(deltaVol > a_cellVolume(cellId)) {
11004 deltaVol = a_cellVolume(cellId);
11005 m_sweptVolume[bndryId] = deltaVol;
11006 }
11007 m_cellVolumesDt1[cellId] = a_cellVolume(cellId) - deltaVol;
11008 m_sweptVolumeDt1[bndryId] = m_sweptVolume[bndryId];
11009 }
11010 }
11011 // some additional and more generalised checks:
11012
11013 if(a_cellVolume(cellId) < 0 || m_cellVolumesDt1[cellId] < 0) {
11014 cerr << "Negative Cell-Volume : " << c_globalId(cellId) << " " << a_cellVolume(cellId) << " "
11015 << m_cellVolumesDt1[cellId] << " " << deltaVol << " " << dV << " " << m_sweptVolume[bndryId]
11016 << " status " << m_gapCells[m_gapCellId[cellId]].status << endl;
11017 }
11018
11019 if(a_cellVolume(cellId) > 1.03 * grid().gridCellVolume(a_level(cellId))) {
11020 cerr << "Volume exeeds Limit " << c_globalId(cellId) << " "
11021 << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " "
11022 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << " status "
11023 << m_gapCells[m_gapCellId[cellId]].status << endl;
11024 }
11025
11026 if(m_cellVolumesDt1[cellId] > 1.03 * grid().gridCellVolume(a_level(cellId))) {
11027 cerr << "Dt-Volume exeeds Limit " << c_globalId(cellId) << " "
11028 << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " "
11029 << m_cellVolumesDt1[cellId] / grid().gridCellVolume(a_level(cellId)) << " " << deltaVol << " "
11030 << m_gapCells[m_gapCellId[cellId]].status << endl;
11031 }
11032 }
11033
11034 } else {
11035 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
11036 m_cellVolumesDt1[cellId] = a_cellVolume(cellId) - deltaVol;
11037 }
11038 }
11039 }
11040
11041 return deltaVol;
11042}
11043
11044
11050template <MInt nDim, class SysEqn>
11052 TRACE();
11053
11054 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
11055 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
11056 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
11057
11058 a_cellVolume(cellId) = mMax(m_volumeThreshold, m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume);
11059 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
11060 m_volumeFraction[bndryId] = mMax(m_volumeThreshold, m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume)
11061 / grid().gridCellVolume(a_level(cellId));
11062 }
11063}
11064
11065
11070template <MInt nDim, class SysEqn>
11072 TRACE();
11073
11074 if(m_timeStepAdaptationStart > -1 && m_timeStepAdaptationEnd > -1) {
11075 adaptTimeStep();
11076 }
11077
11078 m_previousTimeStep = timeStep(true);
11080 const MFloat newTimeStep = timeStep(true);
11081
11082 // update periodicGhostBody-Distance
11083 if(m_constructGField) {
11084 MFloat maxDispl = F2 * newTimeStep * m_UInfinity;
11085 if(m_adaptation) {
11086 m_periodicGhostBodyDist =
11087 1.1
11088 * (m_outerBandWidth[mMin(maxUniformRefinementLevel(), maxRefinementLevel() - 1)]
11089 + ((MFloat)noHaloLayers()) * c_cellLengthAtLevel(minLevel()) + m_maxBodyRadius + maxDispl);
11090 } else {
11091 m_periodicGhostBodyDist =
11092 1.1 * (((MFloat)noHaloLayers()) * c_cellLengthAtLevel(minLevel()) + m_maxBodyRadius + maxDispl);
11093 }
11094 }
11095
11096 // log information for possible maximum cfl-number
11097 MFloat cflMax = F0;
11098 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
11099 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
11100 if(a_bndryId(cellId) < -1) continue;
11101 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
11102 const MFloat a = sysEqn().speedOfSound(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
11103 for(MInt i = 0; i < nDim; i++) {
11104 cflMax = mMax(cflMax, newTimeStep * (fabs(a_pvariable(cellId, PV->VV[i])) + a) / c_cellLengthAtCell(cellId));
11105 }
11106 }
11107
11108 MPI_Allreduce(MPI_IN_PLACE, &cflMax, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "cflMax");
11109 m_log << "Maximum CFL number: " << cflMax << " (" << m_cfl << ")" << endl;
11110
11111 // update swept volume after timeStep change:
11112 auto oldBndryCellsBak(m_oldBndryCells);
11113 m_oldBndryCells.clear();
11114 for(auto it = oldBndryCellsBak.begin(); it != oldBndryCellsBak.end(); ++it) {
11115 const MInt cellId = it->first;
11116 const MFloat sweptVol = it->second;
11117 const MFloat sweptVolUpdate = sweptVol * (newTimeStep / m_previousTimeStep);
11118 m_oldBndryCells.insert(make_pair(cellId, sweptVolUpdate));
11119 }
11120
11121 // update external source terms after timeStep change for conservation!
11122 if(m_hasExternalSource) {
11123 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
11124 if(!a_hasProperty(cellId, SolverCell::IsActive)) continue;
11125 for(MInt var = 0; var < CV->noVariables; var++) {
11126 a_externalSource(cellId, var) *= m_previousTimeStep / newTimeStep;
11127 }
11128 }
11129 }
11130}
11131
11132
11137template <MInt nDim, class SysEqn>
11139 MInt cnt = 0;
11140 set<MInt> nghbrs;
11141
11142 for(MInt dir0 = 0; dir0 < m_noDirs; dir0++) {
11143 MInt nghbrId0 = -1;
11144
11145 if(a_hasNeighbor(cellId, dir0) > 0)
11146 nghbrId0 = c_neighborId(cellId, dir0);
11147 else if(c_parentId(cellId) > -1)
11148 if(a_hasNeighbor(c_parentId(cellId), dir0) > 0) nghbrId0 = c_neighborId(c_parentId(cellId), dir0);
11149
11150 if(nghbrId0 < 0) continue;
11151
11152 if(c_noChildren(nghbrId0) > 0) {
11153 for(MInt child = 0; child < m_noCellNodes; child++) {
11154 if(!childCode[dir0][child]) continue;
11155 if(c_childId(nghbrId0, child) > -1) nghbrs.insert(c_childId(nghbrId0, child));
11156 }
11157 } else
11158 nghbrs.insert(nghbrId0);
11159
11160 for(MInt dir1 = 0; dir1 < m_noDirs; dir1++) {
11161 if((dir1 / 2) == (dir0 / 2)) continue;
11162
11163 MInt nghbrId1 = -1;
11164
11165 if(a_hasNeighbor(nghbrId0, dir1) > 0)
11166 nghbrId1 = c_neighborId(nghbrId0, dir1);
11167 else if(c_parentId(nghbrId0) > -1)
11168 if(a_hasNeighbor(c_parentId(nghbrId0), dir1) > 0) nghbrId1 = c_neighborId(c_parentId(nghbrId0), dir1);
11169
11170 if(nghbrId1 < 0) continue;
11171
11172 if(c_noChildren(nghbrId1) > 0) {
11173 for(MInt child = 0; child < m_noCellNodes; child++) {
11174 if(!childCode[dir0][child] || !childCode[dir1][child]) continue;
11175 if(c_childId(nghbrId1, child) > -1) nghbrs.insert(c_childId(nghbrId1, child));
11176 }
11177 } else
11178 nghbrs.insert(nghbrId1);
11179 IF_CONSTEXPR(nDim == 3) {
11180 for(MInt dir2 = 0; dir2 < m_noDirs; dir2++) {
11181 if(((dir2 / 2) == (dir0 / 2)) || ((dir2 / 2) == (dir1 / 2))) continue;
11182 MInt nghbrId2 = -1;
11183 if(a_hasNeighbor(nghbrId1, dir2) > 0)
11184 nghbrId2 = c_neighborId(nghbrId1, dir2);
11185 else if(c_parentId(nghbrId1) > -1)
11186 if(a_hasNeighbor(c_parentId(nghbrId1), dir2) > 0) nghbrId2 = c_neighborId(c_parentId(nghbrId1), dir2);
11187 if(nghbrId2 < 0) continue;
11188 // nghbrs.insert( nghbrId2 );
11189 if(c_noChildren(nghbrId2) > 0) {
11190 for(MInt child = 0; child < m_noCellNodes; child++) {
11191 if(!childCode[dir0][child] || !childCode[dir1][child] || !childCode[dir2][child]) continue;
11192 if(c_childId(nghbrId2, child) > -1) nghbrs.insert(c_childId(nghbrId2, child));
11193 }
11194 } else
11195 nghbrs.insert(nghbrId2);
11196 }
11197 }
11198 }
11199 }
11200 set<MInt>::iterator it = nghbrs.begin();
11201 for(it = nghbrs.begin(); it != nghbrs.end(); it++) {
11202 ASSERT(cnt < 27 * m_noCellNodes, "");
11203 adjacentCells[cnt] = *it;
11204 cnt++;
11205 }
11206 return cnt;
11207}
11208
11209
11214template <MInt nDim, class SysEqn>
11216 constexpr MInt offs[3] = {1, 3, 9};
11217 auto nbIdx0 = [&]() { return 13; };
11218 auto nbIdx1 = [&](MInt dir0, MInt sign0) { return nbIdx0() + offs[dir0] * sign0; };
11219 auto nbIdx2 = [&](MInt dir0, MInt sign0, MInt dir1, MInt sign1) {
11220 return nbIdx0() + offs[dir0] * sign0 + offs[dir1] * sign1;
11221 };
11222 std::fill_n(nghbrs, 27, -1);
11223 nghbrs[nbIdx0()] = cellId;
11224
11225 for(MInt dir0 = 0; dir0 < m_noDirs; dir0++) {
11226 MInt nghbrId0 = -1;
11227
11228 if(a_hasNeighbor(cellId, dir0) > 0) {
11229 nghbrId0 = c_neighborId(cellId, dir0);
11230 }
11231
11232 if(nghbrId0 < 0) continue;
11233
11234 MInt sign0 = (dir0 % 2 == 0) ? -1 : 1;
11235 ASSERT(nghbrs[nbIdx1(dir0 / 2, sign0)] == -1 || nghbrs[nbIdx1(dir0 / 2, sign0)] == nghbrId0, "");
11236 nghbrs[nbIdx1(dir0 / 2, sign0)] = nghbrId0;
11237
11238 for(MInt dir1 = 0; dir1 < m_noDirs; dir1++) {
11239 if((dir1 / 2) == (dir0 / 2)) continue;
11240 MInt nghbrId1 = -1;
11241 if(a_hasNeighbor(nghbrId0, dir1) > 0) {
11242 nghbrId1 = c_neighborId(nghbrId0, dir1);
11243 }
11244 if(nghbrId1 < 0) continue;
11245 MInt sign1 = (dir1 % 2 == 0) ? -1 : 1;
11246 ASSERT(nghbrs[nbIdx2(dir0 / 2, sign0, dir1 / 2, sign1)] == -1
11247 || nghbrs[nbIdx2(dir0 / 2, sign0, dir1 / 2, sign1)] == nghbrId1,
11248 "");
11249 nghbrs[nbIdx2(dir0 / 2, sign0, dir1 / 2, sign1)] = nghbrId1;
11250 IF_CONSTEXPR(nDim == 3) {
11251 auto nbIdx3 = [&](MInt ldir0, MInt lsign0, MInt ldir1, MInt lsign1, MInt ldir2, MInt lsign2) {
11252 return nbIdx0() + offs[ldir0] * lsign0 + offs[ldir1] * lsign1 + offs[ldir2] * lsign2;
11253 };
11254 for(MInt dir2 = 0; dir2 < m_noDirs; dir2++) {
11255 if(((dir2 / 2) == (dir0 / 2)) || ((dir2 / 2) == (dir1 / 2))) continue;
11256 MInt nghbrId2 = -1;
11257 if(a_hasNeighbor(nghbrId1, dir2) > 0) {
11258 nghbrId2 = c_neighborId(nghbrId1, dir2);
11259 }
11260 if(nghbrId2 < 0) continue;
11261 MInt sign2 = (dir2 % 2 == 0) ? -1 : 1;
11262 ASSERT(nghbrs[nbIdx3(dir0 / 2, sign0, dir1 / 2, sign1, dir2 / 2, sign2)] == -1
11263 || nghbrs[nbIdx3(dir0 / 2, sign0, dir1 / 2, sign1, dir2 / 2, sign2)] == nghbrId2,
11264 "");
11265 nghbrs[nbIdx3(dir0 / 2, sign0, dir1 / 2, sign1, dir2 / 2, sign2)] = nghbrId2;
11266 }
11267 }
11268 }
11269 }
11270
11271 return (std::count_if(nghbrs, nghbrs + 27, [](const MInt& a) { return (a > -1); }));
11272}
11273
11274
11279template <MInt nDim, class SysEqn>
11281 MInt cnt = 0;
11282 set<MInt> nghbrs;
11283
11284 for(MInt dir0 = 0; dir0 < m_noDirs; dir0++) {
11285 if(a_hasNeighbor(cellId, dir0) == 0) continue;
11286
11287 const MInt nghbrId0 = c_neighborId(cellId, dir0);
11288
11289 if(nghbrId0 < 0) continue;
11290
11291 if(a_hasProperty(nghbrId0, SolverCell::IsOnCurrentMGLevel) && !a_hasProperty(nghbrId0, SolverCell::IsInactive)
11292 && !a_isBndryGhostCell(nghbrId0)) {
11293 adjacentCells[cnt] = nghbrId0;
11294 cnt++;
11295 }
11296 for(MInt dir1 = 0; dir1 < m_noDirs; dir1++) {
11297 if((dir1 / 2) == (dir0 / 2)) continue;
11298 if(a_hasNeighbor(nghbrId0, dir1) == 0) continue;
11299 const MInt nghbrId1 = c_neighborId(nghbrId0, dir1);
11300 if(nghbrId1 < 0) continue;
11301 if(a_hasProperty(nghbrId1, SolverCell::IsOnCurrentMGLevel) && !a_hasProperty(nghbrId1, SolverCell::IsInactive)
11302 && !a_isBndryGhostCell(nghbrId1))
11303 nghbrs.insert(nghbrId1);
11304#ifdef __REMOVE_TO_USE__
11305 IF_CONSTEXPR(nDim == 3) {
11306 for(MInt dir2 = 0; dir2 < m_noDirs; dir2++) {
11307 if(((dir2 / 2) == (dir0 / 2)) || ((dir2 / 2) == (dir1 / 2))) continue;
11308 if(a_hasNeighbor(nghbrId1, dir2) == 0) continue;
11309 const MInt nghbrId2 = c_neighborId(nghbrId1, dir2);
11310 if(nghbrId2 < 0) continue;
11311 if(a_hasProperty(nghbrId2, SolverCell::IsOnCurrentMGLevel) && !a_hasProperty(nghbrId2, SolverCell::IsInactive)
11312 && !a_isBndryGhostCell(nghbrId2))
11313 nghbrs.insert(nghbrId2);
11314 }
11315 }
11316#endif
11317 }
11318 }
11319 set<MInt>::iterator it = nghbrs.begin();
11320 for(it = nghbrs.begin(); it != nghbrs.end(); it++) {
11321 adjacentCells[cnt] = *it;
11322 cnt++;
11323 }
11324 return cnt;
11325}
11326
11327
11332template <MInt nDim, class SysEqn>
11334 set<MInt> nghbrs;
11335
11336 for(MInt dir0 = 0; dir0 < m_noDirs; dir0++) {
11337 MInt nghbrId0 = -1;
11338
11339 if(a_hasNeighbor(cellId, dir0) > 0)
11340 nghbrId0 = c_neighborId(cellId, dir0);
11341 else if(c_parentId(cellId) > -1)
11342 if(a_hasNeighbor(c_parentId(cellId), dir0) > 0) nghbrId0 = c_neighborId(c_parentId(cellId), dir0);
11343
11344 if(nghbrId0 < 0) continue;
11345
11346 const MInt noC0 = c_noChildren(nghbrId0);
11347
11348 for(MInt c0 = 0; c0 < mMax(1, noC0); c0++) {
11349 if(noC0 && !childCode[dir0][c0]) continue;
11350 MInt nghbrId00 = noC0 ? c_childId(nghbrId0, c0) : nghbrId0;
11351 if(nghbrId00 < 0) continue;
11352 if(a_hasProperty(nghbrId00, SolverCell::IsOnCurrentMGLevel) && !a_hasProperty(nghbrId00, SolverCell::IsInactive)
11353 && !a_isBndryGhostCell(nghbrId00)) {
11354 nghbrs.insert(nghbrId00);
11355 }
11356 for(MInt dir1 = 0; dir1 < m_noDirs; dir1++) {
11357 if((dir1 / 2) == (dir0 / 2)) continue;
11358 MInt nghbrId1 = -1;
11359 if(a_hasNeighbor(nghbrId00, dir1) > 0)
11360 nghbrId1 = c_neighborId(nghbrId00, dir1);
11361 else if(c_parentId(nghbrId00) > -1)
11362 if(a_hasNeighbor(c_parentId(nghbrId00), dir1) > 0) nghbrId1 = c_neighborId(c_parentId(nghbrId00), dir1);
11363 if(nghbrId1 < 0) continue;
11364 const MInt noC1 = c_noChildren(nghbrId1);
11365 for(MInt c1 = 0; c1 < mMax(1, noC1); c1++) {
11366 if(noC1 && !childCode[dir1][c1]) continue;
11367 MInt nghbrId11 = noC1 ? c_childId(nghbrId1, c1) : nghbrId1;
11368 if(nghbrId11 < 0) continue;
11369 MBool facing = true;
11370 for(MInt i = 0; i < nDim; i++) {
11371 if(fabs(a_coordinate(cellId, i) - a_coordinate(nghbrId00, i))
11372 > ((F1 + 1e-8) * c_cellLengthAtLevel(a_level(cellId))
11373 + (F1 + 1e-8) * c_cellLengthAtLevel(a_level(nghbrId00))))
11374 facing = false;
11375 }
11376 if(!facing) continue;
11377 if(a_hasProperty(nghbrId11, SolverCell::IsOnCurrentMGLevel)
11378 && !a_hasProperty(nghbrId11, SolverCell::IsInactive) && !a_isBndryGhostCell(nghbrId11)) {
11379 nghbrs.insert(nghbrId11);
11380 }
11381
11382#ifdef __REMOVE_TO_USE__
11383 IF_CONSTEXPR(nDim == 3) {
11384 mTerm(1, AT_, "TODO");
11385 for(MInt dir2 = 0; dir2 < m_noDirs; dir2++) {
11386 if(((dir2 / 2) == (dir0 / 2)) || ((dir2 / 2) == (dir1 / 2))) continue;
11387 if(a_hasNeighbor(nghbrId1, dir2) == 0) continue;
11388 const MInt nghbrId2 = c_neighborId(nghbrId1, dir2);
11389 if(nghbrId2 < 0) continue;
11390 if(a_hasProperty(nghbrId2, SolverCell::IsOnCurrentMGLevel)
11391 && !a_hasProperty(nghbrId2, SolverCell::IsInactive) && !a_isBndryGhostCell(nghbrId2))
11392 nghbrs.insert(nghbrId2);
11393 }
11394 }
11395#endif
11396 }
11397 }
11398 }
11399 }
11400
11401 MInt cnt = 0;
11402 for(set<MInt>::iterator it = nghbrs.begin(); it != nghbrs.end(); it++) {
11403 adjacentCells[cnt] = *it;
11404 cnt++;
11405 }
11406 return cnt;
11407}
11408
11409
11414template <MInt nDim, class SysEqn>
11416 MInt cnt = getAdjacentCells(cellId, adjacentCells);
11417 set<MInt> nghbrs;
11418
11419 for(MInt dir0 = 0; dir0 < m_noDirs; dir0++) {
11420 if(a_hasNeighbor(cellId, dir0) == 0) continue;
11421 const MInt nghbrId00 = c_neighborId(cellId, dir0);
11422 if(a_hasNeighbor(nghbrId00, dir0) == 0) continue;
11423 const MInt nghbrId0 = c_neighborId(nghbrId00, dir0);
11424 if(nghbrId0 < 0) continue;
11425 if(a_hasProperty(nghbrId0, SolverCell::IsOnCurrentMGLevel) && !a_hasProperty(nghbrId0, SolverCell::IsInactive)
11426 && !a_isBndryGhostCell(nghbrId0)) {
11427 adjacentCells[cnt] = nghbrId0;
11428 cnt++;
11429 }
11430
11431 for(MInt dir1 = 0; dir1 < m_noDirs; dir1++) {
11432 if((dir1 / 2) == (dir0 / 2)) continue;
11433 if(a_hasNeighbor(nghbrId0, dir1) == 0) continue;
11434 const MInt nghbrId1 = c_neighborId(nghbrId0, dir1);
11435 if(nghbrId1 < 0) continue;
11436 if(a_hasProperty(nghbrId1, SolverCell::IsOnCurrentMGLevel) && !a_hasProperty(nghbrId1, SolverCell::IsInactive)
11437 && !a_isBndryGhostCell(nghbrId1))
11438 nghbrs.insert(nghbrId1);
11439#ifdef __REMOVE_TO_USE__
11440 IF_CONSTEXPR(nDim == 3) {
11441 for(MInt dir2 = 0; dir2 < m_noDirs; dir2++) {
11442 if(((dir2 / 2) == (dir0 / 2)) || ((dir2 / 2) == (dir1 / 2))) continue;
11443 if(a_hasNeighbor(nghbrId1, dir2) == 0) continue;
11444 const MInt nghbrId2 = c_neighborId(nghbrId1, dir2);
11445 if(nghbrId2 < 0) continue;
11446 if(a_hasProperty(nghbrId2, SolverCell::IsOnCurrentMGLevel) && !a_hasProperty(nghbrId2, SolverCell::IsInactive)
11447 && !a_isBndryGhostCell(nghbrId2))
11448 nghbrs.insert(nghbrId2);
11449 }
11450 }
11451#endif
11452 }
11453 }
11454 set<MInt>::iterator it = nghbrs.begin();
11455 for(it = nghbrs.begin(); it != nghbrs.end(); it++) {
11456 adjacentCells[cnt] = *it;
11457 cnt++;
11458 }
11459 return cnt;
11460}
11461
11462
11467template <MInt nDim, class SysEqn>
11469 TRACE();
11470
11471 mTerm(1, AT_, "deprecated, ghost cells are not anticipated for memory efficiency.");
11472
11473 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
11474 const MInt cellId = m_bndryLayerCells[c];
11475
11476 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
11477 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
11478 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
11479 if(a_isBndryGhostCell(cellId)) continue;
11480 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
11481 if(a_bndryId(cellId) < -1) continue;
11482 if(c_noChildren(cellId) > 0) continue;
11483
11484 const MInt bndryId = a_bndryId(cellId);
11485 MFloatScratchSpace dummyPvariables(m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs, PV->noVariables, AT_,
11486 "dummyPvariables");
11487 for(MInt set = m_startSet; set < m_noSets; set++) {
11488 if(a_associatedBodyIds(cellId, set) < 0) continue;
11489
11490 const MInt ghostCellId = -1; // m_nearBndryGhostCells[c][set];
11491
11492 if(ghostCellId < 0) continue;
11493 const MInt bodyId = a_associatedBodyIds(cellId, set);
11494 if(bodyId < 0) {
11495 cerr << "Warning: no associated body" << endl;
11496 continue;
11497 }
11498 const MFloat phi = a_levelSetValuesMb(cellId, set);
11499 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
11500 MFloat vel[3] = {F0, F0, F0};
11501 MFloat xsurf[3] = {F0, F0, F0};
11502 MFloat normal[3] = {F0, F0, F0};
11503 MInt srfc = -1;
11504 if(bndryId >= m_noOuterBndryCells) {
11505 for(MInt s = 0; s < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; s++) {
11506 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[s]->m_bodyId[0] == bodyId) {
11507 srfc = s;
11508 break;
11509 }
11510 }
11511 if(srfc < 0 && m_noLevelSetsUsedForMb == 1) mTerm(1, AT_, "srfc not found.");
11512 }
11513
11514 for(MInt i = 0; i < nDim; i++) {
11515 normal[i] = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i];
11516 }
11517
11518 for(MInt i = 0; i < nDim; i++) {
11519 vel[i] = m_bodyVelocity[bodyId * nDim + i];
11520 xsurf[i] = a_coordinate(cellId, i) - phi * normal[i];
11521 }
11522
11523 MFloat dx[3] = {F0, F0, F0};
11524 MFloat omega[3] = {F0, F0, F0};
11525
11526 for(MInt i = 0; i < nDim; i++) {
11527 dx[i] = xsurf[i] - m_bodyCenter[bodyId * nDim + i];
11528 }
11529
11530 for(MInt i = 0; i < 3; i++) {
11531 omega[i] = m_bodyAngularVelocity[bodyId * 3 + i];
11532 }
11533
11534 vel[0] += omega[1] * dx[2] - omega[2] * dx[1];
11535 vel[1] += omega[2] * dx[0] - omega[0] * dx[2];
11536 IF_CONSTEXPR(nDim == 3) { vel[2] += omega[0] * dx[1] - omega[1] * dx[0]; }
11537
11538 if(m_euler) {
11539 MFloat vel2[3];
11540 for(MInt i = 0; i < nDim; i++) {
11541 vel2[i] = a_pvariable(cellId, PV->VV[i]);
11542 for(MInt j = 0; j < nDim; j++) {
11543 vel2[i] += m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
11544 * (vel[i] - a_pvariable(cellId, PV->VV[j]))
11545 * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[j];
11546 }
11547 }
11548 for(MInt i = 0; i < nDim; i++) {
11549 vel[i] = vel2[i];
11550 }
11551 }
11552
11553 MFloat imageVel[3];
11554 for(MInt i = 0; i < nDim; i++) {
11555 imageVel[i] = a_pvariable(cellId, PV->VV[i]);
11556 }
11557 if(bndryId >= m_noOuterBndryCells && srfc > -1) {
11558 for(MInt s = 0; s < mMin((signed)m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size(),
11559 m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs);
11560 s++) {
11561 for(MInt i = 0; i < nDim; i++) {
11562 dummyPvariables(s, PV->VV[i]) = vel[i];
11563 }
11564 }
11565 for(MInt i = 0; i < nDim; i++) {
11566 imageVel[i] = F0;
11567 }
11568 for(MInt n = 0; n < (signed)m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size(); n++) {
11569 const MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
11570 for(MInt i = 0; i < nDim; i++) {
11571 const MFloat nghbrPvariable = (n < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs)
11572 ? dummyPvariables(n, PV->VV[i])
11573 : a_pvariable(nghbrId, PV->VV[i]);
11574 imageVel[i] +=
11575 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariable;
11576 }
11577 }
11578 MFloat vf = a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId));
11579 MFloat fac = maia::math::deltaFun(vf, 0.95, F1);
11580 for(MInt i = 0; i < nDim; i++) {
11581 imageVel[i] = (fac * a_pvariable(cellId, PV->VV[i]) + (F1 - fac) * imageVel[i]);
11582 }
11583 }
11584
11585
11586 for(MInt i = 0; i < nDim; i++) {
11587 a_pvariable(ghostCellId, PV->VV[i]) = F2 * vel[i] - imageVel[i];
11588 }
11589
11590
11591 MFloat dn = F0;
11592 for(MInt i = 0; i < nDim; i++) {
11593 dn += (a_coordinate(cellId, i) - a_coordinate(ghostCellId, i)) * normal[i];
11594 }
11595 dn -= phi;
11596 if(dn + phi < 1e-8) {
11597 cerr << domainId() << ": warning very small distance " << c_globalId(cellId) << " " << phi << " " << dn << endl;
11598 }
11599
11600 MFloat delta[3] = {F0, F0, F0};
11601 MFloat dr[3] = {F0, F0, F0};
11602 MFloat dw[3] = {F0, F0, F0};
11603 MFloat dg[3] = {F0, F0, F0};
11604 MFloat du[3] = {F0, F0, F0};
11605 MFloat dv[3] = {F0, F0, F0};
11606 for(MInt i = 0; i < nDim; i++) {
11607 dr[i] = a_coordinate(cellId, i) - phi * normal[i] - m_bodyCenter[bodyId * nDim + i];
11608 du[i] = m_bodyAcceleration[bodyId * nDim + i];
11609 dv[i] = vel[i] - m_bodyVelocity[bodyId * nDim + i];
11610 }
11611 for(MInt i = 0; i < 3; i++) {
11612 dw[i] = m_bodyAngularAcceleration[bodyId * 3 + i];
11613 dg[i] = m_bodyAngularVelocity[bodyId * 3 + i];
11614 }
11615 // assemble material acceleration
11616 delta[0] = du[0] + dw[1] * dr[2] - dw[2] * dr[1] + dg[1] * dv[2] - dg[2] * dv[1];
11617 delta[1] = du[1] + dw[2] * dr[0] - dw[0] * dr[2] + dg[2] * dv[0] - dg[0] * dv[2];
11618 delta[2] = du[2] + dw[0] * dr[1] - dw[1] * dr[0] + dg[0] * dv[1] - dg[1] * dv[0];
11619
11620 MFloat an = F0;
11621 for(MInt i = 0; i < nDim; i++) {
11622 an += normal[i] * delta[i];
11623 }
11624
11625 MFloat surfTemp = sysEqn().temperature_ES(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
11626 const MFloat beta = sysEqn().density_ES(an, surfTemp);
11627 const MFloat fac = (F1 + F1B2 * beta * (dn + phi)) / (F1 - F1B2 * beta * (dn + phi));
11628
11629 a_pvariable(ghostCellId, PV->P) = fac * a_pvariable(cellId, PV->P);
11630 a_pvariable(ghostCellId, PV->RHO) = fac * a_pvariable(cellId, PV->RHO);
11631 }
11632 }
11633}
11634
11635
11640template <MInt nDim, class SysEqn>
11642 TRACE();
11643
11644 const MInt recDim = (m_orderOfReconstruction == 2) ? (IPOW2(nDim) + 1) : nDim;
11645
11646 MIntScratchSpace nghbrList(100, AT_, "nghbrList");
11647 MIntScratchSpace nghbrListTmp(100, AT_, "nghbrListTmp");
11648 MIntScratchSpace layerId(100, AT_, "layerList");
11649 MFloatScratchSpace tmpA(100, recDim, AT_, "tmpA");
11650 MFloatScratchSpace tmpC(recDim, 100, AT_, "tmpC");
11651 MFloatScratchSpace weights(100, AT_, "weights");
11652#if defined _MB_DEBUG_ || !defined NDEBUG
11653 MFloat cntCnd = F0;
11654 MFloat avgCnd = F0;
11655 MFloat maxCnd = F0;
11656#endif
11657
11658 // reset noReconstruction neighbors for all bndryLayer Cells
11659 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
11660 const MInt cellId = m_bndryLayerCells[c];
11661 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
11662 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
11663 a_hasProperty(cellId, SolverCell::IsFlux) = true;
11664 a_noReconstructionNeighbors(cellId) = 0;
11665 }
11666
11667 // recompute noReconstruction neighbors for all bndryLayeCells
11668 for(MUint c = 0; c < m_bndryLayerCells.size(); c++) {
11669 const MInt cellId = m_bndryLayerCells[c];
11670 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
11671 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
11672 if(a_isBndryGhostCell(cellId)) continue;
11673 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
11674 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
11675 if(a_bndryId(cellId) < -1) continue;
11676 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(cellId) > 0) continue;
11677 ASSERT(a_noReconstructionNeighbors(cellId) == 0,
11678 to_string(cellId) + " " + to_string(c) + " " + to_string(a_noReconstructionNeighbors(cellId)));
11679
11680 const MInt bndryId = a_bndryId(cellId);
11681
11682 // add ghostCells as reconstruction neighbor for bndryCells, each bndrySurface has one ghostCell
11683 if(bndryId >= m_noOuterBndryCells) {
11684 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
11685 const MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
11686 ASSERT(ghostCellId > -1, "");
11687 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) = ghostCellId;
11688 a_noReconstructionNeighbors(cellId)++;
11689 }
11690 }
11691
11692 const MInt rootCell =
11693 (a_hasProperty(cellId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(cellId) : cellId;
11694 ASSERT(rootCell > -1 && rootCell < a_noCells(), "");
11695
11696 // get all neighbors (also diagonal) with 1 layer
11697 // this causes problems at level jumps, as then
11698 // more than the allowed number of reconstruction neighbors may be found!!!!
11699 // the last entries are then randomly disregareded!
11700 MInt counter = -1;
11701 MInt noactiveNeighbors = 1;
11702 if(!m_bndryLevelJumps && !m_dynamicStencil) {
11703 counter = this->template getAdjacentLeafCells<2, true>(rootCell, 1, nghbrList, layerId);
11704 } else {
11705 // new faster version which only uses direct neighbors and not diagonal ones
11706 // counter = this->template getAdjacentLeafCells<0,true>( rootCell, 1, nghbrList, layerId );
11707
11708 // new!
11709 // check the number of active neighbors,
11710 // reduce the stencil if the number is above the threshold!
11711 // TODO labels:FVMB,totest check if this is done consistently on window&halo cells!
11712 counter = this->template getAdjacentLeafCells<2, true>(rootCell, 1, nghbrList, layerId);
11713 // TODO labels:FVMB update testcases to correct value below!
11714 if(m_engineSetup) {
11715 noactiveNeighbors = a_noReconstructionNeighbors(cellId);
11716 }
11717 for(MInt n = 0; n < counter; n++) {
11718 const MInt nghbrId = nghbrList[n];
11719 if(nghbrId < 0) continue;
11720 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
11721 noactiveNeighbors++;
11722 }
11723 if(noactiveNeighbors > m_cells.noRecNghbrs() - 1) {
11724 counter = this->template getAdjacentLeafCells<0, true>(rootCell, 1, nghbrList, layerId);
11725 }
11726 }
11727
11728 // add reconstruction neighbors
11729 for(MInt n = 0; n < counter; n++) {
11730 const MInt nghbrId = nghbrList[n];
11731 if(nghbrId < 0) continue;
11732 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
11733 if(a_noReconstructionNeighbors(cellId) < m_cells.noRecNghbrs()) {
11734 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) = nghbrId;
11735 a_noReconstructionNeighbors(cellId)++;
11736 } else {
11737 cerr << "Warning: too many reconstruction neighbors for cell " << cellId;
11738 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
11739 cerr << "/-";
11740 } else {
11741 cerr << "/" << c_globalId(cellId);
11742 }
11743 cerr << " " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, 2)
11744 << " " << a_noReconstructionNeighbors(cellId) << "/" << counter << endl;
11745 }
11746 }
11747
11748
11749 const MInt offset = m_cells.noRecNghbrs() * cellId;
11750
11751 // NOTE: cbc cutOff cells should only use direct neighbors for slope-interpolation!
11752 const MInt mode = (m_fvBndryCnd->m_cbcSmallCellCorrection && a_hasProperty(cellId, SolverCell::IsCutOff))
11753 ? 1
11754 : m_reConstSVDWeightMode;
11755 MFloat condNum = computeRecConstSVD(cellId, offset, tmpA, tmpC, weights, recDim, mode, 1);
11756
11757
11758 // if the condNum is invalid, the stencil is recomputed:
11759 if((condNum < F0 || condNum > 1e6 || std::isnan(condNum))) {
11760#if defined _MB_DEBUG_ || !defined NDEBUG
11761
11762 const MFloat vf = (a_bndryId(cellId) > -1) ? m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_volume
11763 / grid().gridCellVolume(a_level(cellId))
11764 : F1;
11765
11766 cerr << domainId() << " " << globalTimeStep << " recompute stencil for cell " << cellId << "/"
11767 << c_globalId(cellId) << " level " << a_level(cellId) << " vol "
11768 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << " " << vf << " cond " << condNum << " "
11769 << endl;
11770#endif
11771 }
11772
11773
11774 if(a_noReconstructionNeighbors(cellId) > m_cells.noRecNghbrs()) {
11775 mTerm(1, AT_, "Error in buildAdditionalReconstructionStencil too many rec neighbors.");
11776 }
11777
11778#if defined _MB_DEBUG_ || !defined NDEBUG
11779 avgCnd += condNum;
11780 maxCnd = mMax(maxCnd, condNum);
11781 cntCnd += F1;
11782#endif
11783 }
11784
11785 m_reconstructionDataSize = 0;
11786 a_reconstructionData(a_noCells()) = -1;
11787
11788#if defined _MB_DEBUG_ || !defined NDEBUG
11789 if(globalTimeStep % 100 == 0) {
11790 MPI_Allreduce(MPI_IN_PLACE, &maxCnd, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "maxCnd");
11791 MPI_Allreduce(MPI_IN_PLACE, &avgCnd, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "avgCnd");
11792 MPI_Allreduce(MPI_IN_PLACE, &cntCnd, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cntCnd");
11793
11794 m_log << "Singular value decomposition: near-boundary maximum/average condition number: " << maxCnd << "/"
11795 << avgCnd / cntCnd << endl;
11796 }
11797#endif
11798}
11799
11800
11805template <MInt nDim, class SysEqn>
11807 if(noNeighborDomains() == 0) {
11808 if(noDomains() > 1) mTerm(1, AT_, "Unexpected situation in updateMultiSolverInformation");
11809 return;
11810 }
11811
11812 if(fullReset) {
11813 mDeallocate(g_mpiRequestMb);
11814 mDeallocate(m_linkedWindowCells);
11815 mDeallocate(m_linkedHaloCells);
11816 mDeallocate(m_gapHaloCells);
11817 mDeallocate(m_gapWindowCells);
11818 mAlloc(g_mpiRequestMb, noNeighborDomains(), "g_mpiRequestMb", MPI_REQ_NULL, AT_);
11819 mAlloc(m_linkedWindowCells, noNeighborDomains(), "m_linkedWindowCells", AT_);
11820 mAlloc(m_linkedHaloCells, noNeighborDomains(), "m_linkedHaloCells", AT_);
11821 mAlloc(m_gapWindowCells, noNeighborDomains(), "m_gapWindowCells", AT_);
11822 mAlloc(m_gapHaloCells, noNeighborDomains(), "m_gapHaloCells", AT_);
11823 }
11824
11826}
11827
11828
11833template <MInt nDim, class SysEqn>
11835 TRACE();
11836
11837 ASSERT(!m_onlineRestart, "");
11838
11839 // Nothing further to be done if inactive
11840 if(!isActive()) return;
11841
11842 const MFloat time0 = MPI_Wtime();
11843
11844 // for STL levelset this is called in coupler init!
11845 if(m_constructGField) {
11846 if(m_initialCondition == 465) {
11847 m_initialCondition = -1;
11848 setInfinityState();
11849 m_initialCondition = 465;
11850 }
11851 initGField();
11852 initBndryLayer();
11853 } else {
11854 initBodyProperties();
11855 }
11856
11857 // initialize the runge kutta integration scheme
11858 initializeRungeKutta();
11859
11860 if(m_restart) {
11861 loadRestartFile();
11862 initBodyProperties();
11863 if(m_geometryChange == nullptr) {
11864 loadBodyRestartFile(0);
11865 } else {
11866 loadBodyRestartFile(2);
11867 }
11868
11869 } else {
11870 applyInitialCondition();
11871 for(MInt cellId = a_noCells(); cellId--;) {
11872 setPrimitiveVariables(cellId);
11873 }
11874 }
11875
11876 // THOMAS
11877 if(this->m_zonal) {
11878 resetZonalSolverData();
11879 if(this->m_STGSponge) this->initSTGSponge();
11880
11881 if(this->m_resetInitialCondition && m_solverId == this->m_zonalRestartInterpolationSolverId) {
11882 if(domainId() == 0) cerr << "resetInitialCondition: loadRestartFile for solver " << m_solverId << endl;
11883 loadRestartFile();
11884 }
11885 }
11886
11887 if(grid().azimuthalPeriodicity()) initAzimuthalCartesianHaloInterpolation();
11888
11889 // set data on halo-cells
11890 if(noNeighborDomains() > 0) {
11891 exchangeDataFV(&a_variable(0, 0), m_noCVars, false, m_rotIndVarsCV);
11892 if(m_restartOldVariables) {
11893 exchangeDataFV(&a_oldVariable(0, 0), m_noCVars, false, m_rotIndVarsCV);
11894 }
11895 exchangeDataFV(&a_pvariable(0, 0), m_noPVars, false, m_rotIndVarsPV);
11896 exchangeData(&a_cellVolume(0), 1); // Exchanging cell volume for azimuthal periodicity would be incorrect!
11897 }
11898
11899 const MFloat time1 = MPI_Wtime();
11900
11901 if(domainId() == 0) m_log << "Init solution time " << time1 - time0 << endl;
11902}
11903
11904
11909template <MInt nDim, class SysEqn>
11911 TRACE();
11912
11913 // Nothing to be done if solver is not active
11914 if(!isActive()) return;
11915
11916 // initialize the solver
11917 ASSERT(!m_onlineRestart, "");
11918 initSolutionStep(-1);
11919
11920 if(!Context::propertyExists("ReLambdaRestart", m_solverId)) {
11921 applyInitialCondition();
11922 computePV();
11923 }
11924
11925 // Reallocate solver memory to arrays depending on a_noCells()
11926 reInitActiveCellIdsMemory();
11927
11928 if(m_zonal) {
11929 determineLESAverageCells();
11930 resetZonalLESAverage();
11931 }
11932
11933 writeListOfActiveFlowCells();
11934 setTimeStep();
11935
11936 // First RHS
11937 // compute a first RHS (firstRHS) for the modified runge-kutta time step/solution step method:
11938 if(m_levelSetMb) {
11939 preSolutionStep(1);
11940
11941 // Set cut-off boundary conditions - Moved behind preSolutionStep
11942 initCutOffBoundaryCondition();
11943 cutOffBoundaryCondition();
11944 if(grid().azimuthalPeriodicity()) {
11945 exchangeFloatDataAzimuthal(&a_pvariable(0, 0), PV->noVariables, m_rotIndVarsPV);
11946 }
11947
11948 if(!m_levelSetRans && !m_standardRK) {
11949 this->rhs();
11950 this->rhsBnd();
11951 prepareNextTimeStep();
11952 }
11953 }
11954}
11955
11956
11961template <MInt nDim, class SysEqn>
11964 setAdditionalCellProperties();
11965}
11966
11967
11972template <MInt nDim, class SysEqn>
11974 // dummy currently
11975}
11976
11977
11982template <MInt nDim, class SysEqn>
11984 const MFloat epsilon = 1e-12;
11985 MBool error;
11986 MInt s, pRow; // pivot row
11987 MFloat f, h, maximum;
11988
11989 // add the unity matrix
11990 for(MInt i = 0; i < nDim; i++) {
11991 for(MInt j = 0; j < nDim; j++) {
11992 m_A[i][nDim + j] = F0;
11993 }
11994 m_A[i][nDim + i] = F1;
11995 }
11996
11997 // Gauss algorithm
11998 error = false;
11999 s = 0;
12000 while(s < nDim) {
12001 maximum = fabs(m_A[s][s]);
12002 pRow = s;
12003 for(MInt i = s + 1; i < nDim; i++) {
12004 if(fabs(m_A[i][s]) > maximum) {
12005 maximum = fabs(m_A[i][s]);
12006 pRow = i;
12007 }
12008 }
12009
12010 if(maximum < epsilon) {
12011 error = true;
12012 break;
12013 }
12014
12015 if(pRow != s) { // exchange rows if required
12016 for(MInt j = s; j < 2 * nDim; j++) {
12017 h = m_A[s][j];
12018 m_A[s][j] = m_A[pRow][j];
12019 m_A[pRow][j] = h;
12020 }
12021 }
12022
12023 f = m_A[s][s];
12024 for(MInt j = s; j < 2 * nDim; j++)
12025 m_A[s][j] /= f;
12026
12027 // elimination
12028 for(MInt i = 0; i < nDim; i++) {
12029 if(i != s) {
12030 f = -m_A[i][s];
12031 for(MInt j = s; j < 2 * nDim; j++)
12032 m_A[i][j] += f * m_A[s][j];
12033 }
12034 }
12035 s++;
12036 }
12037
12038 if(error) {
12039 cerr << "Domain " << domainId() << endl;
12040 cerr << "Error in GJ matrix inverse computation " << s << " " << m_A[s][s] << endl;
12041 for(MInt i = 0; i < nDim; i++) {
12042 for(MInt j = 0; j < nDim; j++) {
12043 cerr << m_A[i][j] << " ";
12044 }
12045 cerr << endl;
12046 }
12047 cerr << endl;
12048 return -1;
12049 }
12050 return 0;
12051}
12052
12053
12058template <MInt nDim, class SysEqn>
12060 TRACE();
12061
12062 exchangeDataFV(&(a_levelSetValuesMb(0, 0)), m_noLevelSetsUsedForMb);
12063 exchangeDataFV(&(a_associatedBodyIds(0, 0)), m_noLevelSetsUsedForMb);
12064}
12065
12073template <MInt nDim, class SysEqn>
12074template <MInt timeStepMethod>
12076 TRACE();
12077
12078 MFloat dt = m_RKalpha[m_RKStep] * timeStep();
12079 const MInt xdim = a_noCells();
12080 const MInt ydim = m_noCVars;
12081
12082 MFloat* RESTRICT cVars = (MFloat*)(&(a_variable(0, 0)));
12083 MFloat* RESTRICT oCVars = (MFloat*)(&(a_oldVariable(0, 0)));
12084 MFloat* RESTRICT RHS = (MFloat*)(&(a_rightHandSide(0, 0)));
12085 MFloat* RESTRICT vol1 = (MFloat*)(&(m_cellVolumesDt1[0]));
12086 MFloat* RESTRICT fVol = (MFloat*)(&(a_FcellVolume(0)));
12087
12088 for(MUint it = 0; it < m_temporarilyLinkedCells.size(); it++) {
12089 const MInt cellId = get<0>(m_temporarilyLinkedCells[it]);
12090 const MInt masterId = get<1>(m_temporarilyLinkedCells[it]);
12091 const MInt tripleLink = get<2>(m_temporarilyLinkedCells[it]);
12092
12093 if(tripleLink < 0) {
12094 MFloat fac0 = a_cellVolume(cellId) / (a_cellVolume(cellId) + a_cellVolume(masterId));
12095 MFloat fac1 = F1 - fac0;
12096 for(MInt v = 0; v < m_noCVars; v++) {
12097 MFloat delta =
12098 (fac1 * vol1[cellId] * oCVars[ydim * cellId + v] - fac0 * vol1[masterId] * oCVars[ydim * masterId + v])
12099 / timeStep()
12100 + fac0 * a_rightHandSide(masterId, v) - fac1 * a_rightHandSide(cellId, v);
12101
12102 a_rightHandSide(cellId, v) += delta;
12103 a_rightHandSide(masterId, v) -= delta;
12104 }
12105 } else {
12106 mTerm(1, AT_, "Not implemented yet!");
12107 const MFloat fac0 =
12108 a_cellVolume(cellId) / (a_cellVolume(cellId) + a_cellVolume(tripleLink) + a_cellVolume(masterId));
12109 const MFloat fac1 =
12110 a_cellVolume(tripleLink) / (a_cellVolume(cellId) + a_cellVolume(tripleLink) + a_cellVolume(masterId));
12111 const MFloat fac2 = F1 - fac0 - fac1;
12112 for(MInt v = 0; v < m_noCVars; v++) {
12113 MFloat delta =
12114 (fac2 * vol1[cellId] * oCVars[ydim * cellId + v] - fac0 * vol1[masterId] * oCVars[ydim * masterId + v])
12115 / timeStep()
12116 + fac0 * a_rightHandSide(masterId, v) - fac1 * a_rightHandSide(cellId, v);
12117
12118 a_rightHandSide(cellId, v) += delta;
12119 a_rightHandSide(masterId, v) -= delta;
12120 }
12121 }
12122 }
12123
12124 for(MInt i = xdim; i--;) {
12125 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
12126 if(a_isHalo(i)) {
12127 continue;
12128 }
12129 if(a_isBndryGhostCell(i)) {
12130 continue;
12131 }
12132
12133 IF_CONSTEXPR(timeStepMethod == 1) {
12134 ASSERT(a_localTimeStep(i) < std::numeric_limits<MFloat>::max() && a_localTimeStep(i) > 0,
12135 "Invalid local time-step for " + to_string(i) + " " + to_string(xdim));
12136 dt = m_RKalpha[m_RKStep] * a_localTimeStep(i);
12137 }
12138#ifdef _ALE_FORM_
12139 cVars[ydim * i + 0] = fVol[i] * (vol1[i] * oCVars[ydim * i + 0] - dt * RHS[ydim * i + 0]);
12140 cVars[ydim * i + 1] = fVol[i] * (vol1[i] * oCVars[ydim * i + 1] - dt * RHS[ydim * i + 1]);
12141 cVars[ydim * i + 2] = fVol[i] * (vol1[i] * oCVars[ydim * i + 2] - dt * RHS[ydim * i + 2]);
12142 cVars[ydim * i + 3] = fVol[i] * (vol1[i] * oCVars[ydim * i + 3] - dt * RHS[ydim * i + 3]);
12143 IF_CONSTEXPR(nDim == 3) {
12144 cVars[ydim * i + 4] = fVol[i] * (vol1[i] * oCVars[ydim * i + 4] - dt * RHS[ydim * i + 4]);
12145 }
12146
12147#else
12148 cVars[ydim * i + 0] = oCVars[ydim * i + 0] - dt * fVol[i] * RHS[ydim * i + 0];
12149 cVars[ydim * i + 1] = oCVars[ydim * i + 1] - dt * fVol[i] * RHS[ydim * i + 1];
12150 cVars[ydim * i + 2] = oCVars[ydim * i + 2] - dt * fVol[i] * RHS[ydim * i + 2];
12151 cVars[ydim * i + 3] = oCVars[ydim * i + 3] - dt * fVol[i] * RHS[ydim * i + 3];
12152 IF_CONSTEXPR(nDim == 3) { cVars[ydim * i + 4] = oCVars[ydim * i + 4] - dt * fVol[i] * RHS[ydim * i + 4]; }
12153#endif
12154 }
12155
12156 m_RKStep++;
12157
12158 updateSplitParentVariables();
12159
12160 if(m_RKStep < m_noRKSteps) {
12161 return false;
12162 } else {
12163 m_RKStep = 0;
12164 return true;
12165 }
12166}
12167
12168
12178template <MInt nDim, class SysEqn>
12179template <MInt timeStepMethod>
12181 TRACE();
12182
12183 NEW_TIMER_GROUP_STATIC(t_initTimer, "RK");
12184 NEW_TIMER_STATIC(t_timertotal, "RK", t_initTimer);
12185 NEW_SUB_TIMER_STATIC(t_init, "init", t_timertotal);
12186 NEW_SUB_TIMER_STATIC(t_exec, "exec", t_timertotal);
12187 NEW_SUB_TIMER_STATIC(t_finalize, "finalize", t_timertotal);
12188 RECORD_TIMER_START(t_timertotal);
12189 RECORD_TIMER_START(t_init);
12190
12191 MFloat* RESTRICT cVars = (MFloat*)(&(a_variable(0, 0)));
12192 MFloat* RESTRICT oCVars = (MFloat*)(&(a_oldVariable(0, 0)));
12193 MFloat* RESTRICT RHS = (MFloat*)(&(a_rightHandSide(0, 0)));
12194 MFloat* RESTRICT RHS0 = (MFloat*)(&(m_rhs0[0][0]));
12195 MFloat* RESTRICT fVol = (MFloat*)(&(a_FcellVolume(0)));
12196 MFloat* RESTRICT vol1 = (MFloat*)(&(m_cellVolumesDt1[0]));
12197 const MInt xdim = noInternalCells(); // a_noCells();
12198 const MInt ydim = m_noCVars;
12199 MFloat dt = timeStep();
12200
12201#ifdef _MB_DEBUG_
12202 const MInt gId = -1;
12203#endif
12204
12205#ifdef GEOM_CONS_LAW
12206 if(m_gclIntermediate) {
12207 const MInt noBCells = m_fvBndryCnd->m_bndryCells->size();
12208 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
12209 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
12210 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
12211
12212 const MFloat deltaVol = (m_RKStep == 0) ? m_sweptVolumeDt1[bndryId]
12213 : m_RKalpha[m_RKStep - 1] * m_sweptVolume[bndryId]
12214 + (F1 - m_RKalpha[m_RKStep - 1]) * m_sweptVolumeDt1[bndryId];
12215 a_cellVolume(cellId) = m_cellVolumesDt1[cellId] + deltaVol;
12216
12217 const MFloat V0 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume - 0.1 * grid().gridCellVolume(a_level(cellId));
12218 const MFloat V1 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume + 0.1 * grid().gridCellVolume(a_level(cellId));
12219 a_cellVolume(cellId) = mMin(V1, mMax(V0, a_cellVolume(cellId)));
12220
12221 a_cellVolume(cellId) = mMax(a_cellVolume(cellId), m_volumeThreshold);
12222 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
12223 }
12224 }
12225#endif
12226
12227 RECORD_TIMER_STOP(t_init);
12228 RECORD_TIMER_START(t_exec);
12229
12230 if(m_RKStep > 0) {
12231 const MFloat beta1 = m_RKalpha[m_RKStep - 1];
12232 const MFloat beta0 = F1 - beta1;
12233
12234 for(MInt i = xdim; i--;) {
12235 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
12236
12237 IF_CONSTEXPR(timeStepMethod == 1) { dt = timeStep() * FPOW2(maxLevel() - a_level(i)); }
12238
12239 cVars[ydim * i + 0] =
12240 fVol[i] * (vol1[i] * oCVars[ydim * i + 0] - dt * (beta1 * RHS[ydim * i + 0] + beta0 * RHS0[ydim * i + 0]));
12241 cVars[ydim * i + 1] =
12242 fVol[i] * (vol1[i] * oCVars[ydim * i + 1] - dt * (beta1 * RHS[ydim * i + 1] + beta0 * RHS0[ydim * i + 1]));
12243 cVars[ydim * i + 2] =
12244 fVol[i] * (vol1[i] * oCVars[ydim * i + 2] - dt * (beta1 * RHS[ydim * i + 2] + beta0 * RHS0[ydim * i + 2]));
12245 cVars[ydim * i + 3] =
12246 fVol[i] * (vol1[i] * oCVars[ydim * i + 3] - dt * (beta1 * RHS[ydim * i + 3] + beta0 * RHS0[ydim * i + 3]));
12247 IF_CONSTEXPR(nDim == 3) {
12248 cVars[ydim * i + 4] =
12249 fVol[i] * (vol1[i] * oCVars[ydim * i + 4] - dt * (beta1 * RHS[ydim * i + 4] + beta0 * RHS0[ydim * i + 4]));
12250
12251 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
12252 for(MInt r = 0; r < m_noRansEquations; ++r) {
12253 cVars[ydim * i + 5 + r] = fVol[i]
12254 * (vol1[i] * oCVars[ydim * i + 5 + r]
12255 - dt * (beta1 * RHS[ydim * i + 5 + r] + beta0 * RHS0[ydim * i + 5 + r]));
12256 }
12257 }
12258
12259 for(MInt s = 0; s < m_noSpecies; s++)
12260 cVars[ydim * i + 5 + s + m_noRansEquations] =
12261 fVol[i]
12262 * (vol1[i] * oCVars[ydim * i + 5 + s + m_noRansEquations]
12263 - dt
12264 * (beta1 * RHS[ydim * i + 5 + s + m_noRansEquations]
12265 + beta0 * RHS0[ydim * i + 5 + s + m_noRansEquations]));
12266 }
12267 else {
12268 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
12269 for(MInt r = 0; r < m_noRansEquations; ++r) {
12270 cVars[ydim * i + 4 + r] = fVol[i]
12271 * (vol1[i] * oCVars[ydim * i + 4 + r]
12272 - dt * (beta1 * RHS[ydim * i + 4 + r] + beta0 * RHS0[ydim * i + 4 + r]));
12273 }
12274 }
12275
12276 for(MInt s = 0; s < m_noSpecies; s++)
12277 cVars[ydim * i + 4 + s + m_noRansEquations] =
12278 fVol[i]
12279 * (vol1[i] * oCVars[ydim * i + 4 + s + m_noRansEquations]
12280 - dt
12281 * (beta1 * RHS[ydim * i + 4 + s + m_noRansEquations]
12282 + beta0 * RHS0[ydim * i + 4 + s + m_noRansEquations]));
12283 }
12284
12285
12286#ifdef _MB_DEBUG_
12287 if(gId > -1 && c_globalId(i) == gId)
12288 cerr << globalTimeStep << " " << m_RKStep << " RK update " << gId << " " << fVol[i] << " " << vol1[i] << " "
12289 << fVol[i] * vol1[i] << " / " << cVars[ydim * i + 0] << " " << cVars[ydim * i + 1] << " "
12290 << cVars[ydim * i + 2] << " " << cVars[ydim * i + 3] << " " << cVars[ydim * i + 4] << " / "
12291 << oCVars[ydim * i + 0] << " " << oCVars[ydim * i + 1] << " " << oCVars[ydim * i + 2] << " "
12292 << oCVars[ydim * i + 3] << " " << oCVars[ydim * i + 4] << endl;
12293#endif
12294 }
12295
12296 } else {
12297 ASSERT(m_RKStep == 0, "");
12298 for(MInt i = xdim; i--;) {
12299 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
12300
12301 IF_CONSTEXPR(timeStepMethod == 1) { dt = timeStep() * FPOW2(maxLevel() - a_level(i)); }
12302
12303 cVars[ydim * i + 0] = fVol[i] * (vol1[i] * oCVars[ydim * i + 0] - dt * RHS0[ydim * i + 0]);
12304 cVars[ydim * i + 1] = fVol[i] * (vol1[i] * oCVars[ydim * i + 1] - dt * RHS0[ydim * i + 1]);
12305 cVars[ydim * i + 2] = fVol[i] * (vol1[i] * oCVars[ydim * i + 2] - dt * RHS0[ydim * i + 2]);
12306 cVars[ydim * i + 3] = fVol[i] * (vol1[i] * oCVars[ydim * i + 3] - dt * RHS0[ydim * i + 3]);
12307 IF_CONSTEXPR(nDim == 3) {
12308 cVars[ydim * i + 4] = fVol[i] * (vol1[i] * oCVars[ydim * i + 4] - dt * RHS0[ydim * i + 4]);
12309 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
12310 for(MInt r = 0; r < m_noRansEquations; ++r) {
12311 cVars[ydim * i + 5 + r] = fVol[i] * (vol1[i] * oCVars[ydim * i + 5 + r] - dt * RHS0[ydim * i + 5 + r]);
12312 }
12313 }
12314
12315 for(MInt s = 0; s < m_noSpecies; s++)
12316 cVars[ydim * i + 5 + s + m_noRansEquations] = fVol[i]
12317 * (vol1[i] * oCVars[ydim * i + 5 + s + m_noRansEquations]
12318 - dt * RHS0[ydim * i + 5 + s + m_noRansEquations]);
12319 }
12320 else {
12321 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
12322 for(MInt r = 0; r < m_noRansEquations; ++r) {
12323 cVars[ydim * i + 4 + r] = fVol[i] * (vol1[i] * oCVars[ydim * i + 4 + r] - dt * RHS0[ydim * i + 4 + r]);
12324 }
12325 }
12326 for(MInt s = 0; s < m_noSpecies; s++)
12327 cVars[ydim * i + 4 + s + m_noRansEquations] = fVol[i]
12328 * (vol1[i] * oCVars[ydim * i + 4 + s + m_noRansEquations]
12329 - dt * RHS0[ydim * i + 4 + s + m_noRansEquations]);
12330 }
12331#ifdef _MB_DEBUG_
12332 if(gId > -1 && c_globalId(i) == gId)
12333 cerr << globalTimeStep << " " << m_RKStep << " RK update " << gId << " " << fVol[i] << " " << vol1[i] << " "
12334 << fVol[i] * vol1[i] << " / " << cVars[ydim * i + 0] << " " << cVars[ydim * i + 1] << " "
12335 << cVars[ydim * i + 2] << " " << cVars[ydim * i + 3] << " " << cVars[ydim * i + 4] << " / "
12336 << oCVars[ydim * i + 0] << " " << oCVars[ydim * i + 1] << " " << oCVars[ydim * i + 2] << " "
12337 << oCVars[ydim * i + 3] << " " << oCVars[ydim * i + 4] << endl;
12338#endif
12339 }
12340 }
12341 RECORD_TIMER_STOP(t_exec);
12342 RECORD_TIMER_START(t_finalize);
12343
12344 updateLinkedCells();
12345 m_RKStep++;
12346
12347 RECORD_TIMER_STOP(t_finalize);
12348 RECORD_TIMER_STOP(t_timertotal);
12349
12350 if(m_RKStep < m_noRKSteps) {
12351 return false;
12352 } else {
12353 m_RKStep = 0;
12354 return true;
12355 }
12356}
12357
12358
12364template <MInt nDim, class SysEqn>
12366 TRACE();
12367
12368 MFloat* RESTRICT cVars = (MFloat*)(&(a_variable(0, 0)));
12369 MFloat* RESTRICT oCVars = (MFloat*)(&(a_oldVariable(0, 0)));
12370 MFloat* RESTRICT RHS = (MFloat*)(&(a_rightHandSide(0, 0)));
12371 MFloat* RESTRICT RHS0 = (MFloat*)(&(m_rhs0[0][0]));
12372 MFloat* RESTRICT fVol = (MFloat*)(&(a_FcellVolume(0)));
12373 MFloat* RESTRICT vol1 = (MFloat*)(&(m_cellVolumesDt1[0]));
12374 const MInt xdim = noInternalCells(); // a_noCells();
12375 const MInt ydim = m_noCVars;
12376
12377#ifdef _MB_DEBUG_
12378 const MInt gId = -1;
12379#endif
12380
12381#ifdef GEOM_CONS_LAW
12382 if(m_gclIntermediate) {
12383 const MInt noBCells = m_fvBndryCnd->m_bndryCells->size();
12384 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
12385 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
12386 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
12387 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
12388 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
12389
12390 const MFloat deltaVol = (m_RKStep == 0) ? m_sweptVolumeDt1[bndryId]
12391 : m_RKalpha[m_RKStep - 1] * m_sweptVolume[bndryId]
12392 + (F1 - m_RKalpha[m_RKStep - 1]) * m_sweptVolumeDt1[bndryId];
12393 a_cellVolume(cellId) = m_cellVolumesDt1[cellId] + deltaVol;
12394
12395 const MFloat V0 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume - 0.1 * grid().gridCellVolume(a_level(cellId));
12396 const MFloat V1 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume + 0.1 * grid().gridCellVolume(a_level(cellId));
12397 a_cellVolume(cellId) = mMin(V1, mMax(V0, a_cellVolume(cellId)));
12398
12399 a_cellVolume(cellId) = mMax(a_cellVolume(cellId), m_volumeThreshold);
12400 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
12401 }
12402 }
12403#endif
12404
12405 if(m_RKStep > 0) {
12406 const MFloat beta1 = m_RKalpha[m_RKStep - 1];
12407 const MFloat beta0 = F1 - beta1;
12408
12409 for(MInt i = xdim; i--;) {
12410 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
12411 const MFloat dt = timeStep() * FPOW2(maxRefinementLevel() - a_level(i));
12412 cVars[ydim * i + 0] =
12413 fVol[i] * (vol1[i] * oCVars[ydim * i + 0] - dt * (beta1 * RHS[ydim * i + 0] + beta0 * RHS0[ydim * i + 0]));
12414 cVars[ydim * i + 1] =
12415 fVol[i] * (vol1[i] * oCVars[ydim * i + 1] - dt * (beta1 * RHS[ydim * i + 1] + beta0 * RHS0[ydim * i + 1]));
12416 cVars[ydim * i + 2] =
12417 fVol[i] * (vol1[i] * oCVars[ydim * i + 2] - dt * (beta1 * RHS[ydim * i + 2] + beta0 * RHS0[ydim * i + 2]));
12418 cVars[ydim * i + 3] =
12419 fVol[i] * (vol1[i] * oCVars[ydim * i + 3] - dt * (beta1 * RHS[ydim * i + 3] + beta0 * RHS0[ydim * i + 3]));
12420 IF_CONSTEXPR(nDim == 3) {
12421 cVars[ydim * i + 4] =
12422 fVol[i] * (vol1[i] * oCVars[ydim * i + 4] - dt * (beta1 * RHS[ydim * i + 4] + beta0 * RHS0[ydim * i + 4]));
12423 }
12424#ifdef _MB_DEBUG_
12425 if(gId > -1 && c_globalId(i) == gId)
12426 cerr << globalTimeStep << " " << m_RKStep << " RK update " << gId << " " << cVars[ydim * i + 0] << " "
12427 << cVars[ydim * i + 1] << " " << cVars[ydim * i + 2] << " " << cVars[ydim * i + 3] << " "
12428 << cVars[ydim * i + 4] << endl;
12429#endif
12430 }
12431
12432 } else {
12433 ASSERT(m_RKStep == 0, "");
12434 for(MInt i = xdim; i--;) {
12435 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
12436 const MFloat dt = timeStep() * FPOW2(maxRefinementLevel() - a_level(i));
12437 cVars[ydim * i + 0] = fVol[i] * (vol1[i] * oCVars[ydim * i + 0] - dt * RHS0[ydim * i + 0]);
12438 cVars[ydim * i + 1] = fVol[i] * (vol1[i] * oCVars[ydim * i + 1] - dt * RHS0[ydim * i + 1]);
12439 cVars[ydim * i + 2] = fVol[i] * (vol1[i] * oCVars[ydim * i + 2] - dt * RHS0[ydim * i + 2]);
12440 cVars[ydim * i + 3] = fVol[i] * (vol1[i] * oCVars[ydim * i + 3] - dt * RHS0[ydim * i + 3]);
12441 IF_CONSTEXPR(nDim == 3) {
12442 cVars[ydim * i + 4] = fVol[i] * (vol1[i] * oCVars[ydim * i + 4] - dt * RHS0[ydim * i + 4]);
12443 }
12444#ifdef _MB_DEBUG_
12445 if(gId > -1 && c_globalId(i) == gId)
12446 cerr << globalTimeStep << " " << m_RKStep << " RK update " << gId << " " << cVars[ydim * i + 0] << " "
12447 << cVars[ydim * i + 1] << " " << cVars[ydim * i + 2] << " " << cVars[ydim * i + 3] << " "
12448 << cVars[ydim * i + 4] << endl;
12449#endif
12450 }
12451 }
12452
12453 updateLinkedCells();
12454
12455 m_RKStep++;
12456
12457 if(m_RKStep < m_noRKSteps) {
12458 return false;
12459 } else {
12460 m_RKStep = 0;
12461 return true;
12462 }
12463}
12464
12465
12471template <MInt nDim, class SysEqn>
12473 MFloat* RESTRICT cVars = (MFloat*)(&(a_variable(0, 0)));
12474 const MInt ydim = m_noCVars;
12475 const MUint noCVars = (MUint)m_noCVars;
12476
12477 MIntScratchSpace haloBufferCnts(mMax(1, noNeighborDomains()), AT_, "haloBufferCnts");
12478 MIntScratchSpace windowBufferCnts(mMax(1, noNeighborDomains()), AT_, "windowBufferCnts");
12479 MIntScratchSpace haloBufferOffsets(noNeighborDomains() + 1, AT_, "haloBufferOffsets");
12480 MIntScratchSpace windowBufferOffsets(noNeighborDomains() + 1, AT_, "windowBufferOffsets");
12481 ScratchSpace<MPI_Request> haloReq(mMax(1, noNeighborDomains()), AT_, "haloReq");
12482 ScratchSpace<MPI_Request> windowReq(mMax(1, noNeighborDomains()), AT_, "windowReq");
12483
12484 MInt haloSize = 0;
12485 MInt windowSize = 0;
12486 haloBufferCnts.fill(0);
12487 windowBufferCnts.fill(0);
12488 haloBufferOffsets.fill(0);
12489 windowBufferOffsets.fill(0);
12490
12491 for(MInt i = 0; i < noNeighborDomains(); i++) {
12492 haloBufferCnts(i) = m_noCVars * (signed)m_linkedHaloCells[i].size();
12493 windowBufferCnts(i) = m_noCVars * (signed)m_linkedWindowCells[i].size();
12494 haloBufferOffsets(i + 1) = haloBufferOffsets(i) + haloBufferCnts(i);
12495 windowBufferOffsets(i + 1) = windowBufferOffsets(i) + windowBufferCnts(i);
12496 haloSize += haloBufferCnts(i);
12497 windowSize += windowBufferCnts(i);
12498 }
12499
12500 MFloatScratchSpace haloBuffer(haloSize, AT_, "haloBuffer");
12501 MFloatScratchSpace windowBuffer(windowSize, AT_, "windowBuffer");
12502
12503 updateSplitParentVariables();
12504
12505 haloReq.fill(MPI_REQUEST_NULL);
12506 windowReq.fill(MPI_REQUEST_NULL);
12507 for(MInt i = 0; i < noNeighborDomains(); i++) {
12508 if(m_linkedWindowCells[i].empty()) continue;
12509 for(MInt j = 0; j < (signed)m_linkedWindowCells[i].size(); j++) {
12510 MInt cellId = m_linkedWindowCells[i][j];
12511 MInt offset = windowBufferOffsets(i) + noCVars * j;
12512 for(MInt v = 0; v < (signed)noCVars; v++) {
12513 windowBuffer(offset + v) = a_variable(cellId, v);
12514 }
12515 }
12516 }
12517 MInt windowCnt = 0;
12518 MInt haloCnt = 0;
12519 if(m_nonBlockingComm) {
12520 for(MInt i = 0; i < noNeighborDomains(); i++) {
12521 if(haloBufferCnts(i) == 0) continue;
12522 MPI_Irecv(&haloBuffer[haloBufferOffsets[i]], haloBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 23, mpiComm(),
12523 &haloReq[haloCnt], AT_, "haloBuffer[haloBufferOffsets[i]]");
12524 haloCnt++;
12525 }
12526 for(MInt i = 0; i < noNeighborDomains(); i++) {
12527 if(windowBufferCnts(i) == 0) continue;
12528 MPI_Isend(&windowBuffer[windowBufferOffsets[i]], windowBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 23,
12529 mpiComm(), &windowReq[windowCnt], AT_, "windowBuffer[windowBufferOffsets[i]]");
12530 windowCnt++;
12531 }
12532 if(haloCnt > 0) MPI_Waitall(haloCnt, &haloReq[0], MPI_STATUSES_IGNORE, AT_);
12533 } else {
12534 for(MInt i = 0; i < noNeighborDomains(); i++) {
12535 if(windowBufferCnts(i) == 0) continue;
12536 MPI_Issend(&windowBuffer[windowBufferOffsets[i]], windowBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 23,
12537 mpiComm(), &windowReq[windowCnt], AT_, "windowBuffer[windowBufferOffsets[i]]");
12538 windowCnt++;
12539 }
12540 for(MInt i = 0; i < noNeighborDomains(); i++) {
12541 if(haloBufferCnts(i) == 0) continue;
12542 MPI_Recv(&haloBuffer[haloBufferOffsets[i]], haloBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 23, mpiComm(),
12543 MPI_STATUS_IGNORE, AT_, "haloBuffer[haloBufferOffsets[i]]");
12544 haloCnt++;
12545 }
12546 }
12547 for(MInt i = 0; i < noNeighborDomains(); i++) {
12548 if(m_linkedHaloCells[i].empty()) continue;
12549 for(MInt j = 0; j < (signed)m_linkedHaloCells[i].size(); j++) {
12550 MInt cellId = m_linkedHaloCells[i][j];
12551 MInt offset = haloBufferOffsets(i) + noCVars * j;
12552 for(MInt v = 0; v < (signed)noCVars; v++) {
12553 a_variable(cellId, v) = haloBuffer(offset + v);
12554 }
12555 }
12556 }
12557 if(windowCnt > 0) MPI_Waitall(windowCnt, &windowReq[0], MPI_STATUSES_IGNORE, AT_);
12558
12559 if(grid().azimuthalPeriodicity()) {
12560 exchangeLinkedHaloCellsForAzimuthalReconstruction();
12561 azimuthalNearBoundaryExchange();
12562 }
12563
12564 for(MUint it = 0; it < m_temporarilyLinkedCells.size(); it++) {
12565 const MInt cellId = get<0>(m_temporarilyLinkedCells[it]);
12566 const MInt masterId = get<1>(m_temporarilyLinkedCells[it]);
12567 const MInt tripleLink = get<2>(m_temporarilyLinkedCells[it]);
12568 if(tripleLink < 0) {
12569 const MFloat fac0 = a_cellVolume(cellId) / (a_cellVolume(cellId) + a_cellVolume(masterId));
12570 const MFloat fac1 = F1 - fac0;
12571 if(false && m_RKStep == 0) {
12572 for(MInt v = 0; v < m_noCVars; v++) {
12573 const MFloat var = fac1 * cVars[ydim * masterId + v];
12574 cVars[ydim * cellId + v] = var;
12575 cVars[ydim * masterId + v] = var;
12576 }
12577 } else {
12578 for(MInt v = 0; v < m_noCVars; v++) {
12579 // If two emerged cells share the same master cell, this formulation is incorrect!
12580 // If the order of the cells changes, e.g., when during DLB one of the cells becomes a halo cell, this even
12581 // results in different solutions.
12582 const MFloat var = fac0 * cVars[ydim * cellId + v] + fac1 * cVars[ydim * masterId + v];
12583 cVars[ydim * cellId + v] = var;
12584 cVars[ydim * masterId + v] = var;
12585 }
12586
12587 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) {
12588 vector<MInt>::iterator it0 = find(m_splitCells.begin(), m_splitCells.end(), cellId);
12589 if(it0 == m_splitCells.end()) mTerm(1, AT_, "split cells inconsistency.");
12590 const MInt pos = distance(m_splitCells.begin(), it0);
12591 ASSERT(m_splitCells[pos] == cellId, "");
12592 for(MUint s = 0; s < m_splitChilds[pos].size(); s++) {
12593 MInt splitChildId = m_splitChilds[pos][s];
12594 for(MInt v = 0; v < m_noCVars; v++) {
12595 cVars[ydim * splitChildId + v] = cVars[ydim * cellId + v];
12596 }
12597 }
12598 }
12599 if(a_hasProperty(masterId, SolverCell::IsSplitCell)) {
12600 vector<MInt>::iterator it0 = find(m_splitCells.begin(), m_splitCells.end(), masterId);
12601 if(it0 == m_splitCells.end()) mTerm(1, AT_, "split cells inconsistency.");
12602 const MInt pos = distance(m_splitCells.begin(), it0);
12603 ASSERT(m_splitCells[pos] == masterId, "");
12604 for(MUint s = 0; s < m_splitChilds[pos].size(); s++) {
12605 MInt splitChildId = m_splitChilds[pos][s];
12606 for(MInt v = 0; v < m_noCVars; v++) {
12607 cVars[ydim * splitChildId + v] = cVars[ydim * masterId + v];
12608 }
12609 }
12610 }
12611 }
12612 } else {
12613 // triple-Links
12614 const MFloat fac0 =
12615 a_cellVolume(cellId) / (a_cellVolume(cellId) + a_cellVolume(tripleLink) + a_cellVolume(masterId));
12616 const MFloat fac1 =
12617 a_cellVolume(tripleLink) / (a_cellVolume(cellId) + a_cellVolume(tripleLink) + a_cellVolume(masterId));
12618 const MFloat fac2 = F1 - fac0 - fac1;
12619
12620 for(MInt v = 0; v < m_noCVars; v++) {
12621 const MFloat var =
12622 fac0 * cVars[ydim * cellId + v] + fac1 * cVars[ydim * tripleLink + v] + fac2 * cVars[ydim * tripleLink + v];
12623 cVars[ydim * cellId + v] = var;
12624 cVars[ydim * tripleLink + v] = var;
12625 cVars[ydim * masterId + v] = var;
12626 }
12627
12628 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) {
12629 vector<MInt>::iterator it0 = find(m_splitCells.begin(), m_splitCells.end(), cellId);
12630 if(it0 == m_splitCells.end()) mTerm(1, AT_, "split cells inconsistency.");
12631 const MInt pos = distance(m_splitCells.begin(), it0);
12632 ASSERT(m_splitCells[pos] == cellId, "");
12633 for(MUint s = 0; s < m_splitChilds[pos].size(); s++) {
12634 MInt splitChildId = m_splitChilds[pos][s];
12635 for(MInt v = 0; v < m_noCVars; v++) {
12636 cVars[ydim * splitChildId + v] = cVars[ydim * cellId + v];
12637 }
12638 }
12639 }
12640 if(a_hasProperty(masterId, SolverCell::IsSplitCell)) {
12641 vector<MInt>::iterator it0 = find(m_splitCells.begin(), m_splitCells.end(), masterId);
12642 if(it0 == m_splitCells.end()) mTerm(1, AT_, "split cells inconsistency.");
12643 const MInt pos = distance(m_splitCells.begin(), it0);
12644 ASSERT(m_splitCells[pos] == masterId, "");
12645 for(MUint s = 0; s < m_splitChilds[pos].size(); s++) {
12646 MInt splitChildId = m_splitChilds[pos][s];
12647 for(MInt v = 0; v < m_noCVars; v++) {
12648 cVars[ydim * splitChildId + v] = cVars[ydim * masterId + v];
12649 }
12650 }
12651 }
12652 if(a_hasProperty(tripleLink, SolverCell::IsSplitCell)) {
12653 vector<MInt>::iterator it0 = find(m_splitCells.begin(), m_splitCells.end(), tripleLink);
12654 if(it0 == m_splitCells.end()) mTerm(1, AT_, "split cells inconsistency.");
12655 const MInt pos = distance(m_splitCells.begin(), it0);
12656 ASSERT(m_splitCells[pos] == tripleLink, "");
12657 for(MUint s = 0; s < m_splitChilds[pos].size(); s++) {
12658 MInt splitChildId = m_splitChilds[pos][s];
12659 for(MInt v = 0; v < m_noCVars; v++) {
12660 cVars[ydim * splitChildId + v] = cVars[ydim * tripleLink + v];
12661 }
12662 }
12663 }
12664 }
12665 }
12666}
12667
12668
12673template <MInt nDim, class SysEqn>
12675 TRACE();
12676
12677 m_fvBndryCnd->copyVarsToSmallCells();
12678}
12679
12680
12685template <MInt nDim, class SysEqn>
12687 switch(i) {
12688 case 0:
12689 return "RHO_U";
12690 case 1:
12691 return "RHO_V";
12692 case 2:
12693 IF_CONSTEXPR(nDim == 2)
12694 return "RHO_E";
12695 else
12696 return "RHO_W";
12697 case 3:
12698 IF_CONSTEXPR(nDim == 2)
12699 return "RHO";
12700 else
12701 return "RHO_E";
12702 case 4:
12703 IF_CONSTEXPR(nDim == 2)
12704 return "<< INVALID INDEX FOR CONSERVATIVE VAR >>";
12705 else
12706 return "RHO";
12707 default:
12708 return "<< INVALID INDEX FOR CONSERVATIVE VAR >>";
12709 }
12710}
12711
12712
12717template <MInt nDim, class SysEqn>
12719 switch(i) {
12720 case 0:
12721 return "U";
12722 case 1:
12723 return "V";
12724 case 2:
12725 IF_CONSTEXPR(nDim == 2)
12726 return "RHO";
12727 else
12728 return "W";
12729 case 3:
12730 IF_CONSTEXPR(nDim == 2)
12731 return "P";
12732 else
12733 return "RHO";
12734 case 4:
12735 IF_CONSTEXPR(nDim == 2)
12736 return "<< INVALID INDEX FOR CONSERVATIVE VAR >>";
12737 else
12738 return "P";
12739 default:
12740 return "<< INVALID INDEX FOR CONSERVATIVE VAR >>";
12741 }
12742}
12743
12744
12749template <MInt nDim, class SysEqn>
12751 TRACE();
12752
12753 if(!m_logBoundaryData && !forceOutput) return;
12754 if(m_noLsMbBndryCells == 0) return;
12755 IF_CONSTEXPR(nDim == 3) return;
12756
12757 MInt cellId;
12758 const MFloat xOffset = m_bodyCenter[0];
12759 const MFloat yOffset = m_bodyCenter[1];
12760 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
12761 const MFloat radToDeg = 360.0 / (2.0 * PI);
12762 MFloat dist;
12763 MFloat shear[nDim];
12764 MFloat gradV[nDim][nDim];
12765 MFloat gradP[nDim];
12766 MFloat angle, u, v, cp, ma, vorticity, tmp; //, angle2;
12767 MFloat rhoU2 = F0;
12768 for(MInt i = 0; i < nDim; i++) {
12769 rhoU2 += POW2(m_VVInfinity[i]);
12770 }
12771 rhoU2 *= m_rhoInfinity;
12772
12773 MInt iTmp;
12774 MFloat fTmp;
12775 MInt noCells;
12776 MBool centerLine;
12777 ScratchSpace<MInt> sortedList(m_noLsMbBndryCells, AT_, "sortedList");
12778 ScratchSpace<MFloat> sortedAngle(m_noLsMbBndryCells, AT_, "sortedAngle");
12779
12780 noCells = 0;
12781
12782 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++) {
12783 cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
12784 centerLine = false;
12785 IF_CONSTEXPR(nDim == 3) {
12786 if(a_coordinate(cellId, 2) >= F0 && a_hasNeighbor(cellId, 4) > 0
12787 && a_coordinate(c_neighborId(cellId, 4), 2) < F0) {
12788 centerLine = true;
12789 }
12790 }
12791 IF_CONSTEXPR(nDim == 3) {
12792 if(!centerLine) continue;
12793 }
12794
12795 angle = F0;
12796 if(a_coordinate(cellId, 1) - yOffset > 0 && a_coordinate(cellId, 0) - xOffset > 0) {
12797 angle = 180 - radToDeg * atan((a_coordinate(cellId, 1) - yOffset) / (a_coordinate(cellId, 0) - xOffset));
12798 } else if(a_coordinate(cellId, 1) - yOffset > 0 && a_coordinate(cellId, 0) - xOffset < 0) {
12799 angle = -radToDeg * atan((a_coordinate(cellId, 1) - yOffset) / (a_coordinate(cellId, 0) - xOffset));
12800 } else if(a_coordinate(cellId, 1) - yOffset < 0 && a_coordinate(cellId, 0) - xOffset > 0) {
12801 angle = 180.0 - radToDeg * atan((a_coordinate(cellId, 1) - yOffset) / (a_coordinate(cellId, 0) - xOffset));
12802 } else {
12803 angle = 360.0 - radToDeg * atan((a_coordinate(cellId, 1) - yOffset) / (a_coordinate(cellId, 0) - xOffset));
12804 }
12805
12806 MFloat dx = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[0] - xOffset;
12807 MFloat dy = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[1] - yOffset;
12808 angle = 180.0 - (radToDeg * atan2(dy, dx));
12809
12810 sortedAngle.p[noCells] = angle;
12811 sortedList.p[noCells] = cellId;
12812 noCells++;
12813 }
12814
12815 for(MInt i = 0; i < noCells - 1; i++) {
12816 for(MInt j = i + 1; j < noCells; j++) {
12817 if(sortedAngle.p[j] < sortedAngle.p[i]) {
12818 iTmp = sortedList.p[i];
12819 sortedList.p[i] = sortedList.p[j];
12820 sortedList.p[j] = iTmp;
12821 fTmp = sortedAngle.p[i];
12822 sortedAngle.p[i] = sortedAngle.p[j];
12823 sortedAngle.p[j] = fTmp;
12824 }
12825 }
12826 }
12827
12828
12829 ofstream ofl2;
12830 ofl2.open(fileName);
12831 if(ofl2.is_open() && ofl2.good()) {
12832 for(MInt c = 0; c < noCells; c++) {
12833 cellId = sortedList.p[c];
12834
12835 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
12836 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
12837 if(a_isHalo(cellId)) continue;
12838 if(a_isPeriodic(cellId)) continue;
12839
12840 MInt bndryId = a_bndryId(cellId);
12841 angle = sortedAngle.p[c];
12842 MFloat rhoSurface = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->RHO];
12843 MFloat pSurface = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->P];
12844 MFloat T = sysEqn().temperature_ES(rhoSurface, pSurface);
12845 MFloat mue = SUTHERLANDLAW(T);
12846
12847 dist = F0;
12848 for(MInt i = 0; i < nDim; i++) {
12849 dist += (a_coordinate(cellId, i) - m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[i])
12850 * m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i];
12851 }
12852 dist = fabs(dist);
12853
12854 MFloat shear2[3] = {F0, F0, F0};
12855 for(MInt i = 0; i < nDim; i++) {
12856 MFloat grad = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_normalDeriv[PV->VV[i]];
12857 shear[i] = mue * grad;
12858 }
12859
12860 MFloat cf = (m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[1] * shear[0]
12861 - m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0] * shear[1])
12862 / (F1B2 * rhoU2 * m_referenceLength * sysEqn().m_Re0);
12863
12864 u = a_pvariable(cellId, PV->VV[0]);
12865 v = a_pvariable(cellId, PV->VV[1]);
12866 ma = sqrt(u * u + v * v);
12867 ma /= sysEqn().speedOfSound(rhoSurface, pSurface);
12868 cp = (pSurface - m_PInfinity) / (F1B2 * rhoU2);
12869
12870 MFloat dudn[nDim];
12871 MFloat nablaPhi[nDim];
12872 MFloat nablaAbs = F0;
12873 for(MInt i = 0; i < nDim; i++) {
12874 nablaPhi[i] = (a_levelSetValuesMb(c_neighborId(cellId, 2 * i + 1), 0)
12875 - a_levelSetValuesMb(c_neighborId(cellId, 2 * i), 0))
12876 / (F2 * c_cellLengthAtLevel(a_level(cellId)));
12877 nablaAbs += POW2(nablaPhi[i]);
12878 }
12879 nablaAbs = sqrt(nablaAbs);
12880 for(MInt i = 0; i < nDim; i++) {
12881 nablaPhi[i] /= nablaAbs;
12882 }
12883
12884 for(MInt i = 0; i < nDim; i++) {
12885 for(MInt j = 0; j < nDim; j++) {
12886 gradV[i][j] = F0;
12887 }
12888 gradP[i] = F0;
12889 dudn[i] = F0;
12890 }
12891
12892 MFloat dundn = F0;
12893 for(MInt i = 0; i < nDim; i++) {
12894 dudn[i] = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_normalDeriv[PV->VV[i]];
12895 }
12896
12897 tmp = F0;
12898 for(MInt i = 0; i < nDim; i++) {
12899 tmp += m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] * gradP[i];
12900 }
12901 for(MInt i = 0; i < nDim; i++) {
12902 gradP[1] = -m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0] * gradP[1]
12903 + m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[1] * gradP[0];
12904 }
12905 gradP[0] = tmp;
12906
12907 MFloat u2 = m_bodyVelocity[0];
12908 MFloat v2 = m_bodyVelocity[1];
12909 for(MInt j = 0; j < nDim; j++) {
12910 u2 += 0.5 * c_cellLengthAtLevel(maxRefinementLevel())
12911 * m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[j] * 0.5
12912 * (a_slope(cellId, PV->U, j) + gradV[PV->U][j]);
12913 v2 += 0.5 * c_cellLengthAtLevel(maxRefinementLevel())
12914 * m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[j] * 0.5
12915 * (a_slope(cellId, PV->V, j) + gradV[PV->V][j]);
12916 }
12917
12918
12919 vorticity = (gradV[1][0] - gradV[0][1]) / m_UInfinity;
12920
12921 MFloat bodyRotation[3] = {0};
12922 getBodyRotation(0, bodyRotation);
12923
12924 const MFloat p0 = a_coordinate(cellId, 0);
12925 const MFloat q0 = a_coordinate(cellId, 1);
12926 const MFloat p = cos(-bodyRotation[2]) * p0 - sin(-bodyRotation[2]) * q0 + F1B4;
12927
12928 ofl2 << cellId << " "; // 1
12929 ofl2 << angle << " "; // 2
12930 ofl2 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume << " "; // 3
12931 ofl2 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_area << " "; // 4
12932 ofl2 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[0] << " "; // 5
12933 ofl2 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[1] << " "; // 6
12934 ofl2 << m_volumeFraction[bndryId] << " "; // 7
12935 ofl2 << dist << " "; // 8
12936 ofl2 << pSurface << " "; // 9
12937 ofl2 << rhoSurface << " "; // 10
12938 ofl2 << cp << " "; // 11
12939 ofl2 << shear[0] << " "; // 12
12940 ofl2 << shear[1] << " "; // 13
12941 ofl2 << a_pvariable(cellId, PV->P) << " "; // 14
12942 ofl2 << vorticity << " "; // 15
12943 ofl2 << gradP[0] << " "; // 18
12944 ofl2 << gradP[1] << " "; // 19
12945 ofl2 << dudn[0] << " "; // 20
12946 ofl2 << dudn[1] << " "; // 21
12947 ofl2 << (u - m_bodyVelocity[0]) / dist << " "; // 22
12948 ofl2 << (v - m_bodyVelocity[1]) / dist << " "; // 23
12949 // ofl2 << (u-m_bodyVelocity[0])/getLevelSetValueSphere(cellId) << " "; //24
12950 ofl2 << (u2 - m_bodyVelocity[0]) / (0.5 * c_cellLengthAtLevel(maxRefinementLevel())) << " "; // 25
12951 ofl2 << (v2 - m_bodyVelocity[1]) / (0.5 * c_cellLengthAtLevel(maxRefinementLevel())) << " "; // 26
12952 ofl2 << dundn << " "; // 27
12953 ofl2 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[0] << " "; // 28
12954 ofl2 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates[1] << " "; // 29
12955 ofl2 << shear2[0] << " "; // 30
12956 ofl2 << shear2[1] << " "; // 31
12957 ofl2 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->U] << " "; // 32
12958 ofl2 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->V] << " "; // 33
12959 ofl2 << a_coordinate(cellId, 0) << " "; // 34
12960 ofl2 << a_coordinate(cellId, 1) << " "; // 35
12961 ofl2 << cf << " "; // 36
12962 ofl2 << p << " "; // 37
12963 ofl2 << globalTimeStep << " "; // 38
12964 ofl2 << nablaPhi[0] << " "; // 39
12965 ofl2 << nablaPhi[1] << " "; // 40
12966 ofl2 << endl;
12967 }
12968
12969 ofl2.close();
12970 ofl2.clear();
12971 } else {
12972 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing!" << endl;
12973 }
12974}
12975
12976
12982template <MInt nDim, class SysEqn>
12984 TRACE();
12985
12986 NEW_TIMER_GROUP_STATIC(t_bodyTimer, "computeBodySurfaceData");
12987 NEW_TIMER_STATIC(t_timertotal, "computeBodySurfaceData", t_bodyTimer);
12988 NEW_SUB_TIMER_STATIC(t_local, "localForce", t_timertotal);
12989 NEW_SUB_TIMER_STATIC(t_reduce, "reduce", t_timertotal);
12990 NEW_SUB_TIMER_STATIC(t_collision, "collision", t_timertotal);
12991 RECORD_TIMER_START(t_timertotal);
12992 RECORD_TIMER_START(t_local);
12993
12994 // bodyForce:nDim, bodyTorque:3, bodyHeatFlux:1
12995 MBool returnCoeffs = false;
12996 MInt noValues = nDim + 3 + 1;
12997 MInt noReturnCoeffs = nDim;
12998
12999 if(pressureForce != nullptr) {
13000 returnCoeffs = true;
13001 noValues += noReturnCoeffs;
13002 }
13003
13004 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
13005 const MFloat F1BRe = F1 / (m_referenceLength * sysEqn().m_Re0);
13006 const MFloat F1BPr = F1 / (m_Pr);
13007
13008 MFloatScratchSpace bodyForce(mMax(1, m_noEmbeddedBodies), noValues, AT_, "bodyForce");
13009 bodyForce.fill(F0);
13010 MFloat coupling = F0;
13011
13012 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++) {
13013 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
13014
13015 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
13016 if(a_isHalo(cellId)) continue;
13017 if(a_isPeriodic(cellId)) continue;
13018 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
13019 if(a_isBndryGhostCell(cellId)) continue;
13020 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
13021
13022 MFloatScratchSpace dummyPvariables(m_bndryCells->a[bndryId].m_noSrfcs, PV->noVariables, AT_, "dummyPvariables");
13023 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
13024 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area < 1e-14) continue;
13025 MInt k = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0];
13026 ASSERT(m_internalBodyId[k] > -1 && m_internalBodyId[k] < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
13027 MInt body = m_internalBodyId[k];
13028 ASSERT(body > -1 && body < m_noEmbeddedBodies, "");
13029
13030 MFloat rhoSurface = F0;
13031 MFloat pSurface = F0;
13032 MInt surfVars = mMin((signed)m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size(),
13033 m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs);
13034
13035 for(MInt s = 0; s < surfVars; s++) {
13036 dummyPvariables(s, PV->P) = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[s]->m_primVars[PV->P];
13037 dummyPvariables(s, PV->RHO) = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[s]->m_primVars[PV->RHO];
13038 }
13039 for(MInt n = 0; n < (signed)m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size(); n++) {
13040 const MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
13041 const MFloat nghbrPvariableP = (n < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs)
13042 ? dummyPvariables(n, PV->P)
13043 : a_pvariable(nghbrId, PV->P);
13044 const MFloat nghbrPvariableRho = (n < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs)
13045 ? dummyPvariables(n, PV->RHO)
13046 : a_pvariable(nghbrId, PV->RHO);
13047 rhoSurface +=
13048 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariableRho;
13049 pSurface += m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariableP;
13050 }
13051
13052 MFloat normal0[3] = {F0, F0, F0};
13053 MFloat normal[3] = {F0, F0, F0};
13054 for(MInt i = 0; i < nDim; i++) {
13055 normal0[i] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
13056 normal[i] = m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i];
13057 }
13058
13059 MFloat dn = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
13060 MFloat T = sysEqn().temperature_ES(rhoSurface, pSurface);
13061 MFloat mue = SUTHERLANDLAW(T);
13062 MFloat dx[3] = {F0, F0, F0};
13063 MFloat df[3] = {F0, F0, F0};
13064 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
13065
13066 for(MInt i = 0; i < nDim; i++) {
13067 const MFloat dp0 = -pSurface * normal0[i] * area;
13068 const MFloat dp = -pSurface * normal[i] * area;
13069 MFloat grad = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[i]];
13070 for(MInt j = 0; j < nDim; j++)
13071 grad += F1B3 * normal[i] * normal[j]
13072 * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[j]];
13073 MFloat ds0 = F1BRe * mue * grad * area;
13074 // The following version was used for JFM2020 "Correlations based on highly resolved simulations".
13075 // TODO labels:FVMB Check the difference for 3D_ellipsoids_Couette for Re -> 0.
13076 // MFloat grad = m_fvBndryCnd->m_bndryCell[ bndryId].m_srfcVariables[srfc]->m_normalDeriv[ PV->VV[i] ];
13077 // for( MInt j = 0; j < nDim; j++ ) grad +=
13078 // F1B3*normal0[i]*normal0[j]*m_fvBndryCnd->m_bndryCell[ bndryId
13079 // ].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[j]
13080 // ]; df[i] = dp0 + ds0; dx[i] = a_coordinate( cellId , i ) - dn * normal0[ i ] - m_bodyCenter[nDim*k+i ];
13081 df[i] = dp + ds0;
13082 dx[i] = a_coordinate(cellId, i) - dn * normal[i] - m_bodyCenter[nDim * k + i];
13083 bodyForce(body, i) += dp0 + ds0;
13084 if(returnCoeffs == true) {
13085 bodyForce(body, nDim + 3 + 1 + i) += dp0;
13086 }
13087 coupling -= (dp0 + ds0) * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]];
13088
13089#if defined _MB_DEBUG_ || !defined NDEBUG
13090 if(std::isnan(dp0) || std::isnan(ds0)) {
13091 const MInt rootId =
13092 (a_hasProperty(cellId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(cellId) : cellId;
13093 cerr << domainId() << " local body force diverged " << globalTimeStep << " " << body << " " << i << " " << k
13094 << " / " << ds0 << " " << dp0 << " " << pSurface << " " << rhoSurface << " " << mue << " " << grad
13095 << " / " << area / m_gridCellArea[a_level(rootId)] << " " << normal0[i] << " " << normal[i] << " "
13096 << dn / c_cellLengthAtCell(rootId) << " / " << cellId << " " << c_globalId(rootId) << " "
13097 << a_level(rootId) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild) << " "
13098 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs << endl;
13099 }
13100#endif
13101 }
13102#ifdef _MB_DEBUG_
13103 if(std::isnan(dx[1] * df[2] - dx[2] * df[1]) || std::isnan(dx[2] * df[0] - dx[0] * df[2])
13104 || std::isnan(dx[0] * df[1] - dx[1] * df[0]))
13105 cerr << domainId() << ": torque0 " << globalTimeStep << " " << c_globalId(cellId) << " " << bndryId << " "
13106 << srfc << " = " << pSurface << " " << rhoSurface << " / " << dx[0] << " " << dx[1] << " " << dx[2]
13107 << " / " << df[0] << " " << df[1] << " " << df[2] << " // " << area / m_gridCellArea[a_level(cellId)]
13108 << " " << pSurface << " " << mue << " "
13109 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[0]] << " "
13110 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[1]] << " "
13111 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[2]] << endl;
13112#endif
13113 IF_CONSTEXPR(nDim == 3) {
13114 bodyForce(body, nDim + 0) += dx[1] * df[2] - dx[2] * df[1];
13115 bodyForce(body, nDim + 1) += dx[2] * df[0] - dx[0] * df[2];
13116 }
13117 bodyForce(body, nDim + 2) += dx[0] * df[1] - dx[1] * df[0];
13118
13119 MFloat gradP = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->P];
13120 MFloat gradRho = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->RHO];
13121 MFloat gradT = m_gamma * (rhoSurface * gradP - pSurface * gradRho) / POW2(rhoSurface);
13122 const MFloat lambdaFluid = (T * sqrt(T) * m_sutherlandPlusOneThermal) / (T + m_sutherlandConstantThermal);
13123 MFloat heatFlux = gradT * area * F1BRe * F1BPr * lambdaFluid * m_gamma;
13124 bodyForce(body, nDim + 3) += heatFlux;
13125 }
13126 }
13127 RECORD_TIMER_STOP(t_local);
13128 RECORD_TIMER_START(t_reduce);
13129
13130 if(m_nonBlockingComm) {
13131#ifndef MAIA_MS_COMPILER
13132 MPI_Request redReq1 = MPI_REQUEST_NULL;
13133 MPI_Request redReq2 = MPI_REQUEST_NULL;
13134 MPI_Iallreduce(MPI_IN_PLACE, &bodyForce[0], bodyForce.size(), MPI_DOUBLE, MPI_SUM, mpiComm(), &redReq1, AT_,
13135 "MPI_IN_PLACE", "bodyForce[0]");
13136 MPI_Iallreduce(MPI_IN_PLACE, &coupling, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), &redReq2, AT_, "MPI_IN_PLACE",
13137 "coupling");
13138 MPI_Wait(&redReq1, MPI_STATUSES_IGNORE, AT_);
13139 MPI_Wait(&redReq2, MPI_STATUSES_IGNORE, AT_);
13140#else
13141 MPI_Allreduce(MPI_IN_PLACE, &bodyForce[0], bodyForce.size(), MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
13142 "bodyForce[0]");
13143 MPI_Allreduce(MPI_IN_PLACE, &coupling, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "coupling");
13144#endif
13145 } else {
13146 MPI_Allreduce(MPI_IN_PLACE, &bodyForce[0], bodyForce.size(), MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
13147 "bodyForce[0]");
13148 MPI_Allreduce(MPI_IN_PLACE, &coupling, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "coupling");
13149 }
13150 RECORD_TIMER_STOP(t_reduce);
13151
13152 // If a pressureForce is requested, it is assumed that the bodyForces are gathered for statistics. To avoid
13153 // additional updates of the bodyForces and torques between the time steps, the function is returned here.
13154 // Updates of the bodyForces and torques after the time step will change the solution.
13155 m_couplingRate = coupling;
13156 if(pressureForce != nullptr) {
13157 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
13158 for(MInt i = 0; i < nDim; i++) {
13159 pressureForce[k * nDim + i] = bodyForce(k, nDim + 3 + 1 + i);
13160 }
13161 }
13162 RECORD_TIMER_STOP(t_timertotal);
13163 return;
13164 }
13165 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
13166 for(MInt i = 0; i < nDim; i++) {
13167 m_bodyForce[k * nDim + i] = bodyForce(k, i);
13168 m_hydroForce[k * nDim + i] = bodyForce(k, i);
13169 }
13170 }
13171 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
13172 m_bodyHeatFlux[k] = bodyForce(k, nDim + 3);
13173 for(MInt i = 0; i < 3; i++) {
13174 m_bodyTorque[k * 3 + i] = bodyForce(k, nDim + i);
13175 }
13176 }
13177
13178 // collision model, Glowinski et al
13179 RECORD_TIMER_START(t_collision);
13180 IF_CONSTEXPR(nDim == 3) {
13181 const MFloat S = (m_noLevelSetsUsedForMb > 1) ? F2 * c_cellLengthAtLevel(maxRefinementLevel())
13182 : F3 * c_cellLengthAtLevel(maxRefinementLevel());
13183 const MFloat deltaMax = 1.5 * S + F2 * m_maxBodyRadius;
13184
13185 if(m_noEmbeddedBodies > 1 && m_applyCollisionModel) {
13186 MIntScratchSpace nearBodies(m_noEmbeddedBodies, AT_, "nearBodies");
13187
13188 for(MInt p = 0; p < m_noEmbeddedBodies; p++) {
13189 m_bodyInCollision[p] = 0;
13190 }
13191
13192 for(MInt p = 0; p < m_noEmbeddedBodies; p++) {
13193 ASSERT(m_bodyTree != nullptr, "");
13194
13195 Point<nDim> pt(m_bodyCenter[p * nDim], m_bodyCenter[p * nDim + 1], m_bodyCenter[p * nDim + 2]);
13196 MInt noNearBodies = m_bodyTree->locatenear(pt, deltaMax, &nearBodies[0], m_noEmbeddedBodies);
13197
13198 for(MInt b = 0; b < noNearBodies; b++) {
13199 const MInt q = nearBodies[b];
13200 if(p == q) continue;
13201
13202 m_bodyInCollision[p] = 1;
13203
13204 const MFloat dp = F2 * mMax(m_bodyRadii[p * 3 + 0], mMax(m_bodyRadii[p * 3 + 1], m_bodyRadii[p * 3 + 2]));
13205 const MFloat dq = F2 * mMax(m_bodyRadii[q * 3 + 0], mMax(m_bodyRadii[q * 3 + 1], m_bodyRadii[q * 3 + 2]));
13206 const MFloat D = F1B2 * (dp + dq);
13207 const MFloat termv =
13208 sqrt(POW2(m_bodyTerminalVelocity[0]) + POW2(m_bodyTerminalVelocity[1]) + POW2(m_bodyTerminalVelocity[2]));
13209 const MFloat delta = sqrt(POW2(m_bodyCenter[p * nDim] - m_bodyCenter[q * nDim])
13210 + POW2(m_bodyCenter[p * nDim + 1] - m_bodyCenter[q * nDim + 1])
13211 + POW2(m_bodyCenter[p * nDim + 2] - m_bodyCenter[q * nDim + 2]));
13212 MFloat dist = delta - D;
13213
13214 if(dist > S) continue;
13215
13216 if(m_bodyTypeMb == 1) {
13217 if(dist < F0 && domainId() == 0) cerr << "Warning: potential overlap for bodies " << p << " " << q << endl;
13218 const MFloat eps = POW2(S / D);
13219 const MFloat C = CdLaw(m_Re * D) * F1B2 * m_rhoU2 * F1B4 * PI * POW2(D);
13220 const MFloat M = F1B2 * (m_bodyMass[m_internalBodyId[p]] + m_bodyMass[m_internalBodyId[q]]);
13221 const MFloat C0 = 8.0 * M * POW2(m_UInfinity + termv) / c_cellLengthAtLevel(maxRefinementLevel());
13222 if(dist < S) {
13223 m_bodyInCollision[p] = 2;
13224 }
13225 for(MInt i = 0; i < nDim; i++) {
13226 MFloat df = C0 * POW2(mMax(F0, -(dist - S) / S))
13227 * (m_bodyCenter[p * nDim + i] - m_bodyCenter[q * nDim + i]) / dist;
13228 m_bodyForce[p * nDim + i] += df;
13229 }
13230 if(domainId() == 0 && dist / c_cellLengthAtLevel(maxRefinementLevel()) < 1.5)
13231 cerr << globalTimeStep << " ---- repulsive force " << m_internalBodyId[q] << " -> " << p << ": "
13232 << C0 * POW2(mMax(F0, -(dist - S) / S)) << " / " << C * POW2(mMax(F0, -(dist - S) / S)) / eps << " ("
13233 << C0 / (C / eps) << ") dist=" << dist / c_cellLengthAtLevel(maxRefinementLevel()) << endl;
13234
13235 } else if(m_bodyTypeMb == 3) {
13236 const MFloat M = F1B2 * (m_bodyMass[m_internalBodyId[p]] + m_bodyMass[m_internalBodyId[q]]);
13237 const MFloat C0 = 16.0 * M * POW2(m_UInfinity + termv) / c_cellLengthAtLevel(maxRefinementLevel());
13238
13239 MFloat xcp[3];
13240 MFloat xcq[3];
13241 MFloat df[3];
13242 dist = distEllipsoidEllipsoid(p, q, xcp, xcq);
13243
13244 if(dist < S) {
13245 m_bodyInCollision[p] = 2;
13246 }
13247
13248 for(MInt i = 0; i < nDim; i++) {
13249 df[i] = C0 * POW2(mMax(F0, -(dist - S) / S)) * (xcp[i] - xcq[i]) / dist;
13250 m_bodyForce[p * nDim + i] += df[i];
13251 }
13252
13253 if(domainId() == 0 && dist / c_cellLengthAtLevel(maxRefinementLevel()) < 1.5)
13254 cerr << globalTimeStep << " ---- repulsive force " << m_internalBodyId[q] << " -> " << p << ": "
13255 << C0 * POW2(mMax(F0, -(dist - S) / S))
13256 << " dist=" << dist / c_cellLengthAtLevel(maxRefinementLevel()) << endl;
13257 }
13258 }
13259 }
13260
13261 if(m_saveSlipInterval > 0) {
13262 MInt noParticlesLocal = m_particleOffsets[domainId() + 1] - m_particleOffsets[domainId()];
13263 MInt noTimeStepsSaved = m_slipDataTimeSteps.size();
13264
13265 for(MInt p = 0; p < noParticlesLocal; p++) {
13266 m_slipDataParticleCollision[noParticlesLocal * noTimeStepsSaved + p] =
13267 m_bodyInCollision[p + m_particleOffsets[domainId()]];
13268 }
13269 }
13270 }
13271 }
13272
13273#if defined _MB_DEBUG_ || !defined NDEBUG
13274 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
13275 for(MInt i = 0; i < nDim; i++) {
13276 if(std::isnan(m_bodyForce[k * nDim + i]) && domainId() == 0) {
13277 cerr << "force " << setprecision(15) << k << " " << i << " " << m_bodyForce[k * nDim + i] << endl;
13278 m_log << "force " << setprecision(15) << k << " " << i << " " << m_bodyForce[k * nDim + i];
13279 for(MInt j = 0; j < nDim; j++)
13280 m_log << " " << m_bodyCenter[nDim * k + j];
13281 for(MInt j = 0; j < 4; j++)
13282 m_log << " " << m_bodyQuaternion[4 * k + j];
13283 m_log << endl;
13284 }
13285 }
13286
13287 for(MInt i = 0; i < 3; i++) {
13288 if(std::isnan(m_bodyTorque[k * 3 + i]) && domainId() == 0) {
13289 cerr << "torque " << setprecision(15) << k << " " << i << " " << m_bodyTorque[k * 3 + i] << endl;
13290 m_log << "torque " << setprecision(15) << k << " " << i << " " << m_bodyTorque[k * 3 + i];
13291 for(MInt j = 0; j < nDim; j++)
13292 m_log << " " << m_bodyCenter[nDim * k + j];
13293 for(MInt j = 0; j < 4; j++)
13294 m_log << " " << m_bodyQuaternion[4 * k + j];
13295 m_log << endl;
13296 }
13297 }
13298 }
13299#endif
13300 RECORD_TIMER_STOP(t_collision);
13301 RECORD_TIMER_STOP(t_timertotal);
13302 DISPLAY_TIMER_OFFSET(t_timertotal, m_restartInterval);
13303}
13304
13305
13310template <MInt nDim, class SysEqn>
13311template <typename T>
13313 return (std::isnan(val) || std::isinf(val));
13314}
13315
13316
13321template <MInt nDim, class SysEqn>
13323 if(m_noEmbeddedBodies == 0) return;
13324 cerr0 << "Init body velocities" << endl;
13325
13338 const MInt initBodyRotation = (Context::propertyExists("initBodyRotation", m_solverId))
13339 ? Context::getSolverProperty<MInt>("initBodyRotation", m_solverId, AT_)
13340 : 0;
13341
13342 memset(m_bodyVelocity, 0, m_noEmbeddedBodies * nDim * sizeof(MFloat));
13343 memset(m_bodyAngularVelocity, 0, m_noEmbeddedBodies * 3 * sizeof(MFloat));
13344
13345 if(initBodyRotation == 1) {
13346 MFloatScratchSpace bodyVol(m_noEmbeddedBodies, AT_, "bodyVol");
13347 MFloatScratchSpace Ek(m_noEmbeddedBodies, AT_, "Ek");
13348 bodyVol.fill(F0);
13349
13350 MFloat vol0 = F0;
13351 MFloat vol1 = F0;
13352 MFloat vol2 = F0;
13353 MFloat Ek0 = F0;
13354 MFloat EkB = F0;
13355 MFloat volm = F0;
13356 MFloat volB = F0;
13357
13358 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
13359 if(a_isHalo(cellId)) continue;
13360 ASSERT(!a_isPeriodic(cellId), "");
13361 if(a_isPeriodic(cellId)) continue;
13362 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(cellId) > 0) continue;
13363 if(a_bndryId(cellId) < -1) continue;
13364
13365 MFloat U2 = F0;
13366 for(MInt i = 0; i < nDim; i++) {
13367 U2 += POW2(a_variable(cellId, CV->RHO_VV[i]) / a_variable(cellId, CV->RHO));
13368 }
13369
13370 Ek0 += F1B2 * a_cellVolume(cellId) * U2;
13371 volm += a_cellVolume(cellId);
13372
13373 if(a_levelSetValuesMb(cellId, 0) < F0 || a_bndryId(cellId) >= m_noOuterBndryCells) {
13374 if(a_associatedBodyIds(cellId, 0) < 0) {
13375 cerr << domainId() << ": negative body id A" << endl;
13376 continue;
13377 }
13378
13379 MInt bodyId = m_internalBodyId[a_associatedBodyIds(cellId, 0)];
13380 MFloat vol = grid().gridCellVolume(a_level(cellId));
13381
13382 if(a_bndryId(cellId) > -1) vol -= a_cellVolume(cellId);
13383
13384 for(MInt i = 0; i < nDim; i++)
13385 m_bodyVelocity[nDim * bodyId + i] += vol * a_pvariable(cellId, PV->VV[i]);
13386
13387 MFloat r2 = F0;
13388 MFloat dx[3]{};
13389
13390 for(MInt i = 0; i < nDim; i++) {
13391 dx[i] = a_coordinate(cellId, i) - m_bodyCenter[bodyId * nDim + i];
13392 r2 += POW2(dx[i]);
13393 }
13394
13395 if(initBodyRotation) {
13396 m_bodyAngularVelocity[3 * bodyId + 0] +=
13397 vol * (dx[1] * a_pvariable(cellId, PV->VV[2]) - dx[2] * a_pvariable(cellId, PV->VV[1])) / r2;
13398 m_bodyAngularVelocity[3 * bodyId + 1] +=
13399 vol * (dx[2] * a_pvariable(cellId, PV->VV[0]) - dx[0] * a_pvariable(cellId, PV->VV[2])) / r2;
13400 m_bodyAngularVelocity[3 * bodyId + 2] +=
13401 vol * (dx[0] * a_pvariable(cellId, PV->VV[1]) - dx[1] * a_pvariable(cellId, PV->VV[0])) / r2;
13402 }
13403 for(MInt i = 0; i < nDim; i++)
13404 Ek[bodyId] += vol * POW2(a_pvariable(cellId, PV->VV[i]));
13405 bodyVol(bodyId) += vol;
13406 vol0 += vol;
13407 for(MInt i = 0; i < nDim; i++)
13408 EkB += vol * POW2(a_pvariable(cellId, PV->VV[i]));
13409 volB += vol;
13410 }
13411 if(a_levelSetValuesMb(cellId, 0) > F0 || a_bndryId(cellId) >= m_noOuterBndryCells) {
13412 MFloat vol = a_cellVolume(cellId);
13413 vol1 += vol;
13414 }
13415
13416 if(a_bndryId(cellId) >= m_noOuterBndryCells) {
13417 MFloat vol = m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_area;
13418 vol2 += vol;
13419 }
13420 }
13421 MPI_Allreduce(MPI_IN_PLACE, m_bodyVelocity, m_noEmbeddedBodies * nDim, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
13422 "MPI_IN_PLACE", "m_bodyVelocity");
13423 MPI_Allreduce(MPI_IN_PLACE, m_bodyAngularVelocity, m_noEmbeddedBodies * 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
13424 "MPI_IN_PLACE", "m_bodyAngularVelocity");
13425 MPI_Allreduce(MPI_IN_PLACE, &bodyVol[0], m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
13426 "bodyVol[0]");
13427 MPI_Allreduce(MPI_IN_PLACE, &vol0, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "vol0");
13428 MPI_Allreduce(MPI_IN_PLACE, &vol1, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "vol1");
13429 MPI_Allreduce(MPI_IN_PLACE, &vol2, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "vol2");
13430 MPI_Allreduce(MPI_IN_PLACE, &Ek[0], m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
13431 "Ek[0]");
13432 MPI_Allreduce(MPI_IN_PLACE, &Ek0, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "Ek0");
13433 MPI_Allreduce(MPI_IN_PLACE, &volm, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "volm");
13434 MPI_Allreduce(MPI_IN_PLACE, &EkB, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "EkB");
13435 MPI_Allreduce(MPI_IN_PLACE, &volB, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "volB");
13436 Ek0 /= volm;
13437 EkB /= volB;
13438
13439 MFloat EkB2 = 0;
13440 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
13441 if(domainId() == 0 && fabs(bodyVol[b] - m_bodyVolume[b]) / m_bodyVolume[b] > 0.1)
13442 cerr << "bad body volume " << b << " " << bodyVol[b] << " " << m_bodyVolume[b] << endl;
13443 Ek[b] /= mMax(1e-14, bodyVol[b]);
13444
13445 for(MInt i = 0; i < nDim; i++) {
13446 m_bodyVelocity[nDim * b + i] /= mMax(1e-14, bodyVol[b]);
13447 m_bodyVelocityDt1[nDim * b + i] = m_bodyVelocity[nDim * b + i];
13448 if(domainId() == 0 && std::isnan(m_bodyVelocity[nDim * b + i]))
13449 cerr << "Warning: body velocity " << b << " " << i << " " << m_bodyVelocity[nDim * b + i] << endl;
13450 EkB2 += F1B2 * POW2(m_bodyVelocity[nDim * b + i]);
13451 }
13452
13453 if(initBodyRotation) {
13454 for(MInt i = 0; i < 3; i++) {
13455 m_bodyAngularVelocity[3 * b + i] /= mMax(1e-14, bodyVol[b]);
13456 m_bodyAngularVelocityDt1[3 * b + i] = m_bodyAngularVelocity[3 * b + i];
13457 if(domainId() == 0 && std::isnan(m_bodyAngularVelocity[3 * b + i]))
13458 cerr << "Warning: body angular velocity " << b << " " << i << " " << m_bodyAngularVelocity[3 * b + i]
13459 << endl;
13460 }
13461 }
13462
13463 for(MUint j = 0; j < m_periodicGhostBodies[b].size(); j++) {
13464 MInt k = m_periodicGhostBodies[b][j];
13465 transferBodyState(k, b);
13466 }
13467 }
13468
13469 for(MInt k = 0; k < m_noEmbeddedBodies + m_noPeriodicGhostBodies; k++) {
13470 for(MInt dir = 0; dir < nDim; dir++) {
13471 m_bodyVelocity[nDim * k + dir] += m_bodyTerminalVelocity[dir];
13472 }
13473 }
13474
13475 if(domainId() == 0) {
13476 cerr << "domain volumes upon init: " << setprecision(12) << vol0 << " " << vol1 << " "
13477 << vol0 / POW3(m_bbox[3] - m_bbox[0]) << " " << (vol0 + vol1) / POW3(m_bbox[3] - m_bbox[0]) << " "
13478 << Ek0 / POW2(m_UInfinity) << " " << EkB / POW2(m_UInfinity) << " "
13479 << (Ek0 * volm + EkB * volB) / ((volm + volB) * POW2(m_UInfinity)) << " "
13480 << EkB2 / (POW2(m_UInfinity) * m_noEmbeddedBodies) << endl;
13481 m_log << "domain volumes upon init: " << setprecision(12) << vol0 << " " << vol1 << " "
13482 << vol0 / POW3(m_bbox[3] - m_bbox[0]) << " " << (vol0 + vol1) / POW3(m_bbox[3] - m_bbox[0]) << " "
13483 << Ek0 / POW2(m_UInfinity) << " " << EkB / POW2(m_UInfinity) << " "
13484 << (Ek0 * volm + EkB * volB) / ((volm + volB) * POW2(m_UInfinity)) << " "
13485 << EkB2 / (POW2(m_UInfinity) * m_noEmbeddedBodies) << endl;
13486 }
13487 } else {
13488 MIntScratchSpace nearestCellToCenter(m_noEmbeddedBodies, AT_, "nearestCellToCenter");
13489 MFloatScratchSpace nearestDist(m_noEmbeddedBodies, AT_, "nearestDist");
13490 nearestCellToCenter.fill(-1);
13491 nearestDist.fill(std::numeric_limits<MFloat>::max());
13492
13493 MFloat volF = F0;
13494 MFloat volB = F0;
13495 MFloat EkFluid = F0;
13496 MFloat EkFluidInBodyVol = F0;
13497 MFloat dx[3] = {F0, F0, F0};
13498
13499 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
13500 if(a_isHalo(cellId)) continue;
13501 ASSERT(!a_isPeriodic(cellId), "");
13502 if(a_isPeriodic(cellId)) continue;
13503 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(cellId) > 0) continue;
13504 if(a_bndryId(cellId) < -1) continue;
13505
13506 MFloat U2 = F0;
13507 for(MInt i = 0; i < nDim; i++) {
13508 U2 += POW2(a_variable(cellId, CV->RHO_VV[i]) / a_variable(cellId, CV->RHO));
13509 }
13510
13511 EkFluid += F1B2 * a_cellVolume(cellId) * U2;
13512 volF += a_cellVolume(cellId);
13513
13514 if(a_levelSetValuesMb(cellId, 0) < F0 || a_bndryId(cellId) >= m_noOuterBndryCells) {
13515 MInt bodyId = a_associatedBodyIds(cellId, 0);
13516 if(bodyId < 0) continue;
13517 bodyId = m_internalBodyId[bodyId];
13518 MFloat vol = grid().gridCellVolume(a_level(cellId));
13519 if(a_bndryId(cellId) > -1) vol -= a_cellVolume(cellId);
13520 volB += vol;
13521 for(MInt i = 0; i < nDim; i++) {
13522 EkFluidInBodyVol += F1B2 * vol * POW2(a_variable(cellId, CV->RHO_VV[i]) / a_variable(cellId, CV->RHO));
13523 }
13524 MFloat r2 = F0;
13525 for(MInt i = 0; i < nDim; i++) {
13526 dx[i] = a_coordinate(cellId, i) - m_bodyCenter[bodyId * nDim + i];
13527 r2 += POW2(dx[i]);
13528 }
13529 if(sqrt(r2) < nearestDist(bodyId)) {
13530 nearestCellToCenter(bodyId) = cellId;
13531 nearestDist(bodyId) = sqrt(r2);
13532 }
13533 }
13534 }
13535
13536 MPI_Allreduce(MPI_IN_PLACE, &EkFluid, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "EkFluid");
13537 MPI_Allreduce(MPI_IN_PLACE, &EkFluidInBodyVol, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
13538 "EkFluidInBodyVol");
13539 MPI_Allreduce(MPI_IN_PLACE, &volF, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "volF");
13540 MPI_Allreduce(MPI_IN_PLACE, &volB, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "volB");
13541 MPI_Allreduce(MPI_IN_PLACE, &nearestDist(0), m_noEmbeddedBodies, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_,
13542 "MPI_IN_PLACE", "nearestDist(0)");
13543
13544 if(initBodyRotation) exchangeAll();
13545
13546 for(MInt bodyId = 0; bodyId < m_noEmbeddedBodies; bodyId++) {
13547 MInt cellId = nearestCellToCenter(bodyId);
13548 if(cellId < 0) continue;
13549 MFloat r2 = F0;
13550 for(MInt i = 0; i < nDim; i++) {
13551 dx[i] = a_coordinate(cellId, i) - m_bodyCenter[bodyId * nDim + i];
13552 r2 += POW2(dx[i]);
13553 }
13554 if(sqrt(r2) > (nearestDist(bodyId) + std::numeric_limits<MFloat>::epsilon())) continue;
13555 for(MInt i = 0; i < nDim; i++) {
13556 m_bodyVelocity[nDim * bodyId + i] = a_variable(cellId, CV->RHO_VV[i]) / a_variable(cellId, CV->RHO);
13557 }
13558 if(initBodyRotation) {
13559 while(a_level(cellId) > maxUniformRefinementLevel()) {
13560 cellId = c_parentId(cellId);
13561 }
13562 vector<vector<MFloat>> slope(nDim, vector<MFloat>(nDim));
13563 for(MInt dir = 0; dir < m_noDirs / 2; dir++) {
13564 MInt nghbrId1 = -1;
13565 MInt nghbrId2 = -1;
13566 if(a_hasNeighbor(cellId, dir) > 0)
13567 nghbrId1 = c_neighborId(cellId, 2 * dir);
13568 else
13569 mTerm(0, AT_, "neighbor not found. PartitionLevelShift?");
13570 if(a_hasNeighbor(cellId, dir + 1) > 0)
13571 nghbrId2 = c_neighborId(cellId, 2 * dir + 1);
13572 else
13573 mTerm(0, AT_, "neighbor not found. PartitionLevelShift?");
13574 for(MInt i = 0; i < nDim; i++) {
13575 slope[i][dir] = F1 / (F2 * grid().cellLengthAtCell(cellId))
13576 * (a_pvariable(nghbrId2, PV->VV[i]) - a_pvariable(nghbrId1, PV->VV[i]));
13577 }
13578 }
13579 for(MInt i = 0; i < nDim; i++) {
13580 MInt id0 = (i + 1) % 3;
13581 MInt id1 = (id0 + 1) % 3;
13582 m_bodyAngularVelocity[3 * bodyId + i] += F1B2 * (slope[id1][id0] - slope[id0][id1]);
13583 }
13584 }
13585 }
13586
13587 MPI_Allreduce(MPI_IN_PLACE, m_bodyVelocity, m_noEmbeddedBodies * nDim, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
13588 "MPI_IN_PLACE", "m_bodyVelocity");
13589 if(initBodyRotation)
13590 MPI_Allreduce(MPI_IN_PLACE, m_bodyAngularVelocity, m_noEmbeddedBodies * 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
13591 "MPI_IN_PLACE", "m_bodyAngularVelocity");
13592
13593 MFloat EkBTot = F0;
13594 MFloat EkBLin = F0;
13595 MFloat EkBRot = F0;
13596 MFloat EkBTerm = F0;
13597 MFloat volBAnalytical = F0;
13598 for(MInt bodyId = 0; bodyId < m_noEmbeddedBodies; bodyId++) {
13599 for(MInt i = 0; i < nDim; i++) {
13600 m_bodyVelocityDt1[nDim * bodyId + i] = m_bodyVelocity[nDim * bodyId + i];
13601 EkBLin += F1B2 * POW2(m_bodyVelocity[nDim * bodyId + i]);
13602 EkBTot += F1B2 * POW2(m_bodyVelocity[nDim * bodyId + i]);
13603 EkBTerm += F1B2 * POW2(m_bodyVelocity[nDim * bodyId + i] + m_bodyTerminalVelocity[i]);
13604 if(domainId() == 0 && std::isnan(m_bodyVelocity[nDim * bodyId + i]))
13605 cerr << "Warning: body velocity " << bodyId << " " << i << " " << m_bodyVelocity[nDim * bodyId + i] << endl;
13606 }
13607
13608 if(initBodyRotation) {
13609 MFloat q[3];
13610 MFloat tmp[3];
13611 MFloatScratchSpace R(3, 3, AT_, "R");
13612 computeRotationMatrix(R, &(m_bodyQuaternion[4 * bodyId]));
13613 for(MInt i = 0; i < 3; i++)
13614 tmp[i] = m_bodyAngularVelocity[bodyId * 3 + i];
13615 matrixVectorProduct(q, R, tmp); // principal axes angular velocity
13616 for(MInt i = 0; i < nDim; i++) {
13617 m_bodyAngularVelocityDt1[3 * bodyId + i] = m_bodyAngularVelocity[3 * bodyId + i];
13618 EkBRot += F1B2 * POW2(q[i]) * m_bodyMomentOfInertia[3 * bodyId + i] / m_bodyMass[bodyId];
13619 EkBTot += EkBRot;
13620 if(domainId() == 0 && std::isnan(m_bodyAngularVelocity[3 * bodyId + i]))
13621 cerr << "Warning: body angular velocity " << bodyId << " " << i << " "
13622 << m_bodyAngularVelocity[3 * bodyId + i] << endl;
13623 }
13624 }
13625
13626 for(MUint j = 0; j < m_periodicGhostBodies[bodyId].size(); j++) {
13627 MInt k = m_periodicGhostBodies[bodyId][j];
13628 transferBodyState(k, bodyId);
13629 }
13630 volBAnalytical += F4B3 * PI * m_bodyRadii[bodyId] * m_bodyRadii[bodyId + 1] * m_bodyRadii[bodyId + 2];
13631 }
13632 for(MInt k = 0; k < m_noEmbeddedBodies + m_noPeriodicGhostBodies; k++) {
13633 for(MInt dir = 0; dir < nDim; dir++) {
13634 m_bodyVelocity[nDim * k + dir] += m_bodyTerminalVelocity[dir];
13635 }
13636 }
13637 MFloat volFAnalytical = F1;
13638 for(MInt dim = 0; dim < nDim; dim++) {
13639 volFAnalytical *= (m_bbox[nDim + dim] - m_bbox[dim]);
13640 }
13641 volFAnalytical -= volBAnalytical;
13642 if(domainId() == 0) {
13643 cerr << "InitBodyFluidVelocities: mean kinetic Energy " << setprecision(12) << "fluid "
13644 << EkFluid / (POW2(m_UInfinity) * volF) << " fluid in bodies "
13645 << EkFluidInBodyVol / (POW2(m_UInfinity) * volB) << " bodies: total "
13646 << EkBTot / (POW2(m_UInfinity) * m_noEmbeddedBodies) << " linear "
13647 << EkBLin / (POW2(m_UInfinity) * m_noEmbeddedBodies) << " rotational "
13648 << EkBRot / (POW2(m_UInfinity * m_noEmbeddedBodies)) << " terminal "
13649 << EkBTerm / (POW2(m_UInfinity) * m_noEmbeddedBodies) << endl;
13650 cerr << "InitBodyFluidVelocities: volumes " << setprecision(12) << "fluid " << volF << " analytical "
13651 << volFAnalytical << " bodies " << volB << " volBAnalytical " << volBAnalytical << endl;
13652 m_log << "InitBodyFluidVelocities: mean kinetic Energy " << setprecision(12) << "fluid "
13653 << EkFluid / (POW2(m_UInfinity) * volF) << " fluid in bodies "
13654 << EkFluidInBodyVol / (POW2(m_UInfinity) * volB) << " bodies total "
13655 << EkBTot / (POW2(m_UInfinity) * m_noEmbeddedBodies) << " linear "
13656 << EkBLin / (POW2(m_UInfinity) * m_noEmbeddedBodies) << " rotational "
13657 << EkBRot / (POW2(m_UInfinity * m_noEmbeddedBodies)) << " terminal "
13658 << EkBTerm / (POW2(m_UInfinity) * m_noEmbeddedBodies) << endl;
13659 m_log << "InitBodyFluidVelocities: volumes " << setprecision(12) << "fluid " << volF << " analytical "
13660 << volFAnalytical << " bodies " << volB << " volBAnalytical " << volBAnalytical << endl;
13661 }
13662 }
13663}
13664
13669template <MInt nDim, class SysEqn>
13671 /*
13672 TRACE();
13673
13674 MInt cellId;
13675
13676 // 1. find near boundary cells
13677 m_noNearBndryCells = 0;
13678 m_nearBndryCells->resetSize(0);
13679
13680 for ( MUint c = 0; c < m_bndryLayerCells.size(); c++ ) {
13681 cellId = m_bndryLayerCells[ c ];
13682 if ( cellId < 0 ) continue;
13683 if ( !a_hasProperty( cellId , SolverCell::IsOnCurrentMGLevel) )
13684 continue; if ( a_hasProperty( cellId , SolverCell::IsInactive ) )
13685 continue; if ( a_isBndryGhostCell( cellId ) ) continue;
13686 //if ( a_level(cellId) != maxRefinementLevel() ) continue;
13687
13688 m_nearBndryCells->append();
13689 m_nearBndryCells->a[ m_noNearBndryCells ] = cellId;
13690 m_noNearBndryCells++;
13691 }*/
13692}
13693
13694
13700template <MInt nDim, class SysEqn>
13702 TRACE();
13703
13704 // set default
13705 execRungeKuttaStep = nullptr;
13717 m_standardRK = (Context::propertyExists("rungeKuttaStandardMb", m_solverId))
13718 ? Context::getSolverProperty<MBool>("rungeKuttaStandardMb", m_solverId, AT_)
13719 : false;
13720
13721
13722 if(!m_standardRK && !m_dualTimeStepping) {
13723 execRungeKuttaStep = m_localTS ? &FvMbCartesianSolverXD<nDim, SysEqn>::rungeKuttaStepNew<1>
13725 } else if(m_standardRK && !m_dualTimeStepping) {
13726 execRungeKuttaStep = m_localTS ? &FvMbCartesianSolverXD<nDim, SysEqn>::rungeKuttaStepStandard<1>
13728 } else if(m_dualTimeStepping) {
13730 }
13731
13732 // number of Runge-Kutta steps
13733 m_noRKSteps = Context::getSolverProperty<MInt>("noRKSteps", m_solverId, AT_);
13734
13735 // alpha
13736 if(m_RKalpha != nullptr) {
13737 mDeallocate(m_RKalpha);
13738 }
13739 mAlloc(m_RKalpha, m_noRKSteps, "m_RKalpha", F0, AT_);
13740
13741 for(MInt i = 0; i < m_noRKSteps; i++) {
13742 m_RKalpha[i] = Context::getSolverProperty<MFloat>("rkalpha-step", m_solverId, AT_, i);
13743 }
13744
13745 m_RKStep = 0;
13746}
13747
13752template <MInt nDim, class SysEqn>
13754 TRACE();
13755
13756 setRungeKuttaFunctionPointer();
13757
13758 if(!m_restart) {
13759 m_time = 0.0;
13760 m_physicalTimeDt1 = m_physicalTime;
13761 }
13762
13763 for(MInt cellId = a_noCells() - 1; cellId >= 0; --cellId) {
13764 for(MInt varId = 0; varId < m_noCVars; varId++) {
13765 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
13766 }
13767 }
13768
13769 computeCellVolumes();
13770}
13771
13772
13777template <MInt nDim, class SysEqn>
13779 TRACE();
13780
13781 if(!m_levelSetMb) applyBoundaryConditionMb();
13782 if(m_trackBodySurfaceData) computeBodySurfaceData();
13783}
13784
13785
13790template <MInt nDim, class SysEqn>
13792 // dummy, see applyBoundaryConditionMb()
13793
13794 for(MInt i = 0; i < noNeighborDomains(); i++) {
13795 for(MInt j = 0; j < m_noMaxLevelHaloCells[i]; j++) {
13796 MInt cellId = m_maxLevelHaloCells[i][j];
13797 setConservativeVariables(cellId);
13798 }
13799 }
13800
13801 if(grid().azimuthalPeriodicity()) {
13802 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
13803 for(MUint j = 0; j < m_azimuthalMaxLevelHaloCells[i].size(); j++) {
13804 MInt cellId = m_azimuthalMaxLevelHaloCells[i][j];
13805 setConservativeVariables(cellId);
13806 }
13807 }
13808 }
13809
13810 // update split childs after exchange()
13811 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
13812 const MInt cellId = m_splitCells[sc];
13813 if(!a_isHalo(cellId)) continue;
13814 MFloat volCnt = F0;
13815 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
13816 const MInt splitChildId = m_splitChilds[sc][ssc];
13817 for(MInt v = 0; v < m_noCVars; v++) {
13818 a_variable(splitChildId, v) = a_variable(cellId, v);
13819 }
13820 for(MInt v = 0; v < m_noFVars; v++) {
13821 a_rightHandSide(splitChildId, v) = a_rightHandSide(cellId, v);
13822 m_rhs0[splitChildId][v] = m_rhs0[cellId][v];
13823 }
13824 volCnt += a_cellVolume(splitChildId);
13825 }
13826 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
13827 const MInt splitChildId = m_splitChilds[sc][ssc];
13828 volCnt = mMax(volCnt, 1e-15);
13829 for(MInt v = 0; v < m_noFVars; v++) {
13830 a_rightHandSide(splitChildId, v) *= a_cellVolume(splitChildId) / volCnt;
13831 m_rhs0[splitChildId][v] *= a_cellVolume(splitChildId) / volCnt;
13832 }
13833 setPrimitiveVariables(splitChildId);
13834 }
13835 }
13836
13837
13838 // if ( m_noPointParticles > 0 ) advancePointParticles();
13839 if(m_RKStep == 0 && m_noPointParticles > 0) advancePointParticles();
13840
13841 if(m_RKStep != 0 || globalTimeStep == 0) return;
13842 if(m_conservationCheck) {
13843 MBool& firstRun = m_static_applyBoundaryCondition_firstRun;
13844 MFloat eRhoL1 = F0;
13845 MFloat eRhoL2 = F0;
13846 MFloat eRhoLoo = F0;
13847 MFloat eVelL1 = F0;
13848 MFloat eVelL2 = F0;
13849 MFloat eVelLoo = F0;
13850 MFloat counter = F0;
13851 MFloat mass = F0;
13852 MFloat vol = F0;
13853 MFloat oldVol = F0;
13854 MFloat rhs = F0;
13855 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
13856 if(a_isBndryGhostCell(cellId)) continue;
13857 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
13858 if(a_isPeriodic(cellId)) continue;
13859 if(a_isHalo(cellId)) continue;
13860 if(c_noChildren(cellId) > 0) continue;
13861 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
13862 // if ( a_coordinate( cellId , 0) < m_bodyCenter[0]) continue;
13863 if(a_coordinate(cellId, 0) > m_bodyCenter[0]) continue;
13864 rhs += a_rightHandSide(cellId, CV->RHO);
13865 MFloat vel = F0;
13866 for(MInt i = 0; i < nDim; i++)
13867 vel += POW2(a_pvariable(cellId, PV->VV[i]) - m_VVInfinity[i]);
13868 vel = sqrt(vel);
13869 eRhoL1 += fabs(a_pvariable(cellId, PV->RHO) - m_rhoInfinity);
13870 eRhoL2 += POW2(a_pvariable(cellId, PV->RHO) - m_rhoInfinity);
13871 eRhoLoo = mMax(eRhoLoo, fabs(a_pvariable(cellId, PV->RHO) - m_rhoInfinity));
13872 eVelL1 += fabs(vel);
13873 eVelL2 += POW2(vel);
13874 eVelLoo = mMax(eVelLoo, fabs(vel));
13875 counter += F1;
13876 mass += a_cellVolume(cellId) * a_variable(cellId, CV->RHO);
13877 vol += a_cellVolume(cellId);
13878 oldVol += m_cellVolumesDt1[cellId];
13879 }
13880 MFloat delta = F0;
13881 MFloat area = F0;
13882 for(MInt bs = 0; bs < m_fvBndryCnd->m_noBoundarySurfaces; bs++) {
13883 MInt srfcId = m_fvBndryCnd->m_boundarySurfaces[bs];
13884 if(a_surfaceBndryCndId(srfcId) / 1000 == 3) {
13885 continue;
13886 }
13887 if(a_isBndryGhostCell(a_surfaceNghbrCellId(srfcId, 0)))
13888 delta -= a_surfaceFlux(srfcId, CV->RHO);
13889 else
13890 delta += a_surfaceFlux(srfcId, CV->RHO);
13891 area += a_surfaceArea(srfcId);
13892 }
13893 MPI_Allreduce(MPI_IN_PLACE, &mass, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "mass");
13894 MPI_Allreduce(MPI_IN_PLACE, &delta, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "delta");
13895 MPI_Allreduce(MPI_IN_PLACE, &vol, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "vol");
13896 MPI_Allreduce(MPI_IN_PLACE, &oldVol, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "oldVol");
13897 MFloat& ERhoL1 = m_static_applyBoundaryCondition_ERhoL1;
13898 MFloat& ERhoL2 = m_static_applyBoundaryCondition_ERhoL2;
13899 MFloat& ERhoLoo = m_static_applyBoundaryCondition_ERhoLoo;
13900 MFloat& EVelL1 = m_static_applyBoundaryCondition_EVelL1;
13901 MFloat& EVelL2 = m_static_applyBoundaryCondition_EVelL2;
13902 MFloat& EVelLoo = m_static_applyBoundaryCondition_EVelLoo;
13903 MFloat& refMass = m_static_applyBoundaryCondition_refMass;
13904 MFloat& oldMass = m_static_applyBoundaryCondition_oldMass;
13905 MFloat& oldVol2 = m_static_applyBoundaryCondition_oldVol2;
13906 if(firstRun) {
13907 ERhoL1 = F0;
13908 ERhoL2 = F0;
13909 ERhoLoo = F0;
13910 EVelL1 = F0;
13911 EVelL2 = F0;
13912 EVelLoo = F0;
13913 refMass = mass;
13914 oldMass = mass;
13915 oldVol2 = vol;
13916 }
13917 ERhoL1 += eRhoL1;
13918 ERhoL2 += eRhoL2;
13919 ERhoLoo = mMax(ERhoLoo, eRhoLoo);
13920 EVelL1 += eVelL1;
13921 EVelL2 += eVelL2;
13922 EVelLoo = mMax(EVelLoo, eVelLoo);
13923 refMass -= timeStep() * delta;
13924 oldMass -= timeStep() * delta;
13926 if(domainId() == 0) {
13927 ofstream ofl;
13928 if(firstRun)
13929 ofl.open("mass_loss", ios_base::out | ios_base::trunc);
13930 else
13931 ofl.open("mass_loss", ios_base::out | ios_base::app);
13932 cerr << "mass defect" << globalTimeStep << " (" << delta * timeStep() << ") " << refMass - mass << " "
13933 << oldMass - mass //<< " " << area
13934 << " //vol " << vol - oldVol << " (" << oldVol - oldVol2 << ") " << setprecision(16)
13935 << timeStep() * (rhs - delta);
13936 if(m_noCellsInsideSpongeLayer > 0) cerr << " | Warning: sponge is on!";
13937 cerr << setprecision(6) << endl;
13938 if(ofl.is_open() && ofl.good()) {
13939 ofl << "mass defect" << setprecision(10) << globalTimeStep << " (" << delta * timeStep() << ") "
13940 << refMass - mass << " " << oldMass - mass //<< " " << area
13941 << " //vol " << vol - oldVol << " (" << oldVol - oldVol2 << ") " << timeStep() * (rhs - delta) << endl;
13942 ofl.close();
13943 }
13944 }
13945 if(m_initialCondition == 474) {
13946 cerr << domainId() << ": ERROR rho " << globalTimeStep << " " << m_bodyCenter[0] / m_bodyDiameter[0] << " // "
13947 << eRhoLoo << " " << eRhoL1 / counter << " " << sqrt(eRhoL2 / counter) << " // " << ERhoLoo << " "
13948 << ERhoL1 / (counter * FTS) << " " << sqrt(ERhoL2 / (counter * FTS));
13949 cerr << " ||| ERROR vel " << eVelLoo << " " << eVelL1 / counter << " " << sqrt(eVelL2 / counter) << " // "
13950 << EVelLoo << " " << EVelL1 / (counter * FTS) << " " << sqrt(EVelL2 / (counter * FTS)) << endl;
13951 if(domainId() == 0) {
13952 ofstream ofl;
13953 ofl.open("mass_error", ios_base::out | ios_base::app);
13954 if(ofl.is_open() && ofl.good()) {
13955 ofl << setprecision(16) << m_time << " " << fabs(refMass - mass) << " " << fabs(oldMass - mass) << " "
13956 << eRhoLoo << " " << eRhoL1 / counter << " " << eVelLoo << " " << eVelL1 / counter << endl;
13957 ofl.close();
13958 }
13959 }
13960 if(m_bodyCenter[0] > m_bodyDiameter[0]) mTerm(0, AT_, "one diameter traveled.");
13961 }
13962 oldMass = mass;
13963 oldVol2 = vol;
13964 firstRun = false;
13965 }
13966}
13967
13968
13973template <MInt nDim, class SysEqn>
13975 TRACE();
13976
13977 if(m_dualTimeStepping) return;
13978
13979 const MUint noFluxVars = FV->noVariables;
13980 const MUint noPVars = PV->noVariables;
13981 const MInt noBCells = m_fvBndryCnd->m_bndryCells->size();
13982 const MUint surfaceVarMemory = 2 * noPVars;
13983 MFloat* RESTRICT area = &a_surfaceArea(0);
13984 MFloat* const RESTRICT fluxes = ALIGNED_MF(&a_surfaceFlux(0, 0));
13985 MFloat* const RESTRICT surfaceVars = ALIGNED_F(&a_surfaceVariable(0, 0, 0));
13986
13987 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
13988 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
13989
13990 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
13991 if(a_isHalo(cellId)) continue;
13992
13993#if defined _ALE_FORM_
13994 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
13995#else
13996 if(a_hasProperty(cellId, SolverCell::IsSplitCell) || a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
13997#endif
13998
13999#ifdef _MB_DEBUG_
14000 MFloat totalArea = F0;
14001 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
14002 totalArea += m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
14003 }
14004#endif
14005
14006 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
14007 for(MInt i = 0; i < nDim; i++) {
14008 MInt srfcId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i];
14009 if(srfcId < 0) continue;
14010
14011#if defined _MB_DEBUG_ || !defined NDEBUG
14012 MFloat area0 = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
14013 MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
14014 ASSERT(fabs(area[srfcId] - area0 * fabs(nml)) < 1e-12,
14015 to_string(area[srfcId]) + " " + to_string(area0 * fabs(nml)));
14016#endif
14017
14018
14019#if defined _ALE_FORM_
14020 const MUint fluxOffset = srfcId * noFluxVars;
14021 const MUint offset = srfcId * surfaceVarMemory;
14022 MFloat* const RESTRICT flux = ALIGNED_MF(fluxes + fluxOffset);
14023 MFloat* const RESTRICT leftSurface = ALIGNED_F(surfaceVars + offset);
14024 const MFloat* const bndrySurf = &m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_primVars[0];
14025
14026 sysEqn().AusmALECorrection(i, area[srfcId], flux, leftSurface, bndrySurf);
14027#else
14028
14029 const MFloat PLR = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P];
14030 const MFloat VLR = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]];
14031
14032
14033 MFloatScratchSpace work(m_noCVars, FUN_, "work");
14034 for(MInt v = 0; v < m_noCVars; v++) {
14035 work[v] = F0;
14036 }
14037 work[CV->RHO_VV[i]] = PLR * area[srfcId];
14038 work[CV->RHO_E] = PLR * VLR * area[srfcId];
14039
14040 a_surfaceVariable(srfcId, 0, PV->VV[i]) = VLR;
14041 a_surfaceVariable(srfcId, 1, PV->VV[i]) = VLR;
14042
14043 const MFloat sign = (nml > F0) ? -F1 : F1;
14044 const MFloat dVdt = (a_cellVolume(cellId) - m_cellVolumesDt1[cellId]) / timeStep();
14045 const MFloat fac = area0 * POW2(nml) / mMax(m_eps, totalArea);
14046#ifdef _MB_DEBUG_
14047 for(MInt v = 0; v < m_noCVars; v++) {
14048 if(std::isnan(work[v]) || std::isnan(sign * fac * a_oldVariable(cellId, v) * dVdt)) {
14049 cerr << domainId() << ": cell " << cellId << " diverged after ALE formulation at " << globalTimeStep << " "
14050 << srfc << " " << i << " " << v << " " << a_hasProperty(cellId, SolverCell::WasInactive) << " /flx "
14051 << work[v] << " " << sign << " " << fac << " " << a_oldVariable(cellId, v) << " /vol " << dVdt << " "
14052 << a_cellVolume(cellId) << " " << m_cellVolumesDt1[cellId] << " /var " << PLR << " "
14053 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_primVars[v] << endl;
14054 }
14055 }
14056#endif
14057 for(MInt v = 0; v < m_noCVars; v++) {
14058 a_surfaceFlux(srfcId, v) = (sign * fac * a_oldVariable(cellId, v) * dVdt) + work[v];
14059 }
14060#endif
14061 }
14062 }
14063 }
14064}
14065
14066
14072template <MInt nDim, class SysEqn>
14074 TRACE();
14075
14076 MBool& mbSpongeLayer = m_static_updateSpongeLayer_mbSpongeLayer;
14077 MBool& first = m_static_updateSpongeLayer_first;
14078 if(first) {
14092 mbSpongeLayer = Context::getSolverProperty<MBool>("mbSpongeLayer", m_solverId, AT_, &mbSpongeLayer);
14093 first = false;
14094 }
14095 if(!mbSpongeLayer) {
14097 } else {
14098 if(m_spongeLayerThickness > F0) {
14099 MInt cellId;
14100 MFloat deltaP, deltaRho;
14101 MFloat FgammaMinusOne = F1 / (m_gamma - F1);
14102 MFloat fac = F1; // / ( m_RKalpha[ m_RKStep ] * timeStep() );
14103
14104
14105 for(MInt c = 0; c < m_noCellsInsideSpongeLayer; c++) {
14106 cellId = m_cellsInsideSpongeLayer[c];
14107
14108 // compute the forcing terms
14109 deltaP = (a_pvariable(cellId, PV->P) - m_PInfinity) * FgammaMinusOne;
14110 deltaRho = a_pvariable(cellId, PV->RHO) - m_rhoInfinity * m_targetDensityFactor;
14111
14112 if((m_initialCondition == 455) || (m_initialCondition == 456) || (m_initialCondition == 45300)) {
14113 a_rightHandSide(cellId, CV->RHO) +=
14114 a_spongeFactor(cellId) * fac * (a_variable(cellId, CV->RHO) - m_rhoInfinity) * a_cellVolume(cellId);
14115 a_rightHandSide(cellId, CV->RHO_E) +=
14116 a_spongeFactor(cellId) * fac * (a_variable(cellId, CV->RHO_E) - m_rhoEInfinity) * a_cellVolume(cellId);
14117 for(MInt i = 0; i < nDim; i++) {
14118 a_rightHandSide(cellId, CV->RHO_VV[i]) +=
14119 a_spongeFactor(cellId) * fac * (a_variable(cellId, CV->RHO_VV[i]) - F0) * a_cellVolume(cellId);
14120 }
14121 }
14122
14123 else if(m_initialCondition == 45301) {
14124 a_rightHandSide(cellId, CV->RHO) +=
14125 a_spongeFactor(cellId) * fac * (a_variable(cellId, CV->RHO) - m_rhoInfinity) * a_cellVolume(cellId);
14126 a_rightHandSide(cellId, CV->RHO_E) +=
14127 a_spongeFactor(cellId) * fac * (a_variable(cellId, CV->RHO_E) - m_rhoEInfinity) * a_cellVolume(cellId);
14128 for(MInt i = 0; i < nDim; i++) {
14129 a_rightHandSide(cellId, CV->RHO_VV[i]) += a_spongeFactor(cellId) * fac
14130 * (a_variable(cellId, CV->RHO_VV[i]) - m_rhoVVInfinity[i])
14131 * a_cellVolume(cellId);
14132 }
14133 }
14134
14135 else {
14136 a_rightHandSide(cellId, CV->RHO_E) += a_spongeFactor(cellId) * deltaP * fac * a_cellVolume(cellId);
14137 a_rightHandSide(cellId, CV->RHO) += a_spongeFactor(cellId) * deltaRho * fac * a_cellVolume(cellId);
14138 }
14139
14140 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
14141 for(MInt r = 0; r < m_noRansEquations; ++r) {
14142 a_rightHandSide(cellId, CV->RHO_NN[r]) +=
14143 a_spongeFactor(cellId) * deltaRho * a_pvariable(cellId, PV->NN[r]) * fac * a_cellVolume(cellId);
14144 }
14145 }
14146 // species
14147 for(MInt s = 0; s < m_noSpecies; s++)
14148 a_rightHandSide(cellId, CV->RHO_Y[s]) +=
14149 a_spongeFactor(cellId) * deltaRho * a_pvariable(cellId, PV->Y[s]) * fac * a_cellVolume(cellId);
14150 }
14151 }
14152 }
14153}
14154
14155
14161template <MInt nDim, class SysEqn>
14163 TRACE();
14164
14165 if(m_RKStep == m_noRKSteps - 1) {
14166 // applying the complete source term at the last RK-step for conservation!
14167 // i.e. devide by RK-factor
14168 // this requires that the rhs0 is free of the old/current source term
14169 MFloat beta = 1 / m_RKalpha[m_RKStep - 1];
14170 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
14171 if(!a_hasProperty(cellId, SolverCell::IsActive)) continue;
14172 for(MInt var = 0; var < CV->noVariables; var++) {
14173 a_rightHandSide(cellId, var) += beta * a_externalSource(cellId, var);
14174 if(std::isnan(a_externalSource(cellId, var))) {
14175 cerr << domainId() << " " << cellId << " " << var << " " << a_coordinate(cellId, 0) << " "
14176 << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, nDim - 1) << " " << var << endl;
14177 mTerm(1, AT_, "External source is nan!");
14178 }
14179 }
14180 }
14181 } else {
14182 if(m_RKStep != 3) {
14183 // apply partial old/current source term to the rightHandSide
14184 // here a devision by the rk-Factor is not necessary as the same source term is
14185 // also applied to the rhs0
14186 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
14187 if(!a_hasProperty(cellId, SolverCell::IsActive)) continue;
14188 for(MInt var = 0; var < CV->noVariables; var++) {
14189 a_rightHandSide(cellId, var) += a_externalSource(cellId, var);
14190 }
14191 }
14192 } else {
14193 // apply old external source
14194 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
14195 if(!a_hasProperty(cellId, SolverCell::IsActive)) continue;
14196 for(MInt var = 0; var < CV->noVariables; var++) {
14197 a_rightHandSide(cellId, var) += m_externalSourceDt1[cellId][var];
14198 }
14199 }
14200 }
14201 }
14202}
14203
14207template <MInt nDim, class SysEqn>
14209 TRACE();
14210
14211 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
14212 if(!a_hasProperty(cellId, SolverCell::IsActive)) continue;
14213 for(MInt var = 0; var < CV->noVariables; var++) {
14214 m_rhs0[cellId][var] -= m_externalSourceDt1[cellId][var];
14215 }
14216 }
14217}
14218
14223template <MInt nDim, class SysEqn>
14225 if(!m_hasExternalSource) return;
14226
14227 const MInt noCBytes = a_noCells() * m_noCVars * sizeof(MFloat);
14228 memcpy(&m_externalSourceDt1[0][0], &(a_externalSource(0, 0)), noCBytes);
14229}
14230
14235template <MInt nDim, class SysEqn>
14237 TRACE();
14238
14239 if(m_initialCondition == 22) { // If Pipe (case 22) change also IC in fvcartesiansolver
14240 MFloat noPeriodicDirs = 0;
14241 for(MInt dim = 0; dim < nDim; dim++) {
14242 if(grid().periodicCartesianDir(dim)) {
14243 m_volumeForcingDir = dim;
14244 noPeriodicDirs++;
14245 }
14246 }
14247 if(noPeriodicDirs > 1) mTerm(1, AT_, "Only one periodic direction is implemented for the pipe case");
14248 if(m_volumeForcingDir == -1) mTerm(-1, AT_, "IC 22 requires a volumeForcingDir");
14249
14250 // Reynolds set in properties is based on unit length L=1
14251 MInt Re_r = Context::getSolverProperty<MFloat>("Re", m_solverId, AT_) * m_pipeRadius;
14252 m_pipeRadius = Context::getSolverProperty<MFloat>("pipeRadius", m_solverId, AT_);
14253
14254 // Any other perpendicular direction indicates the pipe diameter
14255 const MInt rDir1 = ((m_volumeForcingDir + 1) % nDim);
14256 const MInt rDir2 = ((rDir1 + 1) % nDim);
14257 if(rDir1 == rDir2 || rDir1 == m_volumeForcingDir || rDir2 == m_volumeForcingDir)
14258 mTerm(-1, AT_, "Inconsistent dirs.");
14259
14260 const MFloat pipeLength = computeDomainLength(m_volumeForcingDir);
14261
14262 cerr0 << "Update infinity state for IC 22: found pipeRadius = " << m_pipeRadius
14263 << " and pipeLength = " << pipeLength << endl;
14264
14265 MFloat lambda = F0;
14266 if(Re_r < 1500) {
14267 lambda = 32.0 / Re_r;
14268 if(domainId() == 0) cerr << "IC 22, using case Re<1500" << endl;
14269 } else {
14270 lambda = 0.316 / pow(Re_r * F2, 0.25);
14271 if(domainId() == 0) cerr << "IC 22, using case Re>=1500" << endl;
14272 }
14273 MFloat reTau = Re_r * sqrt(lambda / F8);
14274 MFloat uTau = reTau * m_Ma * sqrt(m_TInfinity) / Re_r;
14275 MFloat deltaP = F2 * m_rhoInfinity * POW2(uTau) * (pipeLength) / m_pipeRadius;
14276 m_volumeAcceleration[m_volumeForcingDir] = deltaP / (m_rhoInfinity * pipeLength);
14277 }
14278
14279 // Not used in combination with the levelSet-solver!
14280 if(!m_constructGField) return;
14281
14282 if(m_initialCondition == 15 || m_initialCondition == 16 || m_initialCondition == 467) {
14283 m_rhoInfinity = F1;
14284 m_TInfinity = F1;
14285 m_PInfinity = sysEqn().pressure_ES(m_TInfinity, m_rhoInfinity);
14286 m_UInfinity = m_Ma;
14287 m_VInfinity = F0;
14288 m_WInfinity = F0;
14289
14290 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
14291 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
14292 m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
14293 m_rhoEInfinity = sysEqn().internalEnergy(m_PInfinity, m_rhoInfinity, POW2(m_Ma));
14294 m_hInfinity = sysEqn().enthalpy(m_PInfinity, m_rhoInfinity);
14295 sysEqn().m_Re0 = m_Re * SUTHERLANDLAW(m_TInfinity) / (m_rhoInfinity * m_UInfinity);
14296 sysEqn().m_muInfinity = SUTHERLANDLAW(m_TInfinity);
14297 m_timeRef = m_Ma;
14298 m_VVInfinity[0] = m_UInfinity;
14299 m_VVInfinity[1] = m_VInfinity;
14300 m_VVInfinity[2] = m_WInfinity;
14301 m_rhoVVInfinity[0] = m_rhoUInfinity;
14302 m_rhoVVInfinity[1] = m_rhoVInfinity;
14303 m_rhoVVInfinity[2] = m_rhoWInfinity;
14304
14305 if(m_restartFile) {
14306 m_log << "Restart Reynolds number: " << setprecision(15) << m_Re << " (Re_L=" << m_Re * (m_bbox[3] - m_bbox[0])
14307 << ")"
14308 << " " << sysEqn().m_Re0 << endl;
14309 }
14310 }
14311
14312 if((m_initialCondition == 465 || m_initialCondition == 466) && m_constructGField) {
14313 m_rhoInfinity = F1;
14314 m_TInfinity = F1;
14315 m_PInfinity = sysEqn().pressure_ES(m_TInfinity, m_rhoInfinity);
14316 m_UInfinity = m_Ma;
14317 m_VInfinity = F0;
14318 m_WInfinity = F0;
14319 m_VVInfinity[0] = m_UInfinity;
14320 m_VVInfinity[1] = m_VInfinity;
14321 m_VVInfinity[2] = m_WInfinity;
14322 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
14323 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
14324 m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
14325 m_rhoEInfinity = sysEqn().internalEnergy(m_PInfinity, m_rhoInfinity, POW2(m_Ma));
14326 m_hInfinity = sysEqn().enthalpy(m_PInfinity, m_rhoInfinity);
14327 sysEqn().m_Re0 = m_Re * SUTHERLANDLAW(m_TInfinity) / (m_rhoInfinity * m_UInfinity);
14328 m_timeRef = m_Ma;
14329 }
14330
14331
14332 m_U2 = F0;
14333 for(MInt i = 0; i < nDim; i++) {
14334 m_U2 += POW2(m_VVInfinity[i]);
14335 }
14336 m_rhoU2 = m_U2 * m_rhoInfinity;
14337}
14338
14339
14344template <MInt nDim, class SysEqn>
14346 return sysEqn().temperature_ES(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
14347}
14348
14352template <MInt nDim, class SysEqn>
14354 TRACE();
14355
14357 // for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14358 // a_resetPropertiesSolver(cellId);
14359 // }
14360
14361
14362 // ToDo: currently untested
14363 if(isActive()) {
14364 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) {
14365 if(m_zonal) {
14366 mDeallocate(m_LESVarAverageBal);
14367 if(globalTimeStep >= m_zonalAveragingTimeStep) {
14368 mAlloc(m_LESVarAverageBal, m_LESNoVarAverage, "m_LESVarAverage", AT_);
14369 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
14370 m_LESVarAverageBal[var].resize(noInternalCells());
14371 }
14372 }
14373 }
14374 }
14375 }
14376
14377 // set only restart to true for the next initSolutionStep call!
14378 m_onlineRestart = true;
14379
14380 if(!isActive()) {
14381 m_maxLevelBeforeAdaptation = -1;
14382 } else {
14383 m_maxLevelBeforeAdaptation = maxLevel();
14384 }
14385
14386 mAlloc(m_sweptVolumeBal, c_noCells(), "m_sweptVolumeBal", -F1, AT_);
14387}
14388
14389
14393template <MInt nDim, class SysEqn>
14395 TRACE();
14396
14397 m_loadBalancingReinitStage = 1;
14398
14399 // append the halo-cells
14400 m_cells.append(c_noCells() - m_cells.size());
14401
14402 copyGridProperties();
14403
14404 m_totalnoghostcells = 0;
14405 m_totalnosplitchilds = 0;
14406 ASSERT(m_cells.size() == c_noCells() && c_noCells() == a_noCells(), "");
14407
14408
14409 m_oldBndryCells.clear();
14410 std::map<MInt, std::vector<MFloat>>().swap(m_nearBoundaryBackup);
14411 std::vector<MInt>().swap(m_bndryLayerCells);
14412 std::vector<MInt>().swap(m_massRedistributionIds);
14413 std::vector<MFloat>().swap(m_massRedistributionVariables);
14414 std::vector<MFloat>().swap(m_massRedistributionRhs);
14415 std::vector<MFloat>().swap(m_massRedistributionVolume);
14416 std::vector<MFloat>().swap(m_massRedistributionSweptVol);
14417 std::vector<std::tuple<MInt, MInt, MInt>>().swap(m_temporarilyLinkedCells);
14418 mDeallocate(m_sendBufferSize);
14419 mDeallocate(m_receiveBufferSize);
14420 mDeallocate(g_mpiRequestMb);
14421 mDeallocate(m_linkedWindowCells);
14422 mDeallocate(m_linkedHaloCells);
14423 if(m_closeGaps) {
14424 mDeallocate(m_gapWindowCells);
14425 mDeallocate(m_gapHaloCells);
14426 }
14427
14428 // Nothing to do if solver is not active
14429 if(!grid().isActive()) {
14430 return;
14431 }
14432
14433 m_bndryGhostCellsOffset = a_noCells();
14434 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14435 a_bndryId(cellId) = -1;
14436 a_isBndryGhostCell(cellId) = false;
14437 a_hasProperty(cellId, SolverCell::IsSplitChild) = false;
14438 }
14439
14440 // this can only be done, after the halo property has been set above
14441 this->checkNoHaloLayers();
14442
14443 // ### from c'tor ###
14444 // compute min and max coordinates in the grid
14445 computeDomainAndSpongeDimensions();
14446 // ###
14447
14448 allocateCommunicationMemory();
14449
14450 if(!m_fvBndryCnd->m_cellMerging) {
14451 mDeallocate(m_fvBndryCnd->m_nearBoundaryWindowCells);
14452 mDeallocate(m_fvBndryCnd->m_nearBoundaryHaloCells);
14453 mAlloc(m_fvBndryCnd->m_nearBoundaryWindowCells, noNeighborDomains(), "m_nearBoundaryWindowCells", AT_);
14454 mAlloc(m_fvBndryCnd->m_nearBoundaryHaloCells, noNeighborDomains(), "m_nearBoundaryHaloCells", AT_);
14455 }
14456
14457 std::vector<MInt>().swap(m_splitCells);
14458 std::vector<std::vector<MInt>>().swap(m_splitChilds);
14459 std::map<MInt, MInt>().swap(m_splitChildToSplitCell);
14460 m_totalnosplitchilds = 0;
14461
14462 // during the balance cells are sorted again
14463 if(this->m_adaptation) {
14464 for(MInt i = 0; i < maxNoGridCells(); i++)
14465 m_recalcIds[i] = i;
14466 }
14467
14468 // Azimuthal Balance
14469 if(grid().azimuthalPeriodicity()) {
14470 m_azimuthalNearBoundaryBackup.clear();
14471 initAzimuthalCartesianHaloInterpolation();
14472
14473 MInt noFloatData_ = nDim + m_noFloatDataBalance;
14474 MInt noLongData = m_azimuthalNearBoundaryBackupMaxCount * m_noLongDataBalance;
14475 MInt noFloatData = m_azimuthalNearBoundaryBackupMaxCount * noFloatData_;
14476
14477 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
14478 for(MInt cnt = 0; cnt < m_azimuthalNearBoundaryBackupMaxCount; cnt++) {
14479 MInt longIndex = cnt * m_noLongDataBalance;
14480
14481 MLong gCellId = m_azimuthalNearBoundaryBackupBalLong[cellId * noLongData + longIndex];
14482
14483 if(gCellId == -1) {
14484 continue;
14485 }
14486
14487 ASSERT(gCellId == c_globalId(cellId), "Azimuthal balance, this is not correct. " + to_string(cellId) + " "
14488 + to_string(c_globalId(cellId)) + " " + to_string(gCellId) + " "
14489 + to_string(domainId()));
14490
14491 MInt offset = cnt * noFloatData_;
14492 vector<MFloat> tmpF(noFloatData_);
14493 vector<MUlong> tmpI(m_noLongData);
14494
14495 for(MInt d = offset; d < offset + noFloatData_; d++) {
14496 tmpF[d - offset] = m_azimuthalNearBoundaryBackupBalFloat[cellId * noFloatData + d];
14497 }
14498
14499 tmpI[0] = (MUlong)m_azimuthalNearBoundaryBackupBalLong[cellId * noLongData + longIndex + 1];
14500 tmpI[1] = (MUlong)m_azimuthalNearBoundaryBackupBalLong[cellId * noLongData + longIndex + 2];
14501
14502 m_azimuthalNearBoundaryBackup.insert(make_pair(gCellId, make_pair(tmpF, tmpI)));
14503 }
14504 }
14505
14506 mDeallocate(m_azimuthalNearBoundaryBackupBalFloat);
14507 mDeallocate(m_azimuthalNearBoundaryBackupBalLong);
14508
14509 m_wasBalanced = true;
14510 }
14511
14512 exchangeData(&a_variable(0, 0), CV->noVariables);
14513 exchangeData(&a_cellVolume(0), 1);
14514 exchangeData(&a_rightHandSide(0, 0), m_noFVars);
14515 if(m_dualTimeStepping) {
14516 exchangeData(&m_cellVolumesDt1[0], 1);
14517 }
14518 // change this for proper splitBalance where only boundary data is exchanged
14519 exchangeData(&m_sweptVolumeBal[0], 1);
14520
14521 // exchange properties that are of type MBool
14522 maia::mpi::exchangeBitset(grid().neighborDomains(), grid().haloCells(), grid().windowCells(), mpiComm(),
14523 &a_properties(0), a_noCells());
14524
14525 ScratchSpace<maia::fv::cell::BitsetType> propsBalance(a_noCells(), FUN_, "propsBalance");
14526 propsBalance.fill(maia::fv::cell::BitsetType());
14527
14528 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14529 setPrimitiveVariables(cellId);
14530 for(MInt v = 0; v < CV->noVariables; v++) {
14531 a_oldVariable(cellId, v) = a_variable(cellId, v);
14532 }
14533 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
14534 propsBalance[cellId][maia::fv::cell::p(SolverCell::IsMovingBnd)] =
14535 a_properties(cellId)[maia::fv::cell::p(SolverCell::IsMovingBnd)];
14536 propsBalance[cellId][maia::fv::cell::p(SolverCell::NearWall)] =
14537 a_properties(cellId)[maia::fv::cell::p(SolverCell::NearWall)];
14538 propsBalance[cellId][maia::fv::cell::p(SolverCell::IsInactive)] =
14539 a_properties(cellId)[maia::fv::cell::p(SolverCell::IsInactive)];
14540 propsBalance[cellId][maia::fv::cell::p(SolverCell::WasInactive)] =
14541 a_properties(cellId)[maia::fv::cell::p(SolverCell::WasInactive)];
14542 }
14543
14544 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
14545 a_resetPropertiesSolver(cellId);
14546 }
14547
14548 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
14549 assertValidGridCellId(cellId);
14550 if(m_dualTimeStepping) {
14551 m_cellVolumesDt2[cellId] = m_cellVolumesDt1[cellId];
14552 }
14553 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
14554 for(MInt j = 0; j < m_noFVars; j++) {
14555 m_rhs0[cellId][j] = a_rightHandSide(cellId, j);
14556 }
14557 a_hasProperty(cellId, SolverCell::IsMovingBnd) = propsBalance[cellId][maia::fv::cell::p(SolverCell::IsMovingBnd)];
14558 a_hasProperty(cellId, SolverCell::NearWall) = propsBalance[cellId][maia::fv::cell::p(SolverCell::NearWall)];
14559 a_hasProperty(cellId, SolverCell::IsInactive) = propsBalance[cellId][maia::fv::cell::p(SolverCell::IsInactive)];
14560 a_hasProperty(cellId, SolverCell::WasInactive) = propsBalance[cellId][maia::fv::cell::p(SolverCell::IsInactive)];
14561 }
14562
14563 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
14564 if(a_hasProperty(cellId, SolverCell::NearWall)) {
14565 vector<MFloat> tmp(max(m_noCVars + m_noFVars, 0) + 1);
14566 tmp[0] = m_cellVolumesDt1[cellId];
14567 for(MInt v = 0; v < m_noCVars; v++) {
14568 tmp[1 + v] = a_oldVariable(cellId, v);
14569 }
14570 for(MInt v = 0; v < m_noFVars; v++) {
14571 tmp[1 + m_noCVars + v] = m_rhs0[cellId][v];
14572 }
14573 m_nearBoundaryBackup.insert(make_pair(cellId, tmp));
14574 m_bndryLayerCells.push_back(cellId);
14575 }
14576 // a_hasProperty(cellId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::IsInactive);
14577 }
14578
14579 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
14580 if(a_hasProperty(cellId, SolverCell::IsMovingBnd)) {
14581 // ASSERT( !a_hasProperty( cellId, SolverCell::IsInactive ), "" );
14582 ASSERT(m_sweptVolumeBal[cellId] > -1, "something is wrong with m_sweptVolumeBal");
14583 m_oldBndryCells.insert(make_pair(cellId, m_sweptVolumeBal[cellId]));
14584 }
14585 }
14586
14587 if(grid().azimuthalPeriodicity()) {
14588 commAzimuthalPeriodicData(1);
14589 }
14590
14591
14592 // ToDo: currently untested
14593 if(m_zonal) {
14594 determineLESAverageCells();
14595 resetZonalLESAverage();
14596 resetZonalSolverData();
14597
14598 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) {
14599 if(globalTimeStep >= m_zonalAveragingTimeStep) {
14600 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
14601 // m_LESVarAverageBal[var].resize(c_noCells());
14602 MFloatScratchSpace exchangeLESVarAverageBal(c_noCells(), FUN_, "exchangeIsMovingBnd");
14603 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
14604 exchangeLESVarAverageBal[cellId] = m_LESVarAverageBal[var][cellId];
14605 }
14606 exchangeData(&exchangeLESVarAverageBal[0], 1);
14607 for(MInt i = 0; i < (MInt)m_LESAverageCells.size(); i++) {
14608 MInt cellId = m_LESAverageCells[i];
14609 m_LESVarAverage[var][i] = exchangeLESVarAverageBal[cellId];
14610 }
14611 }
14612 }
14613
14614 MInt cnt = (MInt)m_LESAverageCells.size();
14615 MPI_Allreduce(MPI_IN_PLACE, &cnt, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cnt");
14616 if(domainId() == 0) cerr << "m_noLESAverageCells: " << cnt << endl;
14617 }
14618 // Deallocate memory again
14619 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
14620 m_LESVarAverageBal[var].clear();
14621 }
14622 mDeallocate(m_LESVarAverageBal);
14623 }
14624
14625 copyGridProperties();
14626
14627#ifndef NDEBUG
14628 checkHaloCells();
14629#endif
14630
14631 // reset additional data
14632 mAlloc(m_sendBufferSize, noNeighborDomains(), "m_sendBufferSize", 0, AT_);
14633 mAlloc(m_receiveBufferSize, noNeighborDomains(), "m_receiveBufferSize", 0, AT_);
14634 mAlloc(g_mpiRequestMb, noNeighborDomains(), "g_mpiRequestMb", MPI_REQ_NULL, AT_);
14635 mAlloc(m_linkedWindowCells, noNeighborDomains(), "m_linkedWindowCells", AT_);
14636 mAlloc(m_linkedHaloCells, noNeighborDomains(), "m_linkedHaloCells", AT_);
14637
14638 for(MInt i = 0; i < noNeighborDomains(); i++) {
14639 m_linkedWindowCells[i].clear();
14640 m_linkedHaloCells[i].clear();
14641 }
14642
14643 if(m_closeGaps) {
14644 mAlloc(m_gapWindowCells, noNeighborDomains(), "m_gapWindowCells", AT_);
14645 mAlloc(m_gapHaloCells, noNeighborDomains(), "m_gapHaloCells", AT_);
14646 for(MInt i = 0; i < noNeighborDomains(); i++) {
14647 m_gapWindowCells[i].clear();
14648 m_gapHaloCells[i].clear();
14649 }
14650 }
14651
14652 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14653 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
14654 }
14655
14656 computeLocalBoundingBox();
14657
14658 ASSERT(m_cells.size() == c_noCells(), "");
14659
14660 if(this->m_adaptation) {
14661 m_adaptationSinceLastRestart = true;
14662 m_adaptationSinceLastRestartBackup = true;
14663 }
14664
14665 m_loadBalancingReinitStage = 2;
14666
14667#if defined _MB_DEBUG_ || !defined NDEBUG
14668 if(domainId() == 0) {
14669 cerr << "Checking cells after balance... ";
14670 }
14671 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
14672 for(MInt v = 0; v < CV->noVariables; v++) {
14673 if(std::isnan(a_variable(cellId, v)) && !a_hasProperty(cellId, SolverCell::IsInactive)) {
14674 cerr << "Nan in variable after balance " << cellId << " "
14675 << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << endl;
14676 }
14677 }
14678 if((a_variable(cellId, CV->RHO) < 0 || a_pvariable(cellId, PV->RHO) < 0)
14679 && !a_hasProperty(cellId, SolverCell::IsInactive)) {
14680 cerr << "Neg. density after balance" << cellId << endl;
14681 }
14682 }
14683 if(domainId() == 0) cerr << "finished. " << endl;
14684#endif
14685}
14686
14687
14692template <MInt nDim, class SysEqn>
14693void FvMbCartesianSolverXD<nDim, SysEqn>::balance(const MInt* const noCellsToReceiveByDomain,
14694 const MInt* const noCellsToSendByDomain,
14695 const MInt* const sortedCellId, const MInt oldNoCells) {
14696 TRACE();
14697
14698 // set only restart to true for the next initSolutionStep call!
14699 m_onlineRestart = true;
14700
14701 // additional data to the fv-solver to-be saved during the balancing:
14702 // if globalTimeStep < -1: nothing additionally
14703 // if globalTimeStep > -1:
14704 // - a_rightHandSide
14705 // - m_sweptVolume (in sweptVolBalance)
14706 // - a_properties (in propsBalance and later in propsBak)
14707 // if dualTimeStepping:
14708 // - m_cellVolumesDt1
14709
14710 if(!isActive()) {
14711 grid().update();
14712 FvCartesianSolverXD<nDim, SysEqn>::updateDomainInfo(-1, -1, MPI_COMM_NULL, AT_);
14713 return;
14714 }
14715
14716 MFloatScratchSpace RHS(noCellsToReceiveByDomain[noDomains()], CV->noVariables, FUN_, "RHS");
14717 MFloatScratchSpace cellVolumesDt1((m_dualTimeStepping ? noCellsToReceiveByDomain[noDomains()] : 1), FUN_,
14718 "cellVolumesDt1");
14719 ScratchSpace<maia::fv::cell::BitsetType> props(noCellsToReceiveByDomain[noDomains()], FUN_, "props");
14720 MFloatScratchSpace sweptVol(noCellsToReceiveByDomain[noDomains()], FUN_, "sweptVol");
14721
14722 MBool azimuthal = grid().azimuthalPeriodicity();
14723
14724 if(globalTimeStep > -1) {
14725 MFloatScratchSpace sweptVolBalance(oldNoCells, FUN_, "sweptVolBalance");
14726 ScratchSpace<maia::fv::cell::BitsetType> propsBalance(oldNoCells, FUN_, "propsBalance");
14727 MFloatScratchSpace rightHandSideBalance(oldNoCells, CV->noVariables, FUN_, "rightHandSideBalance");
14728 MFloatScratchSpace volumeDt1Balance(oldNoCells, FUN_, "volumeDt1Balance");
14729
14730 sweptVolBalance.fill(std::numeric_limits<MFloat>::lowest());
14731 propsBalance.fill(maia::fv::cell::BitsetType());
14732
14733 rightHandSideBalance.fill(-1);
14734 volumeDt1Balance.fill(-1);
14735
14736 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
14737 assertValidGridCellId(cellId);
14738 MInt gridCellId = grid().tree().solver2grid(cellId);
14739
14740 propsBalance(gridCellId) = a_properties(cellId);
14741
14742 for(MInt variable = 0; variable < CV->noVariables; variable++) {
14743 rightHandSideBalance(gridCellId, variable) = a_rightHandSide(cellId, variable);
14744 }
14745 }
14746 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
14747 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
14748 ASSERT(!a_isBndryGhostCell(cellId), "");
14749 if(a_isHalo(cellId)) continue;
14750 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
14751 assertValidGridCellId(cellId);
14752 MInt gridCellId = grid().tree().solver2grid(cellId);
14753 // ASSERT( gridCellId < noCellsToSendByDomain[noDomains()], "" );
14754 ASSERT(a_hasProperty(cellId, SolverCell::IsMovingBnd), "");
14755 sweptVolBalance(gridCellId) = m_sweptVolume[bndryId];
14756 }
14757
14758 if(m_dualTimeStepping) {
14759 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
14760 MInt gridCellId = grid().tree().solver2grid(cellId);
14761 volumeDt1Balance(gridCellId) = m_cellVolumesDt1[cellId];
14762 }
14763 }
14764
14765
14766 // Azimuthal periodicity
14767 {
14768 MInt noAziDataToSend = 1;
14769 MInt noAziDataToReceive = 1;
14770 MIntScratchSpace sndSizeAzi(noDomains(), FUN_, "sndSizeAzi");
14771 sndSizeAzi.fill(0);
14772 MIntScratchSpace rcvSizeAzi(noDomains(), FUN_, "rcvSizeAzi");
14773 rcvSizeAzi.fill(0);
14774 MIntScratchSpace sortedIdMap(oldNoCells, FUN_, "sortedIdMap");
14775 sortedIdMap.fill(0);
14776 if(azimuthal) {
14777 m_wasBalanced = true;
14778
14779 MIntScratchSpace sortedCntsAzi(oldNoCells, FUN_, "sortedCntsAzi");
14780 sortedCntsAzi.fill(0);
14781 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
14782 MInt gridCellId = grid().tree().solver2grid(cellId);
14783 if(sortedCellId[gridCellId] < 0) continue;
14784 MLong gCellId = c_globalId(cellId);
14785 sortedCntsAzi[sortedCellId[gridCellId]] = m_azimuthalNearBoundaryBackup.count(gCellId);
14786 }
14787 MInt cnt = 0;
14788 for(MInt i = 0; i < oldNoCells; i++) {
14789 sortedIdMap[i] = cnt;
14790 cnt += sortedCntsAzi[i];
14791 }
14792 MInt offset = 0;
14793 for(MInt i = 0; i < noDomains(); i++) {
14794 for(MInt j = 0; j < noCellsToSendByDomain[i]; j++) {
14795 sndSizeAzi[i] += sortedCntsAzi[offset + j];
14796 }
14797 offset += noCellsToSendByDomain[i];
14798 }
14799 MIntScratchSpace dummyScratch(noDomains(), FUN_, "dummyScratch");
14800 dummyScratch.fill(1);
14801 maia::mpi::exchangeData(&sndSizeAzi[0], domainId(), noDomains(), mpiComm(), 1, &dummyScratch[0],
14802 &dummyScratch[0], &rcvSizeAzi[0]);
14803
14804 noAziDataToSend = mMax(1, std::accumulate(&sndSizeAzi[0], &sndSizeAzi[0] + noDomains(), 0));
14805 noAziDataToReceive = mMax(1, std::accumulate(&rcvSizeAzi[0], &rcvSizeAzi[0] + noDomains(), 0));
14806 }
14807
14808 ScratchSpace<MLong> globalIdAzi(noAziDataToReceive, FUN_, "globalIdAzi");
14809 MFloatScratchSpace cellVolumesAzi(noAziDataToReceive, FUN_, "cellVolumesAzi");
14810 MFloatScratchSpace cellVolumesDt1Azi(noAziDataToReceive, FUN_, "cellVolumesDt1Azi");
14811 MFloatScratchSpace sweptVolAzi(noAziDataToReceive, FUN_, "sweptVolAzi");
14812 ScratchSpace<MUlong> bndryCntAzi(noAziDataToReceive, FUN_, "bndryCntAzi");
14813 ScratchSpace<MUlong> propsAzi(noAziDataToReceive, FUN_, "propsAzi");
14814 MFloatScratchSpace variablesAzi(noAziDataToReceive, CV->noVariables, FUN_, "variablesAzi");
14815 MFloatScratchSpace imageCoordsAzi(noAziDataToReceive, nDim, FUN_, "imageCoordsAzi");
14816 globalIdAzi.fill(-1);
14817 cellVolumesAzi.fill(-1.0);
14818 cellVolumesDt1Azi.fill(-1.0);
14819 sweptVolAzi.fill(std::numeric_limits<MFloat>::lowest());
14820 bndryCntAzi.fill(0);
14821 propsAzi.fill(0);
14822 variablesAzi.fill(-1.0);
14823 imageCoordsAzi.fill(-1.0);
14824 MLongScratchSpace globalIdAziBalance(noAziDataToSend, FUN_, "globalIdAziBalance");
14825 MFloatScratchSpace cellVolumesAziBalance(noAziDataToSend, FUN_, "cellVolumesAziBalance");
14826 MFloatScratchSpace cellVolumesDt1AziBalance(noAziDataToSend, FUN_, "cellVolumesDt1AziBalance");
14827 MFloatScratchSpace sweptVolAziBalance(noAziDataToSend, FUN_, "sweptVolAziBalance");
14828 ScratchSpace<MUlong> bndryCntAziBalance(noAziDataToSend, FUN_, "bndryCntAziBalance");
14829 ScratchSpace<MUlong> propsAziBalance(noAziDataToSend, FUN_, "propsAziBalance");
14830 MFloatScratchSpace variablesAziBalance(noAziDataToSend, CV->noVariables, FUN_, "variablesAziBalance");
14831 MFloatScratchSpace imageCoordsAziBalance(noAziDataToSend, nDim, FUN_, "imageCoordsAziAziBalance");
14832 globalIdAziBalance.fill(-1);
14833 cellVolumesAziBalance.fill(-1);
14834 cellVolumesDt1AziBalance.fill(-1);
14835 sweptVolAziBalance.fill(std::numeric_limits<MFloat>::lowest());
14836 bndryCntAziBalance.fill(0);
14837 propsAziBalance.fill(0);
14838 variablesAziBalance.fill(-1.0);
14839 imageCoordsAziBalance.fill(-1.0);
14840
14841 if(azimuthal) {
14842 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
14843 MInt gridCellId = grid().tree().solver2grid(cellId);
14844 if(sortedCellId[gridCellId] < 0) continue;
14845 MLong gCellId = c_globalId(cellId);
14846 if(m_azimuthalNearBoundaryBackup.count(gCellId) != 0) {
14847 MInt cnt = 0;
14848 auto range = m_azimuthalNearBoundaryBackup.equal_range(gCellId);
14849 for(auto it = range.first; it != range.second; ++it) {
14850 globalIdAziBalance(sortedIdMap[sortedCellId[gridCellId]] + cnt) = gCellId;
14851 cellVolumesAziBalance(sortedIdMap[sortedCellId[gridCellId]] + cnt) = (it->second).first[nDim];
14852 cellVolumesDt1AziBalance(sortedIdMap[sortedCellId[gridCellId]] + cnt) = (it->second).first[nDim + 1];
14853 sweptVolAziBalance(sortedIdMap[sortedCellId[gridCellId]] + cnt) = (it->second).first[nDim + 2];
14854 bndryCntAziBalance(sortedIdMap[sortedCellId[gridCellId]] + cnt) = (it->second).second[0];
14855 propsAziBalance(sortedIdMap[sortedCellId[gridCellId]] + cnt) = (it->second).second[1];
14856 for(MInt v = 0; v < CV->noVariables; v++) {
14857 variablesAziBalance(sortedIdMap[sortedCellId[gridCellId]] + cnt, v) = (it->second).first[nDim + 3 + v];
14858 }
14859 for(MInt d = 0; d < nDim; d++) {
14860 imageCoordsAziBalance(sortedIdMap[sortedCellId[gridCellId]] + cnt, d) = (it->second).first[d];
14861 }
14862 cnt++;
14863 }
14864 }
14865 }
14866
14867 maia::mpi::exchangeData(&globalIdAziBalance[0], domainId(), noDomains(), mpiComm(), 1, &sndSizeAzi[0],
14868 &rcvSizeAzi[0], &globalIdAzi[0]);
14869 maia::mpi::exchangeData(&cellVolumesAziBalance[0], domainId(), noDomains(), mpiComm(), 1, &sndSizeAzi[0],
14870 &rcvSizeAzi[0], &cellVolumesAzi[0]);
14871 maia::mpi::exchangeData(&cellVolumesDt1AziBalance[0], domainId(), noDomains(), mpiComm(), 1, &sndSizeAzi[0],
14872 &rcvSizeAzi[0], &cellVolumesDt1Azi[0]);
14873 maia::mpi::exchangeData(&sweptVolAziBalance[0], domainId(), noDomains(), mpiComm(), 1, &sndSizeAzi[0],
14874 &rcvSizeAzi[0], &sweptVolAzi[0]);
14875 maia::mpi::exchangeData(&bndryCntAziBalance[0], domainId(), noDomains(), mpiComm(), 1, &sndSizeAzi[0],
14876 &rcvSizeAzi[0], &bndryCntAzi[0]);
14877 maia::mpi::exchangeData(&propsAziBalance[0], domainId(), noDomains(), mpiComm(), 1, &sndSizeAzi[0],
14878 &rcvSizeAzi[0], &propsAzi[0]);
14879 maia::mpi::exchangeData(&variablesAziBalance[0], domainId(), noDomains(), mpiComm(), CV->noVariables,
14880 &sndSizeAzi[0], &rcvSizeAzi[0], &variablesAzi[0]);
14881 maia::mpi::exchangeData(&imageCoordsAziBalance[0], domainId(), noDomains(), mpiComm(), nDim, &sndSizeAzi[0],
14882 &rcvSizeAzi[0], &imageCoordsAzi[0]);
14883
14884
14885 MInt offset = 0;
14886 m_azimuthalNearBoundaryBackup.clear();
14887 MInt noFloatData = nDim + sysEqn().CV->noVariables + 3;
14888 MInt noIntData = 2;
14889 for(MInt i = 0; i < noDomains(); i++) {
14890 for(MInt j = 0; j < rcvSizeAzi[i]; j++) {
14891 MInt ind = offset + j;
14892 MLong gCellId = globalIdAzi[ind];
14893 vector<MFloat> tmpF(mMax(noFloatData + nDim, nDim + 3));
14894 vector<MUlong> tmpI(noIntData);
14895 for(MInt d = 0; d < nDim; d++) {
14896 tmpF[d] = imageCoordsAzi(ind, d); // Image coordinate
14897 }
14898 tmpF[nDim] = cellVolumesAzi[ind]; // cellVol
14899 tmpF[nDim + 1] = cellVolumesDt1Azi[ind]; // cellVolDt1
14900 tmpF[nDim + 2] = sweptVolAzi[ind]; // sweptVol
14901 for(MInt v = 0; v < CV->noVariables; v++) {
14902 tmpF[nDim + 3 + v] = variablesAzi(ind, v);
14903 }
14904
14905 tmpI[0] = bndryCntAzi[ind]; // oldBndryCnt
14906 tmpI[1] = propsAzi[ind]; // cell properties
14907 m_azimuthalNearBoundaryBackup.insert(make_pair(gCellId, make_pair(tmpF, tmpI)));
14908 }
14909 offset += rcvSizeAzi[i];
14910 }
14911 }
14912 }
14913
14914 RHS.fill(-1.0);
14915 cellVolumesDt1.fill(-1.0);
14917 sweptVol.fill(std::numeric_limits<MFloat>::lowest());
14918
14919 maia::mpi::communicateData(&rightHandSideBalance(0, 0), oldNoCells, sortedCellId, noDomains(), domainId(),
14920 mpiComm(), noCellsToSendByDomain, noCellsToReceiveByDomain, CV->noVariables, &RHS[0]);
14921 if(m_dualTimeStepping) {
14922 maia::mpi::communicateData(&volumeDt1Balance[0], oldNoCells, sortedCellId, noDomains(), domainId(), mpiComm(),
14923 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &cellVolumesDt1[0]);
14924 }
14925
14926 maia::mpi::communicateBitsetData(&propsBalance[0], oldNoCells, sortedCellId, noDomains(), domainId(), mpiComm(),
14927 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &props[0]);
14928 maia::mpi::communicateData(&sweptVolBalance[0], oldNoCells, sortedCellId, noDomains(), domainId(), mpiComm(),
14929 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &sweptVol[0]);
14930
14931#ifndef NDEBUG
14932 // Timw: avoided as bndryCells exist which are inactive and notMovingBand
14933 // if during cutCell-computation no valid surfaces can be found!
14934 /*
14935 {
14936 MIntScratchSpace nbTest(m_cells.size(), 2, FUN_, "nbTest");
14937 nbTest.fill(0);
14938 for( MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++ ) {
14939 MInt cellId = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_cellId;
14940 //if ( a_isHalo(cellId) ) continue;
14941 if ( !a_hasProperty(cellId, SolverCell::IsSplitChild) ) {
14942 ASSERT( cellId > -1 && cellId < oldNoCells, "" );
14943 }
14944 ASSERT( a_hasProperty( cellId, SolverCell::IsMovingBnd ), "" );
14945 nbTest( cellId, 0 ) = 1;
14946 }
14947 for ( MUint c = 0; c < m_bndryLayerCells.size(); c++ ) {
14948 const MInt cellId = m_bndryLayerCells[ c ];
14949 //if ( a_isHalo(cellId) ) continue;
14950 //if ( a_hasProperty(cellId, SolverCell::IsSplitChild) ) continue;
14951 nbTest( cellId, 1 ) = 1;
14952 }
14953 for ( MInt cellId = 0; cellId < a_noCells(); cellId++ ) {
14954 //if ( a_isHalo(cellId) ) continue;
14955 //if ( a_hasProperty(cellId, SolverCell::IsSplitChild) ) continue;
14956 if ( nbTest(cellId, 0) != (MInt)a_hasProperty( cellId, SolverCell::IsMovingBnd ) )
14957 cerr << cellId << " " << oldNoCells << " " << a_hasProperty(cellId, SolverCell::IsSplitChild) << " " <<
14958 nbTest(cellId, 0) << " " << nbTest(cellId, 1)
14959 << " " << (MInt)a_hasProperty( cellId, SolverCell::IsMovingBnd ) << " " << a_isHalo( cellId) << endl;
14960 ASSERT( nbTest(cellId, 0) == (MInt)a_hasProperty( cellId, SolverCell::IsMovingBnd ), to_string(nbTest(cellId,
14961 0))+" "+to_string(nbTest(cellId, 1))
14962 +" "+to_string((MInt)a_hasProperty( cellId, SolverCell::IsMovingBnd )) );
14963 ASSERT( nbTest(cellId, 1) == (MInt)a_hasProperty( cellId, SolverCell::NearWall ), to_string(nbTest(cellId, 1))
14964 +" "+to_string((MInt)a_hasProperty( cellId, SolverCell::NearWall )) );
14965 if ( a_hasProperty( cellId, SolverCell::IsMovingBnd ) ) ASSERT( m_oldBndryCells.count(cellId) == 1, "" );
14966 }
14967 }
14968 */
14969#endif
14970 }
14971
14972 FvCartesianSolverXD<nDim, SysEqn>::balance(noCellsToReceiveByDomain, noCellsToSendByDomain, sortedCellId, oldNoCells);
14973
14974 ASSERT(m_cells.size() == c_noCells(), "");
14975
14976 if(globalTimeStep > -1) {
14977 MFloatScratchSpace sweptVolBak(a_noCells(), FUN_, "sweptVolBak");
14978 ScratchSpace<maia::fv::cell::BitsetType> propsBak(a_noCells(), FUN_, "propsBak");
14979
14980 sweptVolBak.fill(std::numeric_limits<MFloat>::lowest());
14981 propsBak.fill(maia::fv::cell::BitsetType());
14982
14983 // Step 1: set properties for all Internal-Cells
14984
14985 // Iterate over all received cells (already sorted by global id)
14986 MInt cnt = 0;
14987 for(MInt gridCellId = 0; gridCellId < noCellsToReceiveByDomain[noDomains()]; gridCellId++) {
14988 if(!grid().raw().treeb().solver(gridCellId, m_solverId)) continue;
14989
14990 MInt cellId = cnt;
14991
14992 if(!grid().raw().bitOffset()) {
14993 ASSERT(grid().tree().solver2grid(cellId) == gridCellId, "");
14994 }
14995
14996 // Set solver data
14997 for(MInt j = 0; j < CV->noVariables; j++) {
14998 a_rightHandSide(cellId, j) = RHS(gridCellId, j);
14999 }
15000 if(m_dualTimeStepping) {
15001 m_cellVolumesDt1[cellId] = cellVolumesDt1(gridCellId);
15002 }
15003 assertValidGridCellId(cellId);
15004
15005 sweptVolBak(cellId) = sweptVol(gridCellId);
15006 propsBak(cellId) = props(gridCellId);
15007
15008 cnt++;
15009 }
15010
15011 // Step 2: exchange additiondal properties
15012
15013 maia::mpi::exchangeBitset(grid().neighborDomains(), grid().haloCells(), grid().windowCells(), mpiComm(),
15014 &propsBak[0], m_cells.size());
15015 exchangeData(&a_rightHandSide(0, 0), CV->noVariables);
15016 exchangeData(&sweptVolBak[0], 1);
15017 if(m_dualTimeStepping) {
15018 exchangeData(&m_cellVolumesDt1[0], 1);
15019 }
15020
15021 // Step 3: set additional properties for all cells (also for ghost-cells)
15022
15023 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
15024 assertValidGridCellId(cellId);
15025 if(m_dualTimeStepping) {
15026 m_cellVolumesDt2[cellId] = m_cellVolumesDt1[cellId];
15027 }
15028 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
15029 for(MInt j = 0; j < CV->noVariables; j++) {
15030 m_rhs0[cellId][j] = a_rightHandSide(cellId, j);
15031 }
15032 a_hasProperty(cellId, SolverCell::IsMovingBnd) = propsBak[cellId][maia::fv::cell::p(SolverCell::IsMovingBnd)];
15033 a_hasProperty(cellId, SolverCell::NearWall) = propsBak[cellId][maia::fv::cell::p(SolverCell::NearWall)];
15034 a_hasProperty(cellId, SolverCell::IsInactive) = propsBak[cellId][maia::fv::cell::p(SolverCell::IsInactive)];
15035 a_hasProperty(cellId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::IsInactive);
15036 }
15037
15038#ifndef NDEBUG
15039 checkHaloCells();
15040#endif
15041
15042 m_nearBoundaryBackup.clear();
15043 m_bndryLayerCells.clear();
15044 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
15045 if(a_hasProperty(cellId, SolverCell::NearWall)) {
15046 vector<MFloat> tmp(max(m_noCVars + m_noFVars, 0) + 1);
15047 tmp[0] = m_cellVolumesDt1[cellId];
15048 for(MInt v = 0; v < m_noCVars; v++) {
15049 tmp[1 + v] = a_oldVariable(cellId, v);
15050 }
15051 for(MInt v = 0; v < m_noFVars; v++) {
15052 tmp[1 + m_noCVars + v] = m_rhs0[cellId][v];
15053 }
15054 m_nearBoundaryBackup.insert(make_pair(cellId, tmp));
15055 m_bndryLayerCells.push_back(cellId);
15056 }
15057 }
15058
15059 m_oldBndryCells.clear();
15060 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
15061 if(a_hasProperty(cellId, SolverCell::IsMovingBnd)) {
15062 // ASSERT( !a_hasProperty( cellId, SolverCell::IsInactive ), "" );
15063 m_oldBndryCells.insert(make_pair(cellId, sweptVolBak[cellId]));
15064 }
15065 }
15066
15067 if(azimuthal) {
15068 initAzimuthalCartesianHaloInterpolation();
15069 commAzimuthalPeriodicData(1);
15070 }
15071 }
15072
15073 mDeallocate(m_sendBufferSize);
15074 mDeallocate(m_receiveBufferSize);
15075 mDeallocate(g_mpiRequestMb);
15076 mDeallocate(m_linkedWindowCells);
15077 mDeallocate(m_linkedHaloCells);
15078 mAlloc(m_sendBufferSize, noNeighborDomains(), "m_sendBufferSize", 0, AT_);
15079 mAlloc(m_receiveBufferSize, noNeighborDomains(), "m_receiveBufferSize", 0, AT_);
15080 mAlloc(g_mpiRequestMb, noNeighborDomains(), "g_mpiRequestMb", MPI_REQ_NULL, AT_);
15081 mAlloc(m_linkedWindowCells, noNeighborDomains(), "m_linkedWindowCells", AT_);
15082 mAlloc(m_linkedHaloCells, noNeighborDomains(), "m_linkedHaloCells", AT_);
15083
15084
15085 for(MInt i = 0; i < noNeighborDomains(); i++) {
15086 m_linkedWindowCells[i].clear();
15087 m_linkedHaloCells[i].clear();
15088 // m_fvBndryCnd->m_nearBoundaryWindowCells[i].clear();
15089 // m_fvBndryCnd->m_nearBoundaryHaloCells[i].clear();
15090 }
15091
15092 if(m_closeGaps) {
15093 mDeallocate(m_gapWindowCells);
15094 mDeallocate(m_gapHaloCells);
15095 mAlloc(m_gapWindowCells, noNeighborDomains(), "m_gapWindowCells", AT_);
15096 mAlloc(m_gapHaloCells, noNeighborDomains(), "m_gapHaloCells", AT_);
15097 for(MInt i = 0; i < noNeighborDomains(); i++) {
15098 m_gapWindowCells[i].clear();
15099 m_gapHaloCells[i].clear();
15100 }
15101 }
15102
15103 m_massRedistributionIds.clear();
15104 m_massRedistributionVariables.clear();
15105 m_massRedistributionRhs.clear();
15106 m_massRedistributionVolume.clear();
15107 m_massRedistributionSweptVol.clear();
15108 m_temporarilyLinkedCells.clear();
15109
15110 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
15111 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
15112 }
15113
15114 computeLocalBoundingBox();
15115
15116 if(azimuthal) {
15117 initAzimuthalCartesianHaloInterpolation();
15118 }
15119
15120 ASSERT(m_cells.size() == c_noCells(), "");
15121
15122 // check-Cells:
15123
15124#if defined _MB_DEBUG_ || !defined NDEBUG
15125 if(domainId() == 0) {
15126 cerr << "Checking cells after balance... ";
15127 }
15128 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
15129 for(MInt v = 0; v < CV->noVariables; v++) {
15130 if(std::isnan(a_variable(cellId, v)) && !a_hasProperty(cellId, SolverCell::IsInactive)
15131 && a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
15132 cerr << "Nan in variable after balance " << cellId << " "
15133 << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << endl;
15134 }
15135 }
15136 if((a_variable(cellId, CV->RHO) < 0 || a_pvariable(cellId, PV->RHO) < 0)
15137 && !a_hasProperty(cellId, SolverCell::IsInactive)) {
15138 cerr << "Neg. density after balance" << cellId << endl;
15139 }
15140 }
15141 cerr0 << "finished. " << endl;
15142#endif
15143}
15144
15145
15148template <MInt nDim, class SysEqn>
15150 TRACE();
15151
15152 mDeallocate(m_sweptVolumeBal);
15153
15155
15156 if(!grid().isActive()) {
15157 return;
15158 }
15159
15160 setRungeKuttaFunctionPointer();
15161
15162 if(globalTimeStep > 0) {
15163 if(!m_trackMovingBndry) {
15164 m_fvBndryCnd->m_cellCoordinatesCorrected = false;
15165 // necessary to recreate bndryCells after balance
15166 // if otherwise returning from reInitSolutionStep!!
15167 // TODO labels:FVMB,totest check mode 2, probably best to use mode 0 just after adaptation!
15168 preSolutionStep(0);
15169 // preSolutionStep(2);
15170 }
15171 leastSquaresReconstruction(); // Update slopes
15172 }
15173}
15174
15175
15180template <MInt nDim, class SysEqn>
15183
15184 ASSERT(grid().raw().a_hasProperty(gridCellId, Cell::WasRefined), "");
15185
15186 const MInt childLevel = grid().raw().a_level(gridCellId) + 1;
15187 const MFloat childVolume = grid().cellVolumeAtLevel(childLevel);
15188
15189 const MInt solverCellId = grid().tree().grid2solver(gridCellId);
15190
15191 if(!g_multiSolverGrid) ASSERT(solverCellId == gridCellId, "");
15192
15193 if(solverCellId < 0) return;
15194
15195 // the fv-solver part has already added the cell to the solver!
15196 ASSERT(c_noChildren(solverCellId) > 0, "");
15197
15198 MInt noAddedChilds = 0;
15199
15200 for(MInt c = 0; c < grid().m_maxNoChilds; c++) {
15201 const MInt gridChildId = grid().raw().a_childId(gridCellId, c);
15202
15203 if(gridChildId < 0) continue;
15204
15205 // Skip if cell is a partition level ancestor and its child was not newly created
15206 if(!grid().raw().a_hasProperty(gridChildId, Cell::WasNewlyCreated)
15207 && grid().raw().a_hasProperty(gridCellId, Cell::IsPartLvlAncestor)) {
15208 continue;
15209 }
15210
15211 const MInt solverChildId = grid().tree().grid2solver(gridChildId);
15212
15213 if(solverChildId < 0) continue;
15214
15215 ASSERT(solverChildId == c_childId(solverCellId, c), "");
15216 noAddedChilds++;
15217
15218 for(MInt v = 0; v < m_noFVars; v++) {
15219 m_rhs0[solverChildId][v] = FFPOW2(nDim) * m_rhs0[solverCellId][v];
15220 }
15221
15222 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
15223 a_levelSetValuesMb(solverChildId, set) = a_levelSetValuesMb(solverCellId, set);
15224 a_associatedBodyIds(solverChildId, set) = a_associatedBodyIds(solverCellId, set);
15225 }
15226 m_cellVolumesDt1[solverChildId] = childVolume;
15227 if(m_dualTimeStepping) m_cellVolumesDt2[solverChildId] = childVolume;
15228
15229 a_isGapCell(solverChildId) = a_isGapCell(solverCellId);
15230 a_wasGapCell(solverChildId) = a_wasGapCell(solverCellId);
15231
15232 a_hasProperty(solverChildId, SolverCell::WasInactive) = a_hasProperty(solverCellId, SolverCell::WasInactive);
15233
15234 // if a solverCell is oldBndryCell, all childs are set aswell
15235 // the childs will be corrected later!
15236 // parenta are remaining, to identify the just added cells after the adaptation
15237 auto it = m_oldBndryCells.find(solverCellId);
15238 if(it != m_oldBndryCells.end()) {
15239 const MFloat sweptVol = it->second;
15240 m_oldBndryCells.insert(make_pair(solverChildId, sweptVol));
15241 ASSERT(m_bndryLevelJumps, "");
15242 }
15243
15244 if(grid().azimuthalPeriodicity()) {
15245 // TODO
15246 }
15247 }
15248
15249 if(noAddedChilds > 0) {
15250 a_isGapCell(solverCellId) = false;
15251 a_wasGapCell(solverCellId) = false;
15252 }
15253}
15254
15255
15260template <MInt nDim, class SysEqn>
15262 const MInt solverCellId = grid().tree().grid2solver(gridCellId);
15263 ASSERT(solverCellId > -1 && solverCellId < m_cells.size(), "");
15264
15265 if(!g_multiSolverGrid) {
15266 ASSERT(solverCellId == gridCellId, "");
15267 ASSERT((m_cells.size() - grid().raw().treeb().size()) <= grid().m_maxNoChilds, "");
15268 }
15269
15270 ASSERT(grid().raw().a_noChildren(gridCellId) > 0, "");
15271
15272 // reset the solverCell-properties for the new leaf-cell:
15273 //- cellVolumeDt1
15274 //- oldVariable (this time with Dt1-volume!)
15275 //- rhs0
15276 m_cellVolumesDt1[solverCellId] = F0;
15277 for(MInt v = 0; v < m_noCVars; v++) {
15278 a_oldVariable(solverCellId, v) = F0;
15279 }
15280 for(MInt v = 0; v < m_noFVars; v++) {
15281 m_rhs0[solverCellId][v] = F0;
15282 }
15283 // reset solverCell-properties
15284 a_hasProperty(solverCellId, SolverCell::WasInactive) = false;
15285
15286 MBool wasGapCell = false;
15287 MBool isGapCell = false;
15288 MBool hasBndryCell = false;
15289 MFloat sweptVol = 0;
15290
15291 MInt wasInactive = 0;
15292 MInt noRemovedChilds = 0;
15293
15294 for(MInt c = 0; c < grid().m_maxNoChilds; c++) {
15295 const MInt gridChildId = grid().raw().a_childId(gridCellId, c);
15296 const MInt childId = c_childId(solverCellId, c);
15297 if(childId < 0) continue;
15298 noRemovedChilds++;
15299
15300 ASSERT(grid().tree().solver2grid(childId) == gridChildId, "");
15301
15302 if(!g_multiSolverGrid) ASSERT(childId == gridChildId, "");
15303
15304 if(a_wasGapCell(childId)) wasGapCell = true;
15305 if(a_isGapCell(childId)) isGapCell = true;
15306
15307 if(a_hasProperty(childId, SolverCell::WasInactive)) {
15308 wasInactive++;
15309 } else {
15310 MFloat vol1 = m_cellVolumesDt1[childId];
15311 m_cellVolumesDt1[solverCellId] += vol1;
15312 for(MInt v = 0; v < m_noCVars; v++) {
15313 a_oldVariable(solverCellId, v) += vol1 * a_oldVariable(childId, v);
15314 }
15315 for(MInt v = 0; v < m_noFVars; v++) {
15316 m_rhs0[solverCellId][v] += m_rhs0[childId][v];
15317 }
15318 }
15319
15320 {
15321 auto it = m_oldBndryCells.find(childId);
15322 if(it != m_oldBndryCells.end()) {
15323 hasBndryCell = true;
15324 sweptVol += it->second;
15325 ASSERT(!a_hasProperty(childId, SolverCell::WasInactive) || m_maxLevelDecrease, "");
15326 m_oldBndryCells.erase(it);
15327 ASSERT(m_bndryLevelJumps, "");
15328 }
15329 }
15330 {
15331 auto it = m_nearBoundaryBackup.find(childId);
15332 if(it != m_nearBoundaryBackup.end()) {
15333 m_nearBoundaryBackup.erase(it);
15334 }
15335 }
15336
15337 if(grid().azimuthalPeriodicity()) {
15338 // TODO
15339 }
15340 }
15341
15342 // update variables and properties for the new leaf-cell:
15343 if(wasInactive == noRemovedChilds) {
15344 a_hasProperty(solverCellId, SolverCell::WasInactive) = true;
15345
15346 // if of all childs were inactive, default variables are set!
15347 m_cellVolumesDt1[solverCellId] = grid().gridCellVolume(a_level(solverCellId));
15348 for(MInt v = 0; v < m_noFVars; v++) {
15349 m_rhs0[solverCellId][v] = 0;
15350 }
15351
15352 a_oldVariable(solverCellId, CV->RHO) = m_rhoInfinity;
15353 a_oldVariable(solverCellId, CV->RHO_E) = m_rhoEInfinity;
15354 for(MInt dir = 0; dir < nDim; dir++) {
15355 a_oldVariable(solverCellId, CV->RHO_VV[dir]) = m_rhoVVInfinity[dir];
15356 }
15357
15358 } else {
15359 for(MInt v = 0; v < m_noCVars; v++) {
15360 a_oldVariable(solverCellId, v) /= mMax(m_volumeThreshold, m_cellVolumesDt1[solverCellId]);
15361 }
15362 }
15363
15364 if(wasGapCell) a_wasGapCell(solverCellId) = true;
15365 if(isGapCell) a_isGapCell(solverCellId) = true;
15366 // NOTE: insert new bndryCells to coarseOldBndryCell sorted vector and
15367 // update according to current sweptVolume (see correctCoarseBndryCellVolume)
15368 // if they remain a bndryCell
15369 if(hasBndryCell) {
15370 m_coarseOldBndryCells.insert(solverCellId);
15371 m_oldBndryCells.insert(make_pair(solverCellId, sweptVol));
15372 }
15373
15374 // call removeChilds at the end, otherwise link to children is already invalidated!
15376
15377 // only single-solver!
15378 if(!g_multiSolverGrid) ASSERT((m_cells.size() - grid().raw().treeb().size()) <= grid().m_maxNoChilds, "");
15379}
15380
15381
15386template <MInt nDim, class SysEqn>
15388 TRACE();
15389
15390 MBool forceAdaptation = false;
15391
15392 if(m_engineSetup) {
15393 static const MInt cadInterval = 5;
15394
15395 const MInt cad = this->crankAngle(m_physicalTime, 0);
15396 const MInt cad_dt1 = this->crankAngle(m_physicalTime - timeStep(), 0);
15397
15398 if(cad % cadInterval == 0 && cad_dt1 % cadInterval != 0) {
15399 forceAdaptation = true;
15400 if(domainId() == 0) {
15401 cerr << " FvMb-Solver is forcing a mesh-adaptation at time step " << globalTimeStep << endl;
15402 }
15403 }
15404 }
15405
15406 if(m_forceAdaptation) {
15407 forceAdaptation = true;
15408 m_forceAdaptation = false;
15409 }
15410
15411 return forceAdaptation;
15412}
15413
15414
15419template <MInt nDim, class SysEqn>
15421 TRACE();
15422
15423 if(!isActive()) return;
15424
15425 if(globalTimeStep > 0) {
15426 // update the time and construct new GField before the adaptation
15427 advanceTimeStep();
15428 if(m_constructGField) {
15429 constructGFieldPredictor();
15430 } else if(!m_LsMovement) {
15431 updateBodyProperties();
15432 }
15433 ASSERT(m_structureStep == 0, "");
15434
15435 resetSolverMb();
15436 setLevelSetMbCellProperties();
15437
15438 if(grid().azimuthalPeriodicity()) {
15439 storeAzimuthalPeriodicData();
15440 }
15441
15442 {
15443 // does halo info need to be recovered after adaptation?
15444 auto oldBndryCellsBak(m_oldBndryCells);
15445 m_oldBndryCells.clear();
15446 for(auto it = oldBndryCellsBak.begin(); it != oldBndryCellsBak.end(); ++it) {
15447 if(it->first >= noInternalCells()) continue;
15448 ASSERT(!a_isHalo(it->first), "");
15449 m_oldBndryCells.insert(*it);
15450 }
15451 }
15452
15453 {
15454 // does halo info need to be recovered after adaptation?
15455 auto nearBoundaryBackupBak(m_nearBoundaryBackup);
15456 m_nearBoundaryBackup.clear();
15457 for(auto it = nearBoundaryBackupBak.begin(); it != nearBoundaryBackupBak.end(); ++it) {
15458 if(it->first >= noInternalCells()) continue;
15459 ASSERT(!a_isHalo(it->first), "");
15460 m_nearBoundaryBackup.insert(*it);
15461 }
15462 }
15463 }
15464
15465 m_coarseOldBndryCells.clear();
15466
15468}
15469
15470
15475template <MInt nDim, class SysEqn>
15476void FvMbCartesianSolverXD<nDim, SysEqn>::setSensors(std::vector<std::vector<MFloat>>& sensors,
15477 std::vector<MFloat>& sensorWeight,
15478 std::vector<std::bitset<64>>& sensorCellFlag,
15479 std::vector<MInt>& sensorSolverId) {
15480 if(globalTimeStep < 0 && m_constructGField && m_bodyTypeMb) {
15481 constructGField();
15482 }
15483
15484 const auto sensorOffset = (signed)sensors.size();
15485 FvCartesianSolverXD<nDim, SysEqn>::setSensors(sensors, sensorWeight, sensorCellFlag, sensorSolverId);
15486
15487 // ensure only a single-level change during an adaptation run at the bndry!
15488 // use an additional adaptation after some time steps to ensure smooth transition
15489 if(m_bndryLevelJumps && (maxRefinementLevel() - m_lsCutCellMinLevel > 1)) {
15490 // prevent coarsening of bndry-cells by more than 1 level
15491 for(auto it = m_coarseOldBndryCells.begin(); it != m_coarseOldBndryCells.end(); it++) {
15492 const MInt cellId = *it;
15493 const MInt gridId = grid().tree().solver2grid(cellId);
15494 for(MInt s = 0; s < this->m_noSensors; s++) {
15495 sensorCellFlag[gridId][sensorOffset + s] = false;
15496 sensors[sensorOffset + s][gridId] = 0.0;
15497 }
15498 const MInt parentId = c_parentId(cellId);
15499 if(parentId < 0) continue;
15500 const MInt gridParent = grid().tree().solver2grid(parentId);
15501 sensorCellFlag[gridParent][sensorOffset] = true;
15502 sensors[sensorOffset][gridParent] = 1.0;
15503 }
15504 // prevent refinement of bndry-cells by more than 1 level
15505 for(auto it = m_oldBndryCells.begin(); it != m_oldBndryCells.end(); it++) {
15506 const MInt cellId = it->first;
15507 if(c_isLeafCell(cellId)) continue;
15508 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
15509 const MInt child = c_childId(cellId, childId);
15510 if(child < 0) continue;
15511 const MInt gridId = grid().tree().solver2grid(child);
15512 for(MInt s = 0; s < this->m_noSensors; s++) {
15513 sensorCellFlag[gridId][sensorOffset + s] = false;
15514 sensors[sensorOffset + s][gridId] = 0.0;
15515 }
15516 }
15517 }
15518 }
15519}
15520
15521
15526template <MInt nDim, class SysEqn>
15529
15530 if(grid().azimuthalPeriodicity()) {
15531 initAzimuthalCartesianHaloInterpolation();
15532 this->exchangeAzimuthalPer(&(a_levelSetValuesMb(0, 0)), m_noLevelSetsUsedForMb);
15533 }
15534}
15535
15536
15541template <MInt nDim, class SysEqn>
15543 // set onlineRestart to false for the next initSolutionStep call!
15544 m_onlineRestart = false;
15545
15546 if(isActive()) {
15547 if(maxLevel() != maxRefinementLevel()) {
15548 if(domainId() == 0) {
15549 cerr << "MaxLevel is " << maxLevel() << " and maxRefinementLevel is " << maxRefinementLevel() << endl;
15550 }
15551 }
15552
15553 if(m_maxLevelChange && maxLevel() == maxRefinementLevel()) {
15554 m_maxLevelChange = false;
15555 m_lsCutCellMinLevel = maxLevel();
15556 m_bndryLevelJumps = false;
15557 if(domainId() == 0) {
15558 cerr << "MaxLevel reached maxRefinementLevel! " << endl;
15559 }
15560 }
15561 }
15562
15564
15565 if(globalTimeStep < 0) return;
15566 if(!isActive()) return;
15567
15568 MFloatScratchSpace oldBCData(a_noCells(), 5, AT_, "oldBCData");
15569 oldBCData.fill(std::numeric_limits<MFloat>::lowest());
15570
15571 exchangeData(&a_cellVolume(0), 1);
15572 exchangeData(&m_cellVolumesDt1[0], 1);
15573
15574 // Correction for refined oldBndryCells:
15575 //- add oldBndryCells which are refined to refOldBndryCells and
15576 //- remove them from oldBndryCells!
15577 //- remove further entries (of cells which are uncut or inactive) in correctRefinedBndryCell!
15578 //- correct the swept/old Volume of the remaining bndryCells in correctRefinedBndryCellVolume
15579 // Correction for coarsened oldBndryCells:
15580 //- identify cells as they are marked with -99 sweptVolume
15581 //- correct the swept/old volume in correctCoarseBndryCellsVolume
15582 m_refOldBndryCells.clear();
15583 vector<MInt> deletedBndryCells;
15584 // const MInt noBndryLevelJumps = maxRefinementLevel() - m_lsCutCellMinLevel;
15585 for(auto it = m_oldBndryCells.begin(); it != m_oldBndryCells.end(); it++) {
15586 const MInt cellId = it->first;
15587 ASSERT(!a_isHalo(cellId), "");
15588 const MFloat sweptVol = it->second;
15589 if(!c_isLeafCell(cellId)) {
15590 deletedBndryCells.push_back(cellId);
15591 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
15592 const MInt child = c_childId(cellId, childId);
15593 if(child < 0) continue;
15594 if(!c_isLeafCell(child)) {
15595 cerr << "Cell is " << c_globalId(child) << " " << c_coordinate(child, 0) << " " << c_coordinate(child, 1)
15596 << " " << c_coordinate(child, nDim - 1) << " parent " << c_globalId(cellId) << " "
15597 << c_coordinate(cellId, 0) << " " << c_coordinate(cellId, 1) << " " << c_coordinate(cellId, nDim - 1)
15598 << endl;
15599 mTerm(1, AT_, "Multiple-levell changes in a bndry-cells not supported yet!");
15600 }
15601 m_refOldBndryCells.push_back(child);
15602 oldBCData(child, 0) = 2;
15603 }
15604 /*} else {
15605 vector<MInt> leafChildIds;
15606 grid().getAllLeafChilds(cellId, leafChildIds);
15607 ASSERT(!leafChildIds.empty(), "");
15608 for(MUint i = 0; i < leafChildIds.size(); i++) {
15609 const MInt child = leafChildIds[i];
15610 ASSERT(c_isLeafCell(child), "");
15611 m_refOldBndryCells.push_back(child);
15612 oldBCData(child, 0) = 2;
15613 }
15614
15615 } */
15616 } else {
15617 auto it1 = m_coarseOldBndryCells.find(cellId);
15618 if(it1 != m_coarseOldBndryCells.end()) {
15619 oldBCData(cellId, 0) = 3;
15620 }
15621 if(oldBCData(cellId, 0) < F0) {
15622 oldBCData(cellId, 0) = 1;
15623 }
15624 oldBCData(cellId, 1) = sweptVol;
15625 }
15626 }
15627
15628 for(MInt i = 0; i < (signed)deletedBndryCells.size(); i++) {
15629 const MInt cellId = deletedBndryCells[i];
15630 auto it = m_oldBndryCells.find(cellId);
15631 m_oldBndryCells.erase(it);
15632 ASSERT(!c_isLeafCell(cellId), "");
15633 ASSERT(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel), "");
15634 }
15635
15636 for(auto it = m_nearBoundaryBackup.begin(); it != m_nearBoundaryBackup.end(); it++) {
15637 const MInt cellId = it->first;
15638 ASSERT(!a_isHalo(cellId), to_string(a_isHalo(cellId)));
15639 oldBCData(cellId, 2) = F1;
15640 }
15641
15642 // set wasInactive/wasGapCell for halo-Cells
15643 for(MInt i = 0; i < noNeighborDomains(); i++) {
15644 for(MInt j = 0; j < noWindowCells(i); j++) {
15645 const MInt cellId = windowCellId(i, j);
15646 oldBCData(cellId, 3) = (MFloat)a_hasProperty(cellId, SolverCell::WasInactive);
15647 oldBCData(cellId, 4) = (MFloat)a_hasProperty(cellId, SolverCell::WasGapCell);
15648 }
15649 }
15650
15651 exchangeData(&oldBCData[0], 5);
15652
15653 // add halo-Cells to oldBndryCell and nearBoundaryBackup
15654 // and set wasInactive and wasGapCell
15655 for(MInt cellId = noInternalCells(); cellId < c_noCells(); cellId++) {
15656 ASSERT(a_isHalo(cellId), "");
15657
15658 setConservativeVariables(cellId);
15659 for(MInt v = 0; v < m_noCVars; v++) {
15660 a_oldVariable(cellId, v) = a_variable(cellId, v);
15661 }
15662 if(oldBCData(cellId, 3) > -1) {
15663 a_hasProperty(cellId, SolverCell::WasInactive) = (MInt)oldBCData(cellId, 3);
15664 }
15665 if(oldBCData(cellId, 4) > -1) {
15666 a_hasProperty(cellId, SolverCell::WasGapCell) = (MInt)oldBCData(cellId, 4);
15667 }
15668
15669 if((MInt)oldBCData(cellId, 0) > F0) {
15670 ASSERT(c_isLeafCell(cellId), "");
15671 m_oldBndryCells.insert(make_pair(cellId, oldBCData(cellId, 1)));
15672 if((MInt)oldBCData(cellId, 0) == 2) {
15673 m_refOldBndryCells.push_back(cellId);
15674 } else if((MInt)oldBCData(cellId, 0) == 3) {
15675 m_coarseOldBndryCells.insert(cellId);
15676 }
15677 }
15678 if(oldBCData(cellId, 2) > F0) {
15679 vector<MFloat> tmp(max(m_noCVars + m_noFVars, 0) + 1);
15680 tmp[0] = m_cellVolumesDt1[cellId];
15681 for(MInt v = 0; v < m_noCVars; v++) {
15682 tmp[1 + v] = std::numeric_limits<MFloat>::lowest();
15683 }
15684 for(MInt v = 0; v < m_noFVars; v++) {
15685 tmp[1 + m_noCVars + v] = std::numeric_limits<MFloat>::lowest();
15686 }
15687 m_nearBoundaryBackup.insert(make_pair(cellId, tmp));
15688 }
15689 }
15690
15691 // Comm data back from window rank
15692 if(grid().azimuthalPeriodicity()) {
15693 commAzimuthalPeriodicData();
15694 }
15695
15696 m_surfaces.size(m_initialSurfacesOffset);
15697
15698 m_fvBndryCnd->recorrectCellCoordinates();
15699
15700 m_cells.size(m_bndryGhostCellsOffset);
15701 m_totalnoghostcells = 0;
15702 m_totalnosplitchilds = 0;
15703
15704 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
15705 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
15706 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId = -1;
15707 }
15708 }
15709
15710#if defined _MB_DEBUG_ || !defined NDEBUG
15711
15712 MInt noRefBndryCells = m_refOldBndryCells.size();
15713 MInt noCoBndryCells = m_coarseOldBndryCells.size();
15714
15715 MPI_Allreduce(MPI_IN_PLACE, &noRefBndryCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noRefBndryCells");
15716 MPI_Allreduce(MPI_IN_PLACE, &noCoBndryCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noCoBndryCells");
15717
15718 if(noRefBndryCells > 0) {
15719 m_log << "Refining " << noRefBndryCells << " bndryCells in adaptation!" << endl;
15720 }
15721
15722 if(noCoBndryCells > 0) {
15723 m_log << "Coarsening " << noCoBndryCells << " bndryCells in adaptation!" << endl;
15724 }
15725
15726 checkHaloCells(1);
15727#endif
15728}
15729
15730
15735template <MInt nDim, class SysEqn>
15737 if(m_constructGField || m_levelSetAdaptationScheme != 2) {
15738 distance.fill(std::numeric_limits<MFloat>::max());
15739
15740 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
15741 ASSERT(!a_isBndryGhostCell(cellId), "");
15742 ASSERT(!a_isHalo(cellId), "");
15743 ASSERT(!c_isToDelete(cellId), "");
15744 distance(cellId) = a_levelSetValuesMb(cellId, 0);
15745 }
15746 } else {
15747 // in this case, distance does not describe the distance to the interface!
15748 // instead it is rather used simular to the inList in the lssolver.
15749
15750 MInt listCount = 0;
15751 distance.fill(0.0);
15752
15753 // mark Interface cells based on the levelset-value!
15754 const MInt linerSet = 1;
15755 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
15756 // for (MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
15757 // only refine around G0-set to avoid unnecessary fv-Cells!
15758 const MInt set = 0;
15759 if((MInt)distance(cellId) == 1) continue;
15760 MBool addParents = false;
15761 if(approx(a_levelSetValuesMb(cellId, set), F0, MFloatEps)) {
15762 if(c_isLeafCell(cellId)) {
15763 const MInt bodySet = m_bodyToSetTable[a_associatedBodyIds(cellId, set)];
15764 MInt maxLvl = m_lsCutCellLevel[bodySet];
15765 if(bodySet == linerSet && m_linerLvlJump && a_coordinate(cellId, 0) > -0.51
15766 && a_coordinate(cellId, 0) < 0.51) {
15767 maxLvl = m_lsCutCellLevel[bodySet] + 1;
15768 }
15769 if(a_level(cellId) < maxLvl) {
15770 distance(cellId) = 1.0;
15771 listCount++;
15772 }
15773 } else {
15774 distance(cellId) = 1.0;
15775 listCount++;
15776 }
15777 addParents = true;
15778 } else {
15779 for(MInt dir = 0; dir < m_noDirs; dir++) {
15780 if(a_hasNeighbor(cellId, dir, false) > 0) {
15781 const MInt nghbrId = c_neighborId(cellId, dir, false);
15782 if((a_levelSetValuesMb(nghbrId, set) * a_levelSetValuesMb(cellId, set) < F0)) {
15783 if(c_isLeafCell(cellId)) {
15784 const MInt bodySet = m_bodyToSetTable[a_associatedBodyIds(cellId, set)];
15785 MInt maxLvl = m_lsCutCellLevel[bodySet];
15786 if(bodySet == linerSet && m_linerLvlJump && a_coordinate(cellId, 0) > -0.51
15787 && a_coordinate(cellId, 0) < 0.51) {
15788 maxLvl = m_lsCutCellLevel[bodySet] + 1;
15789 }
15790 if(a_level(cellId) < maxLvl) {
15791 distance(cellId) = 1.0;
15792 listCount++;
15793 }
15794 } else {
15795 distance(cellId) = 1.0;
15796 listCount++;
15797 }
15798 addParents = true;
15799 dir = m_noDirs;
15800 }
15801 }
15802 }
15803 }
15804 if(addParents) {
15805 MInt parentId = c_parentId(cellId);
15806 while(parentId > -1 && parentId < a_noCells()) {
15807 distance(parentId) = 1.0;
15808 parentId = c_parentId(parentId);
15809 }
15810 }
15811 }
15812
15813#if defined _MB_DEBUG_ || !defined NDEBUG
15814 MPI_Allreduce(MPI_IN_PLACE, &listCount, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "listCount");
15815
15816 if(listCount == 0) mTerm(1, AT_, "No Cells found for fv-mb-refinement!");
15817#endif
15818 }
15819
15820 exchangeDataFV(distance.data());
15821}
15822
15823
15828template <MInt nDim, class SysEqn>
15830 TRACE();
15831
15832 const MInt noCells = a_noCells();
15833 ScratchSpace<MBool> prop13(noCells, AT_, "prop13");
15834 ScratchSpace<MBool> inact(noCells, AT_, "inact");
15835 ScratchSpace<MBool> bghost(noCells, AT_, "bghost");
15836 for(MInt c = 0; c < noCells; c++) {
15837 prop13.p[c] = a_hasProperty(c, SolverCell::IsOnCurrentMGLevel);
15838 bghost.p[c] = a_isBndryGhostCell(c);
15839 inact.p[c] = a_hasProperty(c, SolverCell::IsInactive);
15840 if(c_isToDelete(c)) continue;
15841 a_hasProperty(c, SolverCell::IsOnCurrentMGLevel) = true;
15842 a_hasProperty(c, SolverCell::IsInactive) = false;
15843 if(a_isHalo(c)) {
15844 a_isBndryGhostCell(c) = false;
15845 }
15846 }
15847 const MInt haloCellOutput = m_haloCellOutput;
15848 const MInt vtuGeometryOutputExtended = m_vtuGeometryOutputExtended;
15849 const MInt vtuGlobalIdOutput = m_vtuGlobalIdOutput;
15850 const MInt vtuDomainIdOutput = m_vtuDomainIdOutput;
15851 const MInt vtuLevelSetOutput = m_vtuLevelSetOutput;
15852 const MInt vtuVelocityGradientOutput = m_vtuVelocityGradientOutput;
15853
15854 m_haloCellOutput = true;
15855 m_vtuGeometryOutputExtended = true;
15856 m_vtuGlobalIdOutput = true;
15857 m_vtuDomainIdOutput = true;
15858 m_vtuLevelSetOutput = false;
15859 m_vtuVelocityGradientOutput = true;
15860
15861 writeVtkXmlFiles("QOUT_" + suffix, "GEOM_" + suffix, 0, 0);
15862
15863 m_haloCellOutput = haloCellOutput;
15864 m_vtuGeometryOutputExtended = vtuGeometryOutputExtended;
15865 m_vtuGlobalIdOutput = vtuGlobalIdOutput;
15866 m_vtuDomainIdOutput = vtuDomainIdOutput;
15867 m_vtuLevelSetOutput = vtuLevelSetOutput;
15868 m_vtuVelocityGradientOutput = vtuVelocityGradientOutput;
15869
15870 for(MInt c = 0; c < noCells; c++) {
15871 a_hasProperty(c, SolverCell::IsOnCurrentMGLevel) = prop13.p[c];
15872 a_hasProperty(c, SolverCell::IsInactive) = inact.p[c];
15873 a_isBndryGhostCell(c) = bghost.p[c];
15874 }
15875 const MInt cellId = -1;
15876 if(domainId() == 0 && cellId > -1) {
15877 m_log << "CLOG " << globalTimeStep << " " << cellId << " " << a_level(cellId) << " " << c_noChildren(cellId)
15878 << " # " << a_isBndryGhostCell(cellId) << " " << a_isHalo(cellId) << " " << a_noCells() << " # "
15879 << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, 2) << " # ";
15880 for(MInt dir = 0; dir < m_noDirs; dir++) {
15881 MInt cId = (c_neighborId(cellId, dir) > -1) ? m_bndryCandidateIds[c_neighborId(cellId, dir)] : -1;
15882 MInt bId = (c_neighborId(cellId, dir) > -1) ? a_isBndryGhostCell(c_neighborId(cellId, dir)) : -1;
15883 m_log << " / (" << dir << ") " << a_hasNeighbor(cellId, dir) << " " << c_neighborId(cellId, dir) << " " << cId
15884 << " " << bId;
15885 }
15886 m_log << endl;
15887 }
15888
15889
15890 ScratchSpace<MInt> noLsMbCells(noDomains(), AT_, "noLsMbCells");
15891 if(noDomains() > 1)
15892 MPI_Gather(&m_noLsMbBndryCells, 1, MPI_INT, &(noLsMbCells[0]), 1, MPI_INT, 0, mpiComm(), AT_, "m_noLsMbBndryCells",
15893 "(noLsMbCells[0])");
15894 if(domainId() == 0) {
15895 ofstream ofile(("out/QOUT_" + suffix + ".pvd").c_str(), ios_base::out | ios_base::trunc);
15896 if(ofile.is_open() && ofile.good()) {
15897 ofile << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
15898 ofile << "<Collection>" << endl;
15899 for(MInt p = 0; p < noDomains(); p++) {
15900 ofile << "<DataSet part=\"" << p << "\" timestep=\"" << globalTimeStep << "\" file=\""
15901 << "./solver_data/"
15902 << "QOUT_" << suffix << "_B" << p << ".vtu\"/>" << endl;
15903 }
15904 ofile << "</Collection>" << endl;
15905 ofile << "</VTKFile>" << endl;
15906 ofile.close();
15907 ofile.clear();
15908 } else {
15909 cerr << "Error opening file out/QOUT_" << suffix << ".pvd" << endl;
15910 }
15911 ofstream ofile2(("out/GEOM_" + suffix + ".pvd").c_str(), ios_base::out | ios_base::trunc);
15912 if(ofile2.is_open() && ofile2.good()) {
15913 ofile2 << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
15914 ofile2 << "<Collection>" << endl;
15915 for(MInt p = 0; p < noDomains(); p++) {
15916 if(noLsMbCells(p) > 0) {
15917 ofile2 << "<DataSet part=\"" << p << "\" timestep=\"" << globalTimeStep << "\" file=\""
15918 << "./solver_data/"
15919 << "GEOM_" << suffix << "_B" << p << ".vtp\"/>" << endl;
15920 }
15921 }
15922 ofile2 << "</Collection>" << endl;
15923 ofile2 << "</VTKFile>" << endl;
15924 ofile2.close();
15925 ofile2.clear();
15926 } else {
15927 cerr << "Error opening file out/GEOM_" << suffix << ".pvd" << endl;
15928 }
15929 }
15930}
15931
15932
15939template <MInt nDim, class SysEqn>
15941 TRACE();
15942
15943 if(!m_engineSetup) return;
15944
15945 static const MInt cadStart = -10;
15946 static const MInt cadEnd = 725;
15947 static const MInt cadEndSlice = 365;
15948 static const MInt cadInterval = 5;
15949
15950 static const MInt sliceInterval = 1;
15951
15952 const MFloat cad = this->crankAngle(m_physicalTime, 0);
15953 const MFloat cad_prev = this->crankAngle(m_physicalTime - timeStep(), 0);
15954 const MFloat cad_next = this->crankAngle(m_physicalTime + timeStep(), 0);
15955
15956 if(cad > cadEnd) return;
15957
15958 if(cad < cadStart - cadInterval) return;
15959
15960 const MInt cadMaxIter = (cadEnd - cadStart) / cadInterval;
15961 const MInt sliceMaxIter = (cadEndSlice - cadStart) / sliceInterval;
15962
15963 // iterate for full solution output
15964 for(MInt i = 0; i < cadMaxIter; i++) {
15965 const MFloat cadTarget = cadStart + i * cadInterval;
15966
15967 if(cad < cadTarget && cad_next > cadTarget) {
15968 if(fabs(cad - cadTarget) <= fabs(cad_next - cadTarget)) {
15969 if(domainId() == 0) {
15970 cerr << "Saving output at crankAngle " << cad << endl;
15971 }
15972
15973 // trigger full output:
15974 MFloat* backUpCoordinate = NULL;
15975 if(m_vtuCoordinatesThreshold != NULL) {
15976 mAlloc(backUpCoordinate, 6, "backUpCoordinate", F0, AT_);
15977 for(MInt j = 0; j < 2 * nDim; j++) {
15978 backUpCoordinate[j] = m_vtuCoordinatesThreshold[j];
15979 }
15980 mDeallocate(m_vtuCoordinatesThreshold);
15981 m_vtuCoordinatesThreshold = NULL;
15982 }
15983 MString fileName = "FieldData_" + to_string(solverId()) + "_" + to_string((MInt)round(cad));
15984 writeVtkXmlFiles(fileName, "GEO_", false, false);
15985 if(backUpCoordinate != NULL) {
15986 mAlloc(m_vtuCoordinatesThreshold, 6, "backUpCoordinate", F0, AT_);
15987 for(MInt j = 0; j < 2 * nDim; j++) {
15988 m_vtuCoordinatesThreshold[j] = backUpCoordinate[j];
15989 }
15990 }
15991 break;
15992 }
15993 } else if(cad > cadTarget && cad_prev < cadTarget) {
15994 if(abs(cad - cadTarget) < fabs(cad_prev - cadTarget)) {
15995 if(domainId() == 0) {
15996 cerr << "Saving output at crankAngle " << cad << endl;
15997 }
15998 // trigger full output:
15999 MFloat* backUpCoordinate = NULL;
16000 if(m_vtuCoordinatesThreshold != NULL) {
16001 mAlloc(backUpCoordinate, 6, "backUpCoordinate", F0, AT_);
16002 for(MInt j = 0; j < 2 * nDim; j++) {
16003 backUpCoordinate[j] = m_vtuCoordinatesThreshold[j];
16004 }
16005 mDeallocate(m_vtuCoordinatesThreshold);
16006 m_vtuCoordinatesThreshold = NULL;
16007 }
16008 MString fileName = "FieldData_" + to_string(solverId()) + "_" + to_string((MInt)round(cad));
16009 writeVtkXmlFiles(fileName, "GEO_", false, false);
16010 if(backUpCoordinate != NULL) {
16011 mAlloc(m_vtuCoordinatesThreshold, 6, "backUpCoordinate", F0, AT_);
16012 for(MInt j = 0; j < 2 * nDim; j++) {
16013 m_vtuCoordinatesThreshold[j] = backUpCoordinate[j];
16014 }
16015 }
16016 break;
16017 }
16018 }
16019 }
16020
16021 if(cad > cadEndSlice) return;
16022
16023 // iterate for slice output
16024 for(MInt i = 0; i < sliceMaxIter; i++) {
16025 const MFloat sliceTarget = cadStart + i * sliceInterval;
16026
16027 if(cad < sliceTarget && cad_next > sliceTarget) {
16028 if(fabs(cad - sliceTarget) <= fabs(cad_next - sliceTarget)) {
16029 if(domainId() == 0) {
16030 cerr << "Saving output Slice at crankAngle " << cad << endl;
16031 }
16032 MString fileName = "Slice_" + to_string(solverId()) + "_" + to_string((MInt)round(cad));
16033 writeVtkXmlFiles(fileName, "SLICE_GEO", false, false);
16034 break;
16035 }
16036 } else if(cad > sliceTarget && cad_prev < sliceTarget) {
16037 if(abs(cad - sliceTarget) < fabs(cad_prev - sliceTarget)) {
16038 if(domainId() == 0) {
16039 cerr << "Saving output Slice at crankAngle " << cad << endl;
16040 }
16041 MString fileName = "Slice_" + to_string(solverId()) + "_" + to_string((MInt)round(cad));
16042 writeVtkXmlFiles(fileName, "SLICE_GEO", false, false);
16043 break;
16044 }
16045 }
16046 }
16047}
16048
16049
16054template <MInt nDim, class SysEqn>
16056 TRACE();
16057
16058 if(noNeighborDomains() == 0 && grid().noAzimuthalNeighborDomains() == 0) {
16059 if(noDomains() > 1) mTerm(1, AT_, "Unexpected situation in initializeMaxLevelExchange!");
16060 return;
16061 }
16062
16063#ifndef NDEBUG
16064 MIntScratchSpace sndbuf(noDomains(), AT_, "sndbuf");
16065 MIntScratchSpace rcvbuf(noDomains(), AT_, "rcvbuf");
16066 sndbuf.fill(0);
16067 rcvbuf.fill(-1);
16068 for(MInt i = 0; i < noNeighborDomains(); i++) {
16069 sndbuf[neighborDomain(i)] = 1;
16070 }
16071 MPI_Alltoall(sndbuf.getPointer(), 1, MPI_INT, rcvbuf.getPointer(), 1, MPI_INT, mpiComm(), AT_, "sndbuf.getPointer()",
16072 "rcvbuf.getPointer()");
16073 for(MInt i = 0; i < noDomains(); i++) {
16074 if(i == domainId()) continue;
16075 if(sndbuf[i] != rcvbuf[i]) {
16076 cerr << domainId() << ": warning exchange mismatch with domain " << i << " (" << sndbuf[i] << "/" << rcvbuf[i]
16077 << ") " << endl;
16078 }
16079 }
16080#endif
16081
16082//#define NEW_INITMAXLVLEX
16083#ifdef NEW_INITMAXLVLEX
16084 for(MInt i = 0; i < noNeighborDomains(); i++) {
16085 m_noMaxLevelHaloCells[i] = 0;
16086 for(MInt j = 0; j < noHaloCells(i); j++) {
16087 MInt cellId = haloCellId(i, j);
16088 ASSERT(cellId > -1, "");
16089 MBool structuredCell = a_hasProperty(cellId, SolverCell::AtStructuredRegion);
16090 for(MInt dir = 0; dir < m_noDirs; dir++) {
16091 if(a_hasNeighbor(cellId, dir)) {
16092 if(a_hasProperty(c_neighborId(cellId, dir), SolverCell::AtStructuredRegion)) {
16093 structuredCell = true;
16094 }
16095 }
16096 }
16097 if(c_isLeafCell(cellId) || structuredCell) {
16098 m_maxLevelHaloCells[i][m_noMaxLevelHaloCells[i]] = cellId;
16099 m_noMaxLevelHaloCells[i]++;
16100 }
16101 }
16102 }
16103 for(MInt i = 0; i < noNeighborDomains(); i++) {
16104 m_noMaxLevelWindowCells[i] = 0;
16105 for(MInt j = 0; j < noWindowCells(i); j++) {
16106 MInt cellId = windowCellId(i, j);
16107 ASSERT(cellId > -1, "");
16108 MBool structuredCell = a_hasProperty(cellId, SolverCell::AtStructuredRegion);
16109 for(MInt dir = 0; dir < m_noDirs; dir++) {
16110 if(a_hasNeighbor(cellId, dir)) {
16111 if(a_hasProperty(c_neighborId(cellId, dir), SolverCell::AtStructuredRegion)) {
16112 if(a_isWindow(c_neighborId(cellId, dir))) structuredCell = true;
16113 }
16114 }
16115 }
16116 if(c_isLeafCell(cellId) || structuredCell) {
16117 m_maxLevelWindowCells[i][m_noMaxLevelWindowCells[i]] = cellId;
16118 m_noMaxLevelWindowCells[i]++;
16119 }
16120 }
16121 }
16122
16123#ifndef NDEBUG
16124 exchange(); // test max level exchange
16125#endif
16126
16127#else
16128
16129 ScratchSpace<MInt> haloCellsCnt(noNeighborDomains(), AT_, "noHaloCells");
16130 ScratchSpace<MInt> windowCellsCnt(noNeighborDomains(), AT_, "noWindowCells");
16131 for(MInt d = 0; d < noNeighborDomains(); d++) {
16132 haloCellsCnt[d] = noHaloCells(d);
16133 windowCellsCnt[d] = noWindowCells(d);
16134 }
16135
16136 if(noNeighborDomains() > 0) {
16137 mDeallocate(m_maxLevelHaloCells);
16138 mAlloc(m_maxLevelHaloCells, noNeighborDomains(), &haloCellsCnt[0], "m_maxLevelHaloCells", AT_);
16139 mDeallocate(m_maxLevelWindowCells);
16140 mAlloc(m_maxLevelWindowCells, noNeighborDomains(), &windowCellsCnt[0], "m_maxLevelWindowCells", AT_);
16141 }
16142
16143 ScratchSpace<MPI_Request> sendReq(noNeighborDomains(), AT_, "sendReq");
16144 ScratchSpace<MPI_Request> recvReq(noNeighborDomains(), AT_, "recvReq");
16145 sendReq.fill(MPI_REQUEST_NULL);
16146 recvReq.fill(MPI_REQUEST_NULL);
16147
16148 // halo cells
16149 for(MInt i = 0; i < noNeighborDomains(); i++) {
16150 m_noMaxLevelHaloCells[i] = 0;
16151 for(MInt j = 0; j < noHaloCells(i); j++) {
16152 MInt cellId = haloCellId(i, j);
16153 m_receiveBuffers[i][j] = -F1;
16154 MBool structuredCell = a_hasProperty(cellId, SolverCell::AtStructuredRegion);
16155 for(MInt dir = 0; dir < m_noDirs; dir++) {
16156 if(a_hasNeighbor(cellId, dir)) {
16157 if(a_hasProperty(c_neighborId(cellId, dir), SolverCell::AtStructuredRegion)) {
16158 structuredCell = true;
16159 }
16160 }
16161 }
16162 if(!c_isLeafCell(cellId) && !structuredCell) continue;
16163 m_maxLevelHaloCells[i][m_noMaxLevelHaloCells[i]] = cellId;
16164 m_noMaxLevelHaloCells[i]++;
16165 ASSERT(cellId > -1, "");
16166 m_receiveBuffers[i][j] = (MFloat)cellId;
16167 }
16168 }
16169
16170 // send halo cell information
16171 if(noNeighborDomains() > 0) {
16172 if(m_nonBlockingComm) {
16173 for(MInt i = 0; i < noNeighborDomains(); i++) {
16174 MPI_Irecv(m_sendBuffers[i], noWindowCells(i), MPI_DOUBLE, neighborDomain(i), 5, mpiComm(), &recvReq[i], AT_,
16175 "m_sendBuffers[i]");
16176 }
16177 for(MInt i = 0; i < noNeighborDomains(); i++) {
16178 MPI_Isend(m_receiveBuffers[i], noHaloCells(i), MPI_DOUBLE, neighborDomain(i), 5, mpiComm(), &sendReq[i], AT_,
16179 "m_receiveBuffers[i]");
16180 }
16181 MPI_Waitall(noNeighborDomains(), &recvReq[0], MPI_STATUSES_IGNORE, AT_);
16182 MPI_Waitall(noNeighborDomains(), &sendReq[0], MPI_STATUSES_IGNORE, AT_);
16183 } else {
16184 for(MInt i = 0; i < noNeighborDomains(); i++) {
16185 MPI_Issend(m_receiveBuffers[i], noHaloCells(i), MPI_DOUBLE, neighborDomain(i), 5, mpiComm(), &sendReq[i], AT_,
16186 "m_receiveBuffers[i]");
16187 }
16188 for(MInt i = 0; i < noNeighborDomains(); i++) {
16189 MPI_Recv(m_sendBuffers[i], noWindowCells(i), MPI_DOUBLE, neighborDomain(i), 5, mpiComm(), MPI_STATUS_IGNORE,
16190 AT_, "m_sendBuffers[i]");
16191 }
16192 MPI_Waitall(noNeighborDomains(), &sendReq[0], MPI_STATUSES_IGNORE, AT_);
16193 }
16194 }
16195
16196 // write window cell information
16197 for(MInt i = 0; i < noNeighborDomains(); i++) {
16198 m_noMaxLevelWindowCells[i] = 0;
16199 for(MInt j = 0; j < noWindowCells(i); j++) {
16200 if(m_sendBuffers[i][j] > -F1B2) {
16201 ASSERT(windowCellId(i, j) > -1, "");
16202 m_maxLevelWindowCells[i][m_noMaxLevelWindowCells[i]] = windowCellId(i, j);
16203 m_noMaxLevelWindowCells[i]++;
16204 }
16205 }
16206 }
16207#endif
16208
16209
16210 this->prepareMpiExchange();
16211
16212 if(grid().azimuthalPeriodicity()) {
16213 initAzimuthalMaxLevelExchange();
16214 }
16215}
16216
16217
16222template <MInt nDim, class SysEqn>
16223void FvMbCartesianSolverXD<nDim, SysEqn>::createSurface(MInt srfcId, MInt nghbrId0, MInt nghbrId1, MInt orientation) {
16224 TRACE();
16225
16226 ASSERT((srfcId > -1) && (nghbrId0 > -1) && (nghbrId1 > -1), "createSurface(..) error");
16227 ASSERT((srfcId < a_noSurfaces()) && (nghbrId0 < a_noCells()) && (nghbrId1 < a_noCells()),
16228 to_string(nghbrId0) + " " + to_string(nghbrId1) + " " + to_string(c_noCells()) + " " + to_string(a_noCells()));
16229 ASSERT(c_noChildren(nghbrId0) == 0 && c_noChildren(nghbrId1) == 0, "");
16230
16231 a_surfaceOrientation(srfcId) = orientation;
16232 a_surfaceNghbrCellId(srfcId, 0) = nghbrId0;
16233 a_surfaceNghbrCellId(srfcId, 1) = nghbrId1;
16234
16235 if(a_bndryId(nghbrId0) > -1) {
16236 m_bndryCells->a[a_bndryId(nghbrId0)].m_associatedSrfc[2 * orientation + 1] = srfcId;
16237 }
16238 if(a_bndryId(nghbrId1) > -1) {
16239 m_bndryCells->a[a_bndryId(nghbrId1)].m_associatedSrfc[2 * orientation] = srfcId;
16240 }
16241
16242 if(a_level(nghbrId1) > a_level(nghbrId0)) {
16243 const MFloat cellLength = c_cellLengthAtLevel(a_level(nghbrId1));
16244 for(MInt i = 0; i < nDim; i++) {
16245 a_surfaceCoordinate(srfcId, i) = a_coordinate(nghbrId1, i);
16246 }
16247 a_surfaceCoordinate(srfcId, orientation) -= F1B2 * cellLength;
16248 a_surfaceArea(srfcId) = F1;
16249 for(MInt i = 0; i < nDim - 1; i++)
16250 a_surfaceArea(srfcId) *= cellLength;
16251 m_cellSurfaceMapping[nghbrId0][2 * orientation + 1] = -1;
16252 m_cellSurfaceMapping[nghbrId1][2 * orientation] = srfcId;
16253 } else {
16254 const MFloat cellLength = c_cellLengthAtLevel(a_level(nghbrId0));
16255 for(MInt i = 0; i < nDim; i++) {
16256 a_surfaceCoordinate(srfcId, i) = a_coordinate(nghbrId0, i);
16257 }
16258 a_surfaceCoordinate(srfcId, orientation) += F1B2 * cellLength;
16259 a_surfaceArea(srfcId) = F1;
16260 for(MInt i = 0; i < nDim - 1; i++)
16261 a_surfaceArea(srfcId) *= cellLength;
16262 m_cellSurfaceMapping[nghbrId0][2 * orientation + 1] = srfcId;
16263 m_cellSurfaceMapping[nghbrId1][2 * orientation] = -1;
16264 }
16265
16266 if(a_level(nghbrId0) == a_level(nghbrId1)) {
16267 a_surfaceUpwindCoefficient(srfcId) = m_globalUpwindCoefficient;
16268 a_surfaceFactor(srfcId, 0) = F1B2;
16269 a_surfaceFactor(srfcId, 1) = F1B2;
16270 m_cellSurfaceMapping[nghbrId0][2 * orientation + 1] = srfcId;
16271 m_cellSurfaceMapping[nghbrId1][2 * orientation] = srfcId;
16272 } else {
16273 a_surfaceUpwindCoefficient(srfcId) = m_chi;
16274 MFloat tmp = F0;
16275 a_surfaceFactor(srfcId, 0) = F0;
16276 for(MInt i = 0; i < nDim; i++) {
16277 a_surfaceFactor(srfcId, 0) += POW2(a_surfaceCoordinate(srfcId, i) - a_coordinate(nghbrId0, i));
16278 tmp += POW2(a_surfaceCoordinate(srfcId, i) - a_coordinate(nghbrId1, i));
16279 }
16280 a_surfaceFactor(srfcId, 0) = sqrt(a_surfaceFactor(srfcId, 0));
16281 tmp = sqrt(tmp);
16282 a_surfaceFactor(srfcId, 0) = tmp / (a_surfaceFactor(srfcId, 0) + tmp);
16283 a_surfaceFactor(srfcId, 1) = F1 - a_surfaceFactor(srfcId, 0);
16284 }
16285 for(MInt i = 0; i < nDim; i++) {
16286 a_surfaceDeltaX(srfcId, i) = a_surfaceCoordinate(srfcId, i) - a_coordinate(a_surfaceNghbrCellId(srfcId, 0), i);
16287 a_surfaceDeltaX(srfcId, nDim + i) =
16288 a_surfaceCoordinate(srfcId, i) - a_coordinate(a_surfaceNghbrCellId(srfcId, 1), i);
16289 }
16290 MBool flag = false;
16291 for(MInt side = 0; side < 2; side++) {
16292 for(MInt d = 0; d < m_noDirs; d++) {
16293 if(a_hasNeighbor(a_surfaceNghbrCellId(srfcId, side), d) > 0) continue;
16294 if(c_parentId(a_surfaceNghbrCellId(srfcId, side)) == -1) continue;
16295 if(a_hasNeighbor(c_parentId(a_surfaceNghbrCellId(srfcId, side)), d) == 0) continue;
16296 if(c_noChildren(c_neighborId(c_parentId(a_surfaceNghbrCellId(srfcId, side)), d)) > 0) continue;
16297 flag = true;
16298 d = m_noDirs;
16299 }
16300 }
16301
16302 if(flag) a_surfaceUpwindCoefficient(srfcId) = m_chi;
16303 a_surfaceBndryCndId(srfcId) = -1;
16304}
16305
16306
16311template <MInt nDim, class SysEqn>
16313 MInt direction) {
16314 ASSERT((srfcId > -1), "createSurface(..) error");
16315 ASSERT((srfcId < a_noSurfaces()) && (cellId < a_noCells()) && (splitChildId < a_noCells()),
16316 "createSurface(..) error");
16317 ASSERT(c_isLeafCell(cellId), "");
16318
16319 MInt orientation = direction / 2;
16320 a_surfaceOrientation(srfcId) = orientation;
16321 MInt nghbr0 = splitChildId;
16322 MInt nghbr1 = -2;
16323 if(direction % 2 == 0) {
16324 nghbr0 = -2;
16325 nghbr1 = splitChildId;
16326 }
16327 a_surfaceNghbrCellId(srfcId, 0) = nghbr0;
16328 a_surfaceNghbrCellId(srfcId, 1) = nghbr1;
16329
16330 MInt nghbrId = c_neighborId(cellId, direction);
16331 ASSERT(nghbrId > -1, "");
16332
16333 if(nghbr0 == -2) {
16334 nghbr0 = nghbrId;
16335 nghbr1 = cellId;
16336 } else {
16337 nghbr0 = cellId;
16338 nghbr1 = nghbrId;
16339 }
16340
16341 const MFloat cellLength = c_cellLengthAtLevel(a_level(cellId));
16342 for(MInt i = 0; i < nDim; i++) {
16343 a_surfaceCoordinate(srfcId, i) = a_coordinate(cellId, i);
16344 }
16345 a_surfaceCoordinate(srfcId, orientation) += F1B2 * cellLength;
16346 a_surfaceArea(srfcId) = F1;
16347 for(MInt i = 0; i < nDim - 1; i++)
16348 a_surfaceArea(srfcId) *= cellLength;
16349 a_surfaceUpwindCoefficient(srfcId) = m_globalUpwindCoefficient;
16350
16351 a_surfaceFactor(srfcId, 0) = F1B2;
16352 a_surfaceFactor(srfcId, 1) = F1B2;
16353
16354 for(MInt i = 0; i < nDim; i++) {
16355 a_surfaceDeltaX(srfcId, i) = a_surfaceCoordinate(srfcId, i) - a_coordinate(nghbr0, i);
16356 a_surfaceDeltaX(srfcId, nDim + i) = a_surfaceCoordinate(srfcId, i) - a_coordinate(nghbr1, i);
16357 }
16358 a_surfaceBndryCndId(srfcId) = -1;
16359
16360 m_splitSurfaces.insert(srfcId);
16361}
16362
16363
16368template <MInt nDim, class SysEqn>
16370 ASSERT((fromSrfcId > -1) && (toSrfcId > -1) && (fromSrfcId < a_noSurfaces()) && (toSrfcId < a_noSurfaces()),
16371 "moveSurface(..) error");
16372
16373 const MInt ori = a_surfaceOrientation(fromSrfcId);
16374 a_surfaceOrientation(toSrfcId) = ori;
16375
16376 const MInt nghbrId0 = a_surfaceNghbrCellId(fromSrfcId, 0);
16377 const MInt nghbrId1 = a_surfaceNghbrCellId(fromSrfcId, 1);
16378 ASSERT(nghbrId0 > -1 && nghbrId1 > -1, "");
16379 ASSERT(nghbrId0 < a_noCells() && nghbrId1 < a_noCells(), "");
16380
16381 // for split faces, m_cellSurfaceMapping[ cell ][ splitFace ] does not point to the surface, connection only
16382 // 1-sided...
16383 ASSERT(((m_cellSurfaceMapping[nghbrId0][2 * ori + 1] > -1) && (m_cellSurfaceMapping[nghbrId1][2 * ori] > -1))
16384 || (a_bndryId(nghbrId0) > -1 && a_bndryId(nghbrId1) > -1) || a_level(nghbrId0) != a_level(nghbrId1),
16385 "");
16386
16387 if(nghbrId0 > -1) {
16388 if(m_cellSurfaceMapping[nghbrId0][2 * ori + 1] > -1) {
16389 ASSERT(m_cellSurfaceMapping[nghbrId0][2 * ori + 1] == fromSrfcId,
16390 to_string(m_cellSurfaceMapping[nghbrId1][2 * ori + 1]));
16391 m_cellSurfaceMapping[nghbrId0][2 * ori + 1] = toSrfcId;
16392 }
16393 }
16394 if(nghbrId1 > -1) {
16395 if(m_cellSurfaceMapping[nghbrId1][2 * ori] > -1) {
16396 ASSERT(m_cellSurfaceMapping[nghbrId1][2 * ori] == fromSrfcId, to_string(m_cellSurfaceMapping[nghbrId1][2 * ori]));
16397 m_cellSurfaceMapping[nghbrId1][2 * ori] = toSrfcId;
16398 }
16399 }
16400
16401 if(a_bndryId(nghbrId0) > -1) {
16402 // for split faces, m_associatedSrfc[ splitFace ] does not point to the surface, connection only 1-sided...
16403 // ASSERT( m_bndryCells->a[ a_bndryId( nghbrId0 ) ].m_associatedSrfc[ 2*ori + 1 ] == fromSrfcId,
16404 // a_bndryId( nghbrId0 ) << " " << m_bndryCells->a[ a_bndryId( nghbrId0 )
16405 // ].m_associatedSrfc[ 2*ori + 1 ] << " " << fromSrfcId );
16406 if(m_bndryCells->a[a_bndryId(nghbrId0)].m_associatedSrfc[2 * ori + 1] == fromSrfcId)
16407 m_bndryCells->a[a_bndryId(nghbrId0)].m_associatedSrfc[2 * ori + 1] = toSrfcId;
16408 MInt bndryId = a_bndryId(nghbrId0);
16409 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
16410 for(MInt i = 0; i < nDim; i++) {
16411 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] == fromSrfcId) {
16412 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = toSrfcId;
16413 }
16414 }
16415 }
16416 }
16417 if(a_bndryId(nghbrId1) > -1) {
16418 // for split faces, m_associatedSrfc[ splitFace ] does not point to the surface, connection only 1-sided...
16419 // ASSERT( m_bndryCells->a[ a_bndryId( nghbrId1 ) ].m_associatedSrfc[ 2*ori ] == fromSrfcId,
16420 // a_bndryId( nghbrId1 ) << " " << m_bndryCells->a[ a_bndryId( nghbrId0 )
16421 // ].m_associatedSrfc[ 2*ori + 1 ] << " " << fromSrfcId );
16422 if(m_bndryCells->a[a_bndryId(nghbrId1)].m_associatedSrfc[2 * ori] == fromSrfcId)
16423 m_bndryCells->a[a_bndryId(nghbrId1)].m_associatedSrfc[2 * ori] = toSrfcId;
16424 MInt bndryId = a_bndryId(nghbrId1);
16425 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
16426 for(MInt i = 0; i < nDim; i++) {
16427 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] == fromSrfcId) {
16428 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = toSrfcId;
16429 }
16430 }
16431 }
16432 }
16433
16434 if(m_splitSurfaces.erase(fromSrfcId)) m_splitSurfaces.insert(toSrfcId);
16435
16436 a_surfaceNghbrCellId(toSrfcId, 0) = nghbrId0;
16437 a_surfaceNghbrCellId(toSrfcId, 1) = nghbrId1;
16438 a_surfaceNghbrCellId(fromSrfcId, 0) = -1;
16439 a_surfaceNghbrCellId(fromSrfcId, 1) = -1;
16440
16441
16442 for(MInt i = 0; i < nDim; i++) {
16443 a_surfaceCoordinate(toSrfcId, i) = a_surfaceCoordinate(fromSrfcId, i);
16444 }
16445 a_surfaceArea(toSrfcId) = a_surfaceArea(fromSrfcId);
16446
16447 a_surfaceUpwindCoefficient(toSrfcId) = a_surfaceUpwindCoefficient(fromSrfcId);
16448 a_surfaceFactor(toSrfcId, 0) = a_surfaceFactor(fromSrfcId, 0);
16449 a_surfaceFactor(toSrfcId, 1) = a_surfaceFactor(fromSrfcId, 1);
16450
16451 for(MInt i = 0; i < nDim; i++) {
16452 a_surfaceDeltaX(toSrfcId, i) = a_surfaceDeltaX(fromSrfcId, i);
16453 a_surfaceDeltaX(toSrfcId, nDim + i) = a_surfaceDeltaX(fromSrfcId, nDim + i);
16454 }
16455
16456 a_surfaceBndryCndId(toSrfcId) = a_surfaceBndryCndId(fromSrfcId);
16457
16458 for(MInt v = 0; v < m_noCVars; v++) {
16459 a_surfaceVariable(toSrfcId, 0, v) = a_surfaceVariable(fromSrfcId, 0, v);
16460 a_surfaceVariable(toSrfcId, 1, v) = a_surfaceVariable(fromSrfcId, 1, v);
16461 }
16462
16463 m_noSurfaces = a_noSurfaces();
16464}
16465
16466
16471template <MInt nDim, class SysEqn>
16473 MInt delCnt = 0;
16474 MInt delCnt2 = 0;
16475 MInt lastSrfcId = a_noSurfaces() - 1;
16476
16477 if(a_noSurfaces() > 0) {
16478 for(set<MInt>::iterator it = m_freeSurfaceIndices.begin(); it != m_freeSurfaceIndices.end(); ++it) {
16479 MInt srfcId = *it;
16480 if((a_surfaceNghbrCellId(srfcId, 0) > -1) || (a_surfaceNghbrCellId(srfcId, 1) > -1)) {
16481 cerr << "Warning: not expected in compactSurfaces()" << endl;
16482 continue;
16483 }
16484 while((a_surfaceNghbrCellId(lastSrfcId, 0) < 0) || (a_surfaceNghbrCellId(lastSrfcId, 1) < 0)) {
16485 if(lastSrfcId < a_noSurfaces()) {
16486 m_surfaces.erase(lastSrfcId);
16487 m_surfaces.size(lastSrfcId);
16488 }
16489 lastSrfcId = a_noSurfaces() - 1;
16490 if(lastSrfcId == -1) break;
16491 }
16492 if(lastSrfcId == -1 || srfcId >= a_noSurfaces()) {
16493 break;
16494 } else {
16495 lastSrfcId = a_noSurfaces() - 1;
16496 moveSurface(srfcId, lastSrfcId);
16497 m_surfaces.erase(lastSrfcId);
16498 m_surfaces.size(lastSrfcId);
16499 delCnt2++;
16500 }
16501 delCnt++;
16502 }
16503 }
16504 m_freeSurfaceIndices.clear();
16505 m_noSurfaces = a_noSurfaces();
16506}
16507
16508
16513template <MInt nDim, class SysEqn>
16515 if(a_isBndryGhostCell(cellId)) return;
16516 if(c_noChildren(cellId) > 0) return;
16517 if(a_hasProperty(cellId, SolverCell::IsInactive)) return;
16518
16519 // 1. restore state of existing surfaces on the uncut mesh
16520 for(MInt dir = 0; dir < m_noDirs; dir++) {
16521 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
16522 if(srfcId > -1) {
16523 if((a_surfaceNghbrCellId(srfcId, 0) < 0) || (a_surfaceNghbrCellId(srfcId, 1) < 0)) {
16524 cerr << srfcId << " " << cellId << " " << dir << " " << a_coordinate(cellId, 0) << " "
16525 << a_coordinate(cellId, 1) << " " << c_neighborId(cellId, dir) << endl;
16526 cerr << a_isHalo(cellId) << " " << a_isHalo(c_neighborId(cellId, dir)) << " "
16527 << a_hasProperty(c_neighborId(cellId, dir), SolverCell::IsNotGradient) << endl;
16528 }
16529 createSurface(srfcId, a_surfaceNghbrCellId(srfcId, 0), a_surfaceNghbrCellId(srfcId, 1),
16530 a_surfaceOrientation(srfcId));
16531 } else {
16532 if(a_hasNeighbor(cellId, dir) > 0) {
16533 MInt nghbrId = c_neighborId(cellId, dir);
16534 if(c_noChildren(nghbrId) > 0) {
16535 for(MInt child = 0; child < m_noCellNodes; child++) {
16536 if(!childCode[dir][child]) continue;
16537 MInt childId = c_childId(nghbrId, child);
16538 if(childId < 0) continue;
16539 srfcId = m_cellSurfaceMapping[childId][m_revDir[dir]];
16540 if(srfcId > -1) {
16541 createSurface(srfcId, a_surfaceNghbrCellId(srfcId, 0), a_surfaceNghbrCellId(srfcId, 1),
16542 a_surfaceOrientation(srfcId));
16543 }
16544 }
16545 }
16546 }
16547 }
16548 }
16549
16550 // 2. restore previously deleted surfaces
16551 restoreSurfaces(cellId);
16552}
16553
16554
16559template <MInt nDim, class SysEqn>
16561 if(a_isBndryGhostCell(cellId)) mTerm(1, AT_, "Unexpected situation 0 in FvMbCartesianSolverXD::restoreSurfaces()");
16562 if(c_noChildren(cellId) > 0) return;
16563 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) return;
16564 if(a_hasProperty(cellId, SolverCell::IsInactive)) return;
16565
16566 for(MInt dir = 0; dir < m_noDirs; dir++) {
16567 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
16568
16569 if(srfcId < 0) {
16570 if(a_hasNeighbor(cellId, dir) > 0) {
16571 const MInt nghbrId = c_neighborId(cellId, dir);
16572 if(c_noChildren(nghbrId) > 0) {
16573 for(MInt child = 0; child < m_noCellNodes; child++) {
16574 if(!childCode[dir][child]) continue;
16575 const MInt childId = c_childId(nghbrId, child);
16576 if(childId < 0) continue;
16577 ASSERT(!a_isBndryGhostCell(childId), "");
16578 srfcId = m_cellSurfaceMapping[childId][m_revDir[dir]];
16579 if(srfcId > -1) {
16580 ASSERT(srfcId < a_noSurfaces(), to_string(srfcId) + " " + to_string(a_noSurfaces()));
16581 if(a_surfaceNghbrCellId(srfcId, m_revDir[dir] % 2) != cellId) {
16582 cerr << cellId << " " << nghbrId << " " << srfcId << " " << a_isHalo(cellId) << " " << a_level(cellId)
16583 << " " << a_level(nghbrId) << endl;
16584 cerr << dir << " " << child << " " << childId << endl;
16585 cerr << a_surfaceNghbrCellId(srfcId, 0) << " " << a_surfaceNghbrCellId(srfcId, 1) << " " << endl;
16586 if(a_surfaceNghbrCellId(srfcId, 0) > -1 && a_surfaceNghbrCellId(srfcId, 1) > -1) {
16587 cerr << a_level(a_surfaceNghbrCellId(srfcId, 0)) << " " << a_level(a_surfaceNghbrCellId(srfcId, 1))
16588 << " " << endl;
16589 }
16590 cerr << c_parentId(cellId) << " " << c_noChildren(cellId) << endl;
16591 for(MInt d = 0; d < m_noDirs; d++) {
16592 cerr << d << ": " << a_hasNeighbor(cellId, d) << "/" << c_neighborId(cellId, d);
16593 if(c_parentId(cellId) > -1) {
16594 cerr << " # " << a_hasNeighbor(c_parentId(cellId), d) << "/" << c_neighborId(c_parentId(cellId), d);
16595 }
16596 cerr << endl;
16597 }
16598 // writeVtkErrorFile();
16599 mTerm(1, AT_, "Unexpected situation in restoreSurfaces");
16600 }
16601 } else {
16602 if(a_hasProperty(childId, SolverCell::IsInactive)) continue;
16603 if(a_hasProperty(childId, SolverCell::IsNotGradient)) continue;
16604 if(a_isHalo(cellId) && a_isHalo(childId)) continue;
16605 srfcId = getNewSurfaceId();
16606
16607 ASSERT(a_level(cellId) != a_level(childId), "");
16608
16609 if(dir % 2 == 0)
16610 createSurface(srfcId, childId, cellId, dir / 2);
16611 else
16612 createSurface(srfcId, cellId, childId, dir / 2);
16613 }
16614 }
16615 } else {
16616 ASSERT(!a_isBndryGhostCell(nghbrId), "");
16617 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
16618 if(a_hasProperty(nghbrId, SolverCell::IsNotGradient)) continue;
16619 if(a_isHalo(cellId) && a_isHalo(nghbrId)) continue;
16620 srfcId = getNewSurfaceId();
16621 if(dir % 2 == 0)
16622 createSurface(srfcId, nghbrId, cellId, dir / 2);
16623 else
16624 createSurface(srfcId, cellId, nghbrId, dir / 2);
16625 }
16626 } else {
16627 if(c_parentId(cellId) > -1) {
16628 if(a_hasNeighbor(c_parentId(cellId), dir) > 0) {
16629 const MInt nghbrId = c_neighborId(c_parentId(cellId), dir);
16630 ASSERT(!a_isBndryGhostCell(nghbrId), "");
16631 srfcId = m_cellSurfaceMapping[nghbrId][m_revDir[dir]];
16632 if(srfcId > -1) {
16633 m_log << "nghb surf " << globalTimeStep << " " << srfcId << " " << nghbrId << " " << cellId << " "
16634 << a_noSurfaces() << " / " << c_isToDelete(cellId) << " "
16635 << a_hasProperty(cellId, SolverCell::IsInactive) << " " << c_isToDelete(nghbrId) << " "
16636 << a_hasProperty(nghbrId, SolverCell::IsInactive) << " " << a_surfaceNghbrCellId(srfcId, 0) << " "
16637 << a_surfaceNghbrCellId(srfcId, 1) << endl;
16638 }
16639 ASSERT(srfcId < a_noSurfaces(), "");
16640 if(srfcId > -1) {
16641 cerr << domainId() << ": " << srfcId << " " << cellId << " " << nghbrId << " / "
16642 << a_surfaceNghbrCellId(srfcId, 0) << " " << a_surfaceNghbrCellId(srfcId, 1) << " / "
16643 << a_level(cellId) << " " << a_level(nghbrId) << " / " << a_coordinate(cellId, 0) << " "
16644 << a_coordinate(cellId, 1) << " / " << a_coordinate(nghbrId, 0) << " " << a_coordinate(nghbrId, 1)
16645 << endl;
16646 }
16647 ASSERT(srfcId < 0, "");
16648 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
16649 if(a_hasProperty(nghbrId, SolverCell::IsNotGradient)) continue;
16650 if(a_isHalo(cellId) && a_isHalo(nghbrId)) continue;
16651 if(c_noChildren(nghbrId) > 0) {
16652 cerr << domainId() << ": error surf " << dir << " " << cellId << " " << nghbrId << " "
16653 << c_globalId(cellId) << " " << c_globalId(nghbrId) << " " << c_neighborId(cellId, dir, false) << " "
16654 << c_noChildren(nghbrId) << " " << c_childId(nghbrId, 0) << " " << a_level(cellId) << " "
16655 << a_level(nghbrId) << " " << a_isHalo(cellId) << " " << a_isHalo(nghbrId) << " "
16656 << a_levelSetValuesMb(cellId, 0) / c_cellLengthAtCell(cellId) << " "
16657 << a_levelSetValuesMb(nghbrId, 0) / c_cellLengthAtCell(nghbrId) << endl;
16658 }
16659 ASSERT(c_noChildren(nghbrId) == 0, "");
16660 if(srfcId < 0) srfcId = getNewSurfaceId();
16661
16662 ASSERT(a_level(cellId) != a_level(nghbrId), "");
16663 if(dir % 2 == 0)
16664 createSurface(srfcId, nghbrId, cellId, dir / 2);
16665 else
16666 createSurface(srfcId, cellId, nghbrId, dir / 2);
16667 }
16668 }
16669 }
16670 } else {
16671 if(a_surfaceNghbrCellId(srfcId, 0) < 0 || a_surfaceNghbrCellId(srfcId, 1) < 0) {
16672 cerr << "srcf neighbors: " << srfcId << " " << cellId << " " << a_surfaceNghbrCellId(srfcId, 0) << " "
16673 << a_surfaceNghbrCellId(srfcId, 0) << endl;
16674 }
16675 }
16676 }
16677}
16678
16679
16685template <MInt nDim, class SysEqn>
16686inline MInt FvMbCartesianSolverXD<nDim, SysEqn>::getFacingNghbrs(const MInt cellId, const MBool includeAllChilds) {
16687 MInt counter = 0;
16688
16689 for(MInt dir = 0; dir < m_noDirs; dir++) {
16690 if(a_hasNeighbor(cellId, dir) > 0) {
16691 MInt nghbrId = c_neighborId(cellId, dir);
16692 if(c_noChildren(nghbrId) > 0) {
16693 for(MInt child = 0; child < m_noCellNodes; child++) {
16694 if(!includeAllChilds && !childCode[dir][child]) continue;
16695 MInt childId = c_childId(nghbrId, child);
16696 if(childId < 0) continue;
16697 if(a_isBndryGhostCell(childId)) continue;
16698 if(!childCode[dir][child] && c_noChildren(childId) > 0) continue;
16699
16700 if(!((c_noChildren(childId) == 0) || (a_isHalo(cellId)))) {
16701 cerr << cellId << " " << nghbrId << " " << childId << " " << c_childId(childId, 0) << " " << dir << " "
16702 << child << " / " << a_isHalo(cellId) << " " << a_isWindow(cellId) << " " << a_isHalo(childId) << " "
16703 << a_isWindow(childId) << " " << a_isHalo(nghbrId) << " " << a_isWindow(nghbrId) << " // "
16704 << c_noChildren(cellId) << " " << c_noChildren(childId) << " " << a_level(cellId) << " /// "
16705 << (c_childId(childId, 0) > -1 ? c_noChildren(c_childId(childId, 0)) : -1) << " "
16706 << (c_childId(childId, 1) > -1 ? c_noChildren(c_childId(childId, 1)) : -1) << " "
16707 << (c_childId(childId, 2) > -1 ? c_noChildren(c_childId(childId, 2)) : -1) << " "
16708 << (c_childId(childId, 3) > -1 ? c_noChildren(c_childId(childId, 3)) : -1) << " "
16709 << (c_childId(childId, 4) > -1 ? c_noChildren(c_childId(childId, 4)) : -1) << " "
16710 << (c_childId(childId, 5) > -1 ? c_noChildren(c_childId(childId, 5)) : -1) << " "
16711 << (c_childId(childId, 6) > -1 ? c_noChildren(c_childId(childId, 6)) : -1) << " "
16712 << (c_childId(childId, 7) > -1 ? c_noChildren(c_childId(childId, 7)) : -1) << endl;
16713 }
16714 ASSERT((c_noChildren(childId) == 0) || (a_isHalo(cellId)),
16715 "(1) No children expected FvMbCartesianSolverXD::getFacingNghbrs(..) "
16716 << cellId << " " << nghbrId << " " << childId << " " << c_childId(childId, 0) << " " << dir << " "
16717 << child << " " << c_noChildren(childId));
16718 m_nghbrList[counter++] = childId;
16719 }
16720 } else {
16721 ASSERT(nghbrId > -1, "Invalid neighbor id in FvMbCartesianSolverXD::getFacingNghbrs(..)");
16722 if(a_isBndryGhostCell(nghbrId)) continue;
16723 m_nghbrList[counter++] = nghbrId;
16724 }
16725 } else {
16726 if(c_parentId(cellId) > -1) {
16727 if(a_hasNeighbor(c_parentId(cellId), dir) > 0) {
16728 MInt nghbrId = c_neighborId(c_parentId(cellId), dir);
16729 ASSERT(nghbrId > -1, "Invalid neighbor id in FvMbCartesianSolverXD::getFacingNghbrs(..)");
16730 if(a_isBndryGhostCell(nghbrId)) continue;
16731 if(c_noChildren(nghbrId) == 0) m_nghbrList[counter++] = nghbrId;
16732 }
16733 }
16734 }
16735 }
16736 return counter;
16737}
16738
16739
16744template <MInt nDim, class SysEqn>
16746 const MInt dir = a_surfaceOrientation(srfcId);
16747 const MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
16748 const MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
16749
16750 if(nghbr0 > -1) {
16751 ASSERT(m_cellSurfaceMapping[nghbr0][2 * dir + 1] < 0 || m_cellSurfaceMapping[nghbr0][2 * dir + 1] == srfcId,
16752 to_string(m_cellSurfaceMapping[nghbr0][2 * dir + 1]));
16753 m_cellSurfaceMapping[nghbr0][2 * dir + 1] = -1;
16754 if(a_bndryId(nghbr0) > -1) {
16755 m_bndryCells->a[a_bndryId(nghbr0)].m_associatedSrfc[2 * dir + 1] = -1;
16756 MInt bndryId = a_bndryId(nghbr0);
16757 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
16758 for(MInt i = 0; i < nDim; i++) {
16759 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] == srfcId) {
16760 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = -1;
16761 }
16762 }
16763 }
16764 }
16765 }
16766
16767 if(nghbr1 > -1) {
16768 ASSERT(m_cellSurfaceMapping[nghbr1][2 * dir] < 0 || m_cellSurfaceMapping[nghbr1][2 * dir] == srfcId,
16769 to_string(m_cellSurfaceMapping[nghbr1][2 * dir]));
16770 m_cellSurfaceMapping[nghbr1][2 * dir] = -1;
16771 if(a_bndryId(nghbr1) > -1) {
16772 m_bndryCells->a[a_bndryId(nghbr1)].m_associatedSrfc[2 * dir] = -1;
16773 MInt bndryId = a_bndryId(nghbr1);
16774 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
16775 for(MInt i = 0; i < nDim; i++) {
16776 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] == srfcId) {
16777 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = -1;
16778 }
16779 }
16780 }
16781 }
16782 }
16783
16784 a_surfaceNghbrCellId(srfcId, 0) = -1;
16785 a_surfaceNghbrCellId(srfcId, 1) = -1;
16786 a_surfaceBndryCndId(srfcId) = -1;
16787 m_splitSurfaces.erase(srfcId);
16788
16789 if(srfcId >= a_noSurfaces()) {
16790 mTerm(1, AT_, "Invalid surface.");
16791 } else if(srfcId == (a_noSurfaces() - 1)) {
16792 m_surfaces.erase(a_noSurfaces() - 1);
16793 m_surfaces.size(a_noSurfaces() - 1);
16794 m_noSurfaces = a_noSurfaces();
16795 } else {
16796 m_freeSurfaceIndices.insert(srfcId);
16797 }
16798}
16799
16800
16805template <MInt nDim, class SysEqn>
16807 for(MInt dir = 0; dir < m_noDirs; dir++) {
16808 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
16809
16810 if(srfcId > -1) {
16811 deleteSurface(srfcId);
16812 } else {
16813 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && checkNeighborActive(cellId, dir)
16814 && a_hasNeighbor(cellId, dir) > 0) {
16815 MInt nghbrId = c_neighborId(cellId, dir);
16816 if(c_noChildren(nghbrId) > 0) {
16817 for(MInt child = 0; child < m_noCellNodes; child++) {
16818 if(!childCode[dir][child]) continue;
16819 MInt childId = c_childId(nghbrId, child);
16820 if(childId < 0) continue;
16821 srfcId = m_cellSurfaceMapping[childId][m_revDir[dir]];
16822 if(srfcId > -1) {
16823 deleteSurface(srfcId);
16824 }
16825 }
16826 }
16827 }
16828 }
16829 }
16830}
16831
16832
16837template <MInt nDim, class SysEqn>
16839 if(cellId1 == cellId0) return;
16840
16842
16843 for(MInt v = 0; v < m_noFVars; v++) {
16844 std::swap(m_rhs0[cellId1][v], m_rhs0[cellId0][v]);
16845 }
16846
16847 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
16848 std::swap(a_levelSetValuesMb(cellId1, set), a_levelSetValuesMb(cellId0, set));
16849 std::swap(a_associatedBodyIds(cellId1, set), a_associatedBodyIds(cellId0, set));
16850 }
16851
16852 std::swap(m_cellVolumesDt1[cellId1], m_cellVolumesDt1[cellId0]);
16853 if(m_dualTimeStepping) std::swap(m_cellVolumesDt2[cellId1], m_cellVolumesDt2[cellId0]);
16854
16855 if(!m_oldBndryCells.empty()) {
16856 auto it0 = m_oldBndryCells.find(cellId0);
16857 auto it1 = m_oldBndryCells.find(cellId1);
16858 if(it0 != m_oldBndryCells.end() && it1 != m_oldBndryCells.end()) {
16859 std::swap(it0->second, it1->second);
16860 } else if(it0 != m_oldBndryCells.end()) {
16861 MFloat val = it0->second;
16862 m_oldBndryCells.erase(it0);
16863 m_oldBndryCells.insert(make_pair(cellId1, val));
16864 } else if(it1 != m_oldBndryCells.end()) {
16865 MFloat val = it1->second;
16866 m_oldBndryCells.erase(it1);
16867 m_oldBndryCells.insert(make_pair(cellId0, val));
16868 }
16869 }
16870
16871 if(!m_nearBoundaryBackup.empty()) {
16872 auto it0 = m_nearBoundaryBackup.find(cellId0);
16873 auto it1 = m_nearBoundaryBackup.find(cellId1);
16874 if(it0 != m_nearBoundaryBackup.end() && it1 != m_nearBoundaryBackup.end()) {
16875 std::swap(it0->second, it1->second);
16876 } else if(it0 != m_nearBoundaryBackup.end()) {
16877 vector<MFloat> val(it0->second);
16878 m_nearBoundaryBackup.erase(it0);
16879 m_nearBoundaryBackup.insert(make_pair(cellId1, val));
16880 } else if(it1 != m_nearBoundaryBackup.end()) {
16881 vector<MFloat> val(it1->second);
16882 m_nearBoundaryBackup.erase(it1);
16883 m_nearBoundaryBackup.insert(make_pair(cellId0, val));
16884 }
16885 }
16886
16887 if(!m_coarseOldBndryCells.empty()) {
16888 auto it0 = m_coarseOldBndryCells.find(cellId0);
16889 auto it1 = m_coarseOldBndryCells.find(cellId1);
16890 if(it0 != m_coarseOldBndryCells.end() && it1 == m_coarseOldBndryCells.end()) {
16891 // nothing to be done
16892 } else if(it0 != m_coarseOldBndryCells.end()) {
16893 m_coarseOldBndryCells.erase(it0);
16894 m_coarseOldBndryCells.insert(cellId1);
16895 } else if(it1 != m_coarseOldBndryCells.end()) {
16896 m_coarseOldBndryCells.erase(it1);
16897 m_coarseOldBndryCells.insert(cellId0);
16898 }
16899 }
16900
16901 if(!m_oldGeomBndryCells.empty()) {
16902 auto it0 = m_oldGeomBndryCells.find(cellId0);
16903 auto it1 = m_oldGeomBndryCells.find(cellId1);
16904 if(it0 != m_oldGeomBndryCells.end() && it1 == m_oldGeomBndryCells.end()) {
16905 std::swap(it0->second, it1->second);
16906 } else if(it0 != m_oldGeomBndryCells.end()) {
16907 const MFloat volume = it0->second;
16908 m_oldGeomBndryCells.erase(it0);
16909 m_oldGeomBndryCells.insert(make_pair(cellId1, volume));
16910 } else if(it1 != m_oldGeomBndryCells.end()) {
16911 const MFloat volume = it1->second;
16912 m_oldGeomBndryCells.erase(it1);
16913 m_oldGeomBndryCells.insert(make_pair(cellId0, volume));
16914 }
16915 }
16916
16917 // Swap stored azimuthal near boundary data
16918 if(grid().azimuthalPeriodicity()) {
16919 MInt cnt0 = m_azimuthalNearBoundaryBackup.count(cellId0);
16920 MInt cnt1 = m_azimuthalNearBoundaryBackup.count(cellId1);
16921 ASSERT(cnt0 < 3 && cnt1 < 3, "cnt should not exceed 2");
16922 if(cnt0 == 2) {
16923 auto range = m_azimuthalNearBoundaryBackup.equal_range(cellId0);
16924 auto it00 = range.first;
16925 auto it01 = it00++;
16926 if(cnt1 == 0) {
16927 {
16928 pair<vector<MFloat>, vector<MUlong>> tmp(it00->second.first, it00->second.second);
16929 m_azimuthalNearBoundaryBackup.erase(it00);
16930 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId1, tmp));
16931 }
16932 {
16933 pair<vector<MFloat>, vector<MUlong>> tmp(it01->second.first, it01->second.second);
16934 m_azimuthalNearBoundaryBackup.erase(it01);
16935 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId1, tmp));
16936 }
16937 } else if(cnt1 == 1) {
16938 {
16939 auto it10 = m_azimuthalNearBoundaryBackup.find(cellId1);
16940 std::swap(it00->second, it10->second);
16941 }
16942 {
16943 pair<vector<MFloat>, vector<MUlong>> tmp(it01->second.first, it01->second.second);
16944 m_azimuthalNearBoundaryBackup.erase(it01);
16945 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId1, tmp));
16946 }
16947 } else { // cnt1 == 2
16948 auto range2 = m_azimuthalNearBoundaryBackup.equal_range(cellId1);
16949 auto it10 = range2.first;
16950 auto it11 = it10++;
16951 std::swap(it00->second, it10->second);
16952 std::swap(it01->second, it11->second);
16953 }
16954 } else if(cnt0 == 1) {
16955 auto it00 = m_azimuthalNearBoundaryBackup.find(cellId0);
16956 if(cnt1 == 0) {
16957 pair<vector<MFloat>, vector<MUlong>> tmp(it00->second.first, it00->second.second);
16958 m_azimuthalNearBoundaryBackup.erase(it00);
16959 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId1, tmp));
16960 } else if(cnt1 == 1) {
16961 auto it10 = m_azimuthalNearBoundaryBackup.find(cellId1);
16962 std::swap(it00->second, it10->second);
16963 } else { // cnt1 == 2
16964 auto range = m_azimuthalNearBoundaryBackup.equal_range(cellId1);
16965 auto it10 = range.first;
16966 auto it11 = it10++;
16967 std::swap(it00->second, it10->second);
16968 pair<vector<MFloat>, vector<MUlong>> tmp(it11->second.first, it11->second.second);
16969 m_azimuthalNearBoundaryBackup.erase(it11);
16970 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId0, tmp));
16971 }
16972 } else { // cnt0 == 0
16973 if(cnt1 == 0) {
16974 // Nothing to be done
16975 } else if(cnt1 == 1) {
16976 auto it10 = m_azimuthalNearBoundaryBackup.find(cellId1);
16977 pair<vector<MFloat>, vector<MUlong>> tmp(it10->second.first, it10->second.second);
16978 m_azimuthalNearBoundaryBackup.erase(it10);
16979 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId0, tmp));
16980 } else { // cnt1 == 2
16981 auto range = m_azimuthalNearBoundaryBackup.equal_range(cellId1);
16982 auto it10 = range.first;
16983 auto it11 = it10++;
16984 {
16985 pair<vector<MFloat>, vector<MUlong>> tmp(it10->second.first, it10->second.second);
16986 m_azimuthalNearBoundaryBackup.erase(it10);
16987 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId0, tmp));
16988 }
16989 {
16990 pair<vector<MFloat>, vector<MUlong>> tmp(it11->second.first, it11->second.second);
16991 m_azimuthalNearBoundaryBackup.erase(it11);
16992 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId0, tmp));
16993 }
16994 }
16995 }
16996 }
16997}
16998
16999
17004template <MInt nDim, class SysEqn>
17006 MInt srfcId = -1;
17007
17008 if(m_freeSurfaceIndices.size() > 0) {
17009 set<MInt>::iterator it = m_freeSurfaceIndices.begin();
17010 srfcId = *(it);
17011 m_freeSurfaceIndices.erase(it);
17012 if(srfcId >= a_noSurfaces()) {
17013 srfcId = -1;
17014 m_freeSurfaceIndices.clear();
17015 }
17016 }
17017 if(srfcId < 0) {
17018 srfcId = a_noSurfaces();
17019 m_surfaces.append();
17020 m_noSurfaces = a_noSurfaces();
17021 }
17022
17023 return srfcId;
17024}
17025
17026
17031template <MInt nDim, class SysEqn>
17033 TRACE();
17034
17035 m_log << "Creating initial surfaces..." << endl;
17036
17037 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
17038 MFloatScratchSpace surfArea(noBndryCells, m_noDirs, AT_, "surfArea");
17039 MFloatScratchSpace surfCentroid(noBndryCells, m_noDirs, nDim, AT_, "surfCentroid");
17040 surfArea.fill(sqrt(-F1));
17041 surfCentroid.fill(sqrt(-F1));
17042 for(MInt srfcId = 0; srfcId < a_noSurfaces(); srfcId++) {
17043 for(MInt side = 0; side < 2; side++) {
17044 MInt ori = a_surfaceOrientation(srfcId);
17045 MInt cellId = a_surfaceNghbrCellId(srfcId, side);
17046 if(cellId > -1) {
17047 MInt bndryId = a_bndryId(cellId);
17048 if(bndryId > -1) {
17049 MInt dir = (side == 0) ? 2 * ori + 1 : 2 * ori;
17050 surfArea(bndryId, dir) = a_surfaceArea(srfcId);
17051
17052 for(MInt i = 0; i < nDim; i++) {
17053 surfCentroid(bndryId, dir, i) = a_surfaceCoordinate(srfcId, i);
17054 }
17055 }
17056 }
17057 }
17058 }
17059
17060 // store all surfaces that have been generated so far (Cartesian cut surfaces)
17061 // const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
17062
17063 // delete the surfaces that won't be required later
17064 // 1) store the relevant surfaces
17065 MInt counter = 0;
17066 MInt otherDir[] = {1, 0, 3, 2, 5, 4};
17067 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
17068 MInt cell = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
17069
17070 if(!a_hasProperty(cell, SolverCell::IsOnCurrentMGLevel)) continue;
17071 MInt nghbrId = -1;
17072 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
17073 if(a_hasNeighbor(cell, dirId) > 0) {
17074 nghbrId = c_neighborId(cell, dirId);
17075 } else {
17076 if(c_parentId(cell) > -1) {
17077 if(a_hasNeighbor(c_parentId(cell), dirId) > 0) {
17078 nghbrId = c_neighborId(c_parentId(cell), dirId);
17079 } else {
17080 continue;
17081 }
17082 } else {
17083 continue;
17084 }
17085 }
17086
17087 if(a_bndryId(nghbrId) < 0) continue;
17088 MBool createSrfc = true;
17089 // check conditions for surface generation
17090 // (1) no master-slave interface
17091 // (2) no slave-slave interface if both slave cells have the same master
17092 // (3) no periodic-periodic interface
17093 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > -1) {
17094 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == nghbrId
17095 || m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId
17096 == m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId) {
17097 createSrfc = false;
17098 }
17099 }
17100 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId > -1) {
17101 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == (MInt)cell
17102 || m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId
17103 == m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId) {
17104 createSrfc = false;
17105 }
17106 }
17107 if(a_isPeriodic(cell) && a_isPeriodic(nghbrId)) createSrfc = false;
17108
17109 // do not create a surface between two halo cells
17110 // create a surface if slave-neighbor are both halo cells but the master is not
17111 if(a_isHalo(cell) && a_isHalo(nghbrId)) {
17112 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == -1
17113 && m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == -1) {
17114 createSrfc = false;
17115 }
17116 }
17117
17118 // this is valid for isotropical refinement only!!
17119 if(!createSrfc) continue;
17120
17121 if((a_level(cell) > a_level(nghbrId)) || ((a_level(cell) == a_level(nghbrId)) && dirId % 2 == 0)) {
17122 MInt oldSrfcId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_associatedSrfc[dirId];
17123
17124 if(oldSrfcId < 0) continue;
17125
17126 if(oldSrfcId != counter) {
17127 m_surfaces.copy(oldSrfcId, counter);
17128 m_surfaces.erase(oldSrfcId);
17129 if(a_level(cell) == a_level(nghbrId))
17130 m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_associatedSrfc[otherDir[dirId]] = counter;
17131 }
17132 counter++;
17133 }
17134 }
17135 }
17136
17137 // delete all other surfaces created in createCutFace
17138 while(a_noSurfaces() > counter) {
17139 MInt size = a_noSurfaces();
17140 m_surfaces.erase(size - 1);
17141 m_surfaces.size(size - 1);
17142 }
17143
17144 // store relevant surface information in scratch space
17145 MInt noSurfaces = a_noSurfaces();
17146 MIntScratchSpace surfaceOrientation(noSurfaces, AT_, "surfaceOrientation");
17147 MFloatScratchSpace surfaceArea(noSurfaces, AT_, "surfaceArea");
17148 MIntScratchSpace surfaceNeighbors(noSurfaces, 2, AT_, "surfaceNeighbors");
17149 MFloatScratchSpace surfaceCentroid(noSurfaces, nDim, AT_, "surfaceCentroid");
17150 for(MInt s = 0; s < noSurfaces; s++) {
17151 surfaceOrientation[s] = a_surfaceOrientation(s);
17152 surfaceArea[s] = a_surfaceArea(s);
17153 surfaceNeighbors(s, 0) = a_surfaceNghbrCellId(s, 0);
17154 surfaceNeighbors(s, 1) = a_surfaceNghbrCellId(s, 1);
17155 for(MInt i = 0; i < nDim; i++) {
17156 surfaceCentroid(s, i) = a_surfaceCoordinate(s, i);
17157 }
17158 }
17159
17160 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
17161 if(a_isBndryGhostCell(cellId)) continue;
17162 if(c_noChildren(cellId) > 0) continue;
17163 removeSurfaces(cellId);
17164 }
17165 m_surfaces.clear();
17166
17167 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
17168 if(a_bndryId(cellId) < -1) continue;
17169 if(a_isBndryGhostCell(cellId)) continue;
17170 if(c_noChildren(cellId) > 0) continue;
17171 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
17172 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17173
17174 restoreSurfaces(cellId);
17175 }
17176
17177 m_log << a_noSurfaces() << endl;
17178
17179 // correct cut surfaces of outer boundary cells with the previously generated surface information
17180 // first set the associatedSrfc pointers correctly
17181 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++)
17182 for(MInt dir = 0; dir < m_noDirs; dir++)
17183 m_fvBndryCnd->m_bndryCells->a[bndryId].m_associatedSrfc[dir] = -1;
17184
17185 for(MInt srfcId = 0; srfcId < a_noSurfaces(); srfcId++) {
17186 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
17187 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
17188 ASSERT(nghbr0 > -1 && nghbr1 > -1 && nghbr0 < a_noCells() && nghbr1 < a_noCells(), "");
17189 MInt bndryIdN0 = a_bndryId(nghbr0);
17190 MInt bndryIdN1 = a_bndryId(nghbr1);
17191 if(bndryIdN0 > -1 && bndryIdN1 > -1) {
17192 MInt dirN0 = 2 * a_surfaceOrientation(srfcId) + 1;
17193 MInt dirN1 = 2 * a_surfaceOrientation(srfcId) + 0;
17194 MInt level0 = a_level(nghbr0);
17195 MInt level1 = a_level(nghbr1);
17196 if(level0 >= level1) m_fvBndryCnd->m_bndryCells->a[bndryIdN0].m_associatedSrfc[dirN0] = srfcId;
17197 if(level1 >= level0) m_fvBndryCnd->m_bndryCells->a[bndryIdN1].m_associatedSrfc[dirN1] = srfcId;
17198
17199
17200 a_surfaceArea(srfcId) = surfArea(bndryIdN0, dirN0);
17201 for(MInt i = 0; i < nDim; i++) {
17202 a_surfaceCoordinate(srfcId, i) = surfCentroid(bndryIdN0, dirN0, i);
17203 }
17204 }
17205 }
17206
17207 // then run over the previously created surfaces and correct the information of the newly created surfaces
17208 for(MInt s = 0; s < noSurfaces; s++) {
17209 MInt nghbr0 = surfaceNeighbors(s, 0);
17210 MInt nghbr1 = surfaceNeighbors(s, 1);
17211 if(nghbr0 < 0 || nghbr1 < 0) continue;
17212 ASSERT(nghbr0 > -1 && nghbr1 > -1 && nghbr0 < a_noCells() && nghbr1 < a_noCells(), "");
17213 MInt bndryIdN0 = a_bndryId(nghbr0);
17214 MInt bndryIdN1 = a_bndryId(nghbr1);
17215 if(bndryIdN0 > -1 && bndryIdN1 > -1) {
17216 MInt dirN0 = 2 * surfaceOrientation(s) + 1;
17217 MInt dirN1 = 2 * surfaceOrientation(s) + 0;
17218 MInt level0 = a_level(nghbr0);
17219 MInt level1 = a_level(nghbr1);
17220 if(level0 == level1) {
17221 MInt associatedSrfc0 = m_fvBndryCnd->m_bndryCells->a[bndryIdN0].m_associatedSrfc[dirN0];
17222 MInt associatedSrfc1 = m_fvBndryCnd->m_bndryCells->a[bndryIdN1].m_associatedSrfc[dirN1];
17223 ASSERT(associatedSrfc0 == associatedSrfc1, "");
17224 }
17225 MInt associatedSrfc = (level0 > level1) ? m_fvBndryCnd->m_bndryCells->a[bndryIdN0].m_associatedSrfc[dirN0]
17226 : m_fvBndryCnd->m_bndryCells->a[bndryIdN1].m_associatedSrfc[dirN1];
17227 if(associatedSrfc < 0)
17228 cerr << "surface info " << nghbr0 << " " << nghbr1 << " " << c_globalId(nghbr0) << " " << c_globalId(nghbr1)
17229 << " / " << level0 << " " << level1 << " " << dirN0 << " " << dirN1 << " / "
17230 << m_fvBndryCnd->m_bndryCells->a[bndryIdN0].m_associatedSrfc[dirN0] << " "
17231 << m_fvBndryCnd->m_bndryCells->a[bndryIdN1].m_associatedSrfc[dirN1] << " / "
17232 << a_hasProperty(nghbr0, SolverCell::IsInactive) << " " << a_hasProperty(nghbr1, SolverCell::IsInactive)
17233 << " / " << a_hasProperty(nghbr0, SolverCell::IsNotGradient) << " "
17234 << a_hasProperty(nghbr1, SolverCell::IsNotGradient) << " / " << surfaceCentroid(s, 0) << " "
17235 << surfaceCentroid(s, 1) << " " << surfaceCentroid(s, nDim - 1) << endl;
17236 // ASSERT( associatedSrfc > -1 && associatedSrfc < a_noSurfaces(), to_string(associatedSrfc));
17237 if(associatedSrfc > -1) {
17238 ASSERT(associatedSrfc > -1 && associatedSrfc < a_noSurfaces(), to_string(associatedSrfc));
17239 ASSERT(a_surfaceOrientation(associatedSrfc) == surfaceOrientation(s), "");
17240 ASSERT(a_surfaceNghbrCellId(associatedSrfc, 0) == surfaceNeighbors(s, 0), "");
17241 ASSERT(a_surfaceNghbrCellId(associatedSrfc, 1) == surfaceNeighbors(s, 1), "");
17242 }
17243 }
17244 }
17245
17246 m_log << "...done." << endl;
17247 m_log << a_noSurfaces() << " surfaces created." << endl;
17248}
17249
17250
17255template <MInt nDim, class SysEqn>
17257 TRACE();
17258
17259 m_reconstructionConstants.clear();
17260 m_reconstructionCellIds.clear();
17261 m_reconstructionNghbrIds.clear();
17262
17263 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
17264
17265 // reset number of reconstruction Neighbors for all cells!
17266 a_noReconstructionNeighbors(cellId) = 0;
17267
17268 if(a_isBndryGhostCell(cellId)) continue;
17269 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17270 if(!a_hasProperty(cellId, SolverCell::IsFlux)) continue;
17271 if(a_bndryId(cellId) == -2) continue;
17272 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
17273 if(c_noChildren(cellId) > 0) continue;
17274 if(a_bndryId(cellId) > -1) {
17275 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_linkedCellId > -1) continue;
17276 }
17277 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17278
17279 // recompute number of reconstruction constants for relevant cells
17280 rebuildReconstructionConstants(cellId);
17281 }
17282}
17283
17284
17289template <MInt nDim, class SysEqn>
17291 TRACE();
17292
17293#if defined _MB_DEBUG_ || !defined NDEBUG
17294
17295 for(MInt i = 0; i < noNeighborDomains(); i++) {
17296 for(MInt j = 0; j < m_noMaxLevelWindowCells[i]; j++) {
17297 MInt cellId = m_maxLevelWindowCells[i][j];
17298 for(MInt v = 0; v < m_noPVars; v++) {
17299 if(std::isnan(a_pvariable(cellId, v))) {
17300 cerr << domainId() << ": nan send " << cellId << " " << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)
17301 << " " << a_hasProperty(cellId, SolverCell::IsInactive) << " " << c_noChildren(cellId) << " "
17302 << a_levelSetValuesMb(cellId, 0) << endl;
17303 }
17304 }
17305 }
17306 }
17307#endif
17308
17310
17311 // temporary split cell fix: all split childs receive the variables of their parents!
17312 for(MInt sc = 0; (unsigned)sc < m_splitCells.size(); sc++) {
17313 MInt scId = m_splitCells[sc];
17314 for(MInt ssc = 0; (unsigned)ssc < m_splitChilds[sc].size(); ssc++) {
17315 MInt splitChildId = m_splitChilds[sc][ssc];
17316 for(MInt v = 0; v < m_noCVars; v++) {
17317 a_variable(splitChildId, v) = a_variable(scId, v);
17318 }
17319 for(MInt v = 0; v < m_noPVars; v++) {
17320 a_pvariable(splitChildId, v) = a_pvariable(scId, v);
17321 }
17322 }
17323 }
17324
17325
17326#ifdef _MB_DEBUG_
17327
17328 if(!isMultilevel() || isMultilevelPrimary()) {
17329 m_solutionDiverged = false;
17330 MInt cnt = 0;
17331 for(MInt i = 0; i < noNeighborDomains(); i++) {
17332 for(MInt j = 0; j < m_noMaxLevelHaloCells[i]; j++) {
17333 MInt cellId = m_maxLevelHaloCells[i][j];
17334 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17335 ASSERT(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel), "");
17336 for(MInt v = 0; v < m_noPVars; v++) {
17337 if(!(a_pvariable(cellId, v) >= F0 || a_pvariable(cellId, v) < F0) || std::isnan(a_pvariable(cellId, v))) {
17338 cerr << domainId() << ": EXC " << i << " " << j << " " << c_globalId(cellId) << " " << a_bndryId(cellId)
17339 << " " << a_level(cellId) << " /v " << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId))
17340 << " " << m_cellVolumesDt1[cellId] / grid().gridCellVolume(a_level(cellId)) << " " << v << " "
17341 << a_variable(cellId, v) << " /l " << a_levelSetValuesMb(cellId, 0) / c_cellLengthAtCell(cellId) << " "
17342 << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " "
17343 << a_coordinate(cellId, mMin((MInt)FD, 2)) << " "
17344 << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << endl;
17345 m_solutionDiverged = true;
17346 cnt++;
17347 }
17348 }
17349 // if ( a_cellVolume(cellId)/grid().gridCellVolume(a_level(cellId)) > m_fvBndryCnd->m_volumeLimitWall ) {
17350 if(a_pvariable(cellId, PV->RHO) < F0 || a_pvariable(cellId, PV->P) < F0) {
17351 cerr << domainId() << ": EXC2 " << i << " " << j << " " << neighborDomain(i) << " / " << c_globalId(cellId)
17352 << " " << a_bndryId(cellId) << " " << a_level(cellId) << " /r " << a_pvariable(cellId, PV->RHO) << " /p "
17353 << a_pvariable(cellId, PV->P) << " /v " << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId))
17354 << " " << m_cellVolumesDt1[cellId] / grid().gridCellVolume(a_level(cellId)) << " /l "
17355 << a_levelSetValuesMb(cellId, 0) / c_cellLengthAtCell(cellId) << " " << a_coordinate(cellId, 0) << " "
17356 << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, mMin((MInt)FD, 2)) << " "
17357 << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << endl;
17358 m_solutionDiverged = true;
17359 cnt++;
17360 }
17361 //}
17362 if(cnt >= 10) break;
17363 }
17364 if(cnt >= 10) break;
17365 }
17366 if(cnt >= 10) cerr << "More than 10 errors. Not reporting any more." << endl;
17367 if(m_solutionDiverged) {
17368 cerr << "Solution diverged (EXC) at solver " << domainId() << " " << globalTimeStep << " " << m_RKStep << endl;
17369 }
17370 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
17371 "m_solutionDiverged");
17372
17373 if(m_solutionDiverged) {
17374 writeVtkXmlFiles("QOUT", "GEOM", false, true);
17375 MPI_Barrier(mpiComm(), AT_);
17376 mTerm(1, AT_, "Solution diverged after exchange.");
17377 }
17378 }
17379#endif
17380
17381 // only at leaf-level should be sufficient!
17382 for(MInt i = 0; i < noNeighborDomains(); i++) {
17383 for(MInt j = 0; j < m_noMaxLevelHaloCells[i]; j++) {
17384 const MInt cellId = m_maxLevelHaloCells[i][j];
17385 setConservativeVariables(cellId);
17386 }
17387 }
17388}
17389
17390
17395template <MInt nDim, class SysEqn>
17397 const MInt recDim = (m_orderOfReconstruction == 2) ? (IPOW2(nDim) + 1) : nDim;
17398 const MInt maxNoNghbrs = 150;
17399
17400 MIntScratchSpace nghbrList(maxNoNghbrs, AT_, "nghbrList");
17401 MIntScratchSpace layerId(maxNoNghbrs, AT_, "layerList");
17402
17403 if(c_noChildren(cellId) > 0 || a_hasProperty(cellId, SolverCell::IsNotGradient)
17404 || !a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
17405 cerr << domainId() << " Warning: trying to rebuild stencil of cell " << cellId << " with " << c_noChildren(cellId)
17406 << " children and prop-7=" << a_hasProperty(cellId, SolverCell::IsNotGradient)
17407 << ", prop-13=" << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << ", level=" << a_level(cellId)
17408 << ", inact=" << a_hasProperty(cellId, SolverCell::IsInactive) << ". Skipped." << endl;
17409 a_noReconstructionNeighbors(cellId) = 0;
17410 return;
17411 }
17412
17413 const MInt counter = this->template getAdjacentLeafCells<0, true>(cellId, 1, nghbrList, layerId);
17414
17415 if(counter > maxNoNghbrs) {
17416 mTerm(1, AT_, "too many nghbrs " + to_string(counter));
17417 }
17418 a_noReconstructionNeighbors(cellId) = 0;
17419
17420 if(a_bndryId(cellId) > -1) {
17421 for(MInt srfc = 0; srfc < m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs; srfc++) {
17422 MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcVariables[srfc]->m_ghostCellId;
17423 if(ghostCellId < 0) cerr << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << endl;
17424 if(ghostCellId < 0)
17425 mTerm(1, AT_,
17426 "ghostCellId not set! " + to_string(cellId) + " " + to_string(a_bndryId(cellId)) + " "
17427 + to_string(ghostCellId) + " " + to_string(srfc) + " " + to_string(a_isHalo(cellId)) + " "
17428 + to_string(a_isBndryGhostCell(cellId)));
17429 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) = ghostCellId;
17430 a_noReconstructionNeighbors(cellId)++;
17431 }
17432 }
17433
17434 MBool atInterface = false;
17435 for(MInt k = 0; k < counter; k++) {
17436 MInt nghbrId = nghbrList[k];
17437 if(nghbrId < 0) continue;
17438 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17439 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) = nghbrId;
17440 a_noReconstructionNeighbors(cellId)++;
17441 if(a_noReconstructionNeighbors(cellId) > m_cells.noRecNghbrs()) {
17442 mTerm(1, AT_, "too many rec nghbrs " + to_string(cellId));
17443 }
17444 if(a_level(nghbrId) < a_level(cellId)) {
17445 atInterface = true;
17446 }
17447 }
17448
17449 // use a different stencil at level-jumps for local-time stepping
17450 //(more stable, i.e. larger CFL!)
17451 if(m_localTS && atInterface) {
17452 const MInt counter2 = this->template getAdjacentLeafCells<2, true>(cellId, 1, nghbrList, layerId);
17453 for(MInt k = 0; k < counter2; k++) {
17454 MInt nghbrId = nghbrList[k];
17455 if(nghbrId < 0) {
17456 continue;
17457 }
17458 if(a_hasProperty(nghbrId, SolverCell::IsInvalid)) {
17459 continue;
17460 }
17461 if(a_level(nghbrId) >= a_level(cellId)) {
17462 continue;
17463 }
17464 MBool exist = false;
17465 for(MInt i = 0; i < a_noReconstructionNeighbors(cellId); i++) {
17466 if(a_reconstructionNeighborId(cellId, i) == nghbrId) {
17467 exist = true;
17468 break;
17469 }
17470 }
17471 if(!exist) {
17472 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) = nghbrId;
17473 a_noReconstructionNeighbors(cellId)++;
17474 }
17475 if(a_noReconstructionNeighbors(cellId) > m_cells.noRecNghbrs()) {
17476 mTerm(1, AT_, "too many rec nghbrs " + to_string(cellId) + " " + to_string(counter));
17477 }
17478 }
17479 }
17480
17481
17482 const MInt noNghbrIds = a_noReconstructionNeighbors(cellId);
17483
17484 MFloatScratchSpace tmpA(noNghbrIds, recDim, AT_, "tmpA");
17485 MFloatScratchSpace tmpC(recDim, noNghbrIds, AT_, "tmpC");
17486 MFloatScratchSpace weights(noNghbrIds, AT_, "weights");
17487
17488 ASSERT(!a_hasProperty(cellId, SolverCell::IsNotGradient) && c_isLeafCell(cellId),
17489 "a_hasProperty(cellId, SolverCell::IsNotGradient) "
17490 + std::to_string(a_hasProperty(cellId, SolverCell::IsNotGradient)) + " c_isLeafCell(cellId) "
17491 + std::to_string(c_isLeafCell(cellId)));
17492
17493 const MInt offset = m_cells.noRecNghbrs() * cellId;
17494 computeRecConstSVD(cellId, offset, tmpA, tmpC, weights, recDim, 0, -1);
17495}
17496
17497
17503template <MInt nDim, class SysEqn>
17505 TRACE();
17506 TERMM_IF_COND(m_reConstSVDWeightMode == 3 || m_reConstSVDWeightMode == 4, "Not yet implemented!");
17507
17508 MFloat* RESTRICT slope = (MFloat*)(&(a_slope(0, 0, 0)));
17509 MFloat* RESTRICT vars = (MFloat*)(&(a_pvariable(0, 0)));
17510 const MInt noCells = a_noCells();
17511
17512 std::fill_n(slope, noCells * m_noSlopes, 0.0);
17513
17514#ifdef _OPENMP
17515#pragma omp parallel for
17516#endif
17517 for(MInt cellId = 0; cellId < noCells; cellId++) {
17518 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) {
17519 continue;
17520 }
17521 if(a_isBndryGhostCell(cellId)) {
17522 continue;
17523 }
17524 if(a_hasProperty(cellId, SolverCell::IsInactive)) {
17525 continue;
17526 }
17527
17528 const MInt k = m_noSlopes * cellId;
17529 const MInt offset = nDim * a_reconstructionData(cellId);
17530 for(MInt n = a_noReconstructionNeighbors(cellId); n--;) {
17531 for(MInt v = 0; v < m_noPVars; v++) {
17532 IF_CONSTEXPR(nDim == 3) {
17533#ifdef _OPENMP
17534#pragma omp atomic
17535#endif
17536 slope[k + nDim * v + 2] +=
17537 m_reconstructionConstants[offset + n * nDim + 2]
17538 * (vars[m_noPVars * a_reconstructionNeighborId(cellId, n) + v] - vars[m_noPVars * cellId + v]);
17539 }
17540#ifdef _OPENMP
17541#pragma omp atomic
17542#endif
17543 slope[k + nDim * v + 1] +=
17544 m_reconstructionConstants[offset + n * nDim + 1]
17545 * (vars[m_noPVars * a_reconstructionNeighborId(cellId, n) + v] - vars[m_noPVars * cellId + v]);
17546#ifdef _OPENMP
17547#pragma omp atomic
17548#endif
17549 slope[k + nDim * v] +=
17550 m_reconstructionConstants[offset + n * nDim]
17551 * (vars[m_noPVars * a_reconstructionNeighborId(cellId, n) + v] - vars[m_noPVars * cellId + v]);
17552 }
17553 }
17554 }
17555
17556 if(!m_useCentralDifferencingSlopes) {
17557 return;
17558 }
17559
17560 MBoolScratchSpace atBnd(noCells, AT_, "atBnd");
17561 MBoolScratchSpace nearBnd(noCells, AT_, "nearBnd");
17562 atBnd.fill(false);
17563 nearBnd.fill(false);
17564 array<MFloat, 20> centralDiffConst;
17565 std::vector<std::vector<MInt>> structuredCells(maxLevel() - minLevel() + 1);
17566 std::vector<MInt> nearBoundaryCells;
17567
17568 for(MInt level = minLevel(); level <= maxLevel(); level++) {
17569 structuredCells[level - minLevel()].clear();
17570 }
17571
17572 for(MInt level = minLevel(); level <= maxRefinementLevel(); level++) {
17573 centralDiffConst[level] = 1.0 / (2.0 * c_cellLengthAtLevel(level));
17574 }
17575
17576#ifdef _OPENMP
17577#pragma omp parallel for
17578#endif
17579 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
17580 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
17581 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
17582 continue;
17583 }
17584
17585 atBnd(cellId) = true;
17586 MInt parentId = a_hasProperty(cellId, SolverCell::IsSplitChild) ? c_parentId(getAssociatedInternalCell(cellId))
17587 : c_parentId(cellId);
17588 while(parentId > -1) {
17589 atBnd(parentId) = true;
17590 parentId = c_parentId(parentId);
17591 }
17592 }
17593
17594#ifdef _OPENMP
17595#pragma omp parallel for
17596#endif
17597 for(MInt cellId = 0; cellId < noCells; cellId++) {
17598 if(a_bndryId(cellId) < -1) continue;
17599 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
17600 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17601 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
17602 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17603
17604 if(atBnd(cellId)) {
17605 nearBoundaryCells.push_back(cellId);
17606 nearBnd(cellId) = true;
17607 continue;
17608 }
17609 MBool nearb = false;
17610 for(MInt dir = 0; dir < m_noDirs; dir++) {
17611 if(!a_hasNeighbor(cellId, dir)) {
17612 MInt parentId = c_parentId(cellId);
17613 while(parentId > -1) {
17614 if(a_hasNeighbor(parentId, dir)) {
17615 if(atBnd(c_neighborId(parentId, dir))) {
17616 nearb = true;
17617 }
17618 break;
17619 }
17620 parentId = c_parentId(parentId);
17621 }
17622 } else if(atBnd(c_neighborId(cellId, dir))) {
17623 nearb = true;
17624 break;
17625 }
17626 }
17627 if(nearb) {
17628 nearBoundaryCells.push_back(cellId);
17629 nearBnd(cellId) = true;
17630 continue;
17631 }
17632 }
17633
17634#ifdef _OPENMP
17635#pragma omp parallel for
17636#endif
17637 for(MInt cellId = 0; cellId < noCells; cellId++) {
17638 if(a_bndryId(cellId) != -1) continue;
17639 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
17640 if(nearBnd(cellId)) continue;
17641 if(!c_isLeafCell(cellId)) continue;
17642 if(a_hasProperty(cellId, SolverCell::IsInactive)) {
17643 nearBnd(cellId) = true;
17644 MInt parentId = c_parentId(cellId);
17645 while(parentId > -1) {
17646 nearBnd(parentId) = true;
17647 parentId = c_parentId(parentId);
17648 }
17649 }
17650 }
17651
17652 for(MInt level = minLevel(); level <= maxLevel(); level++) {
17653 structuredCells[level - minLevel()].clear();
17654 }
17655#ifdef _OPENMP
17656#pragma omp parallel for
17657#endif
17658 for(MInt cellId = 0; cellId < noCells; cellId++) {
17659 if(a_bndryId(cellId) < -1) continue;
17660 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
17661 if(nearBnd(cellId)) continue;
17662 if(a_hasProperty(cellId, SolverCell::AtStructuredRegion)) {
17663 structuredCells[c_level(cellId) - minLevel()].push_back(cellId);
17664 }
17665 }
17666
17667#ifdef _OPENMP
17668#pragma omp parallel for
17669#endif
17670 // TODO labels:FVMB this is just debug and should only be applied for debug-compilation
17671 for(MInt cellId = 0; cellId < noCells; cellId++) {
17672 if(a_bndryId(cellId) < -1) continue;
17673 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
17674 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
17675 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
17676 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17677 if(!a_hasProperty(cellId, SolverCell::AtStructuredRegion) && !nearBnd(cellId)
17678 && !(c_parentId(cellId) > -1 && a_hasProperty(c_parentId(cellId), SolverCell::AtStructuredRegion)))
17679 cerr << "strng " << c_globalId(cellId) << " " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " "
17680 << a_hasProperty(cellId, Cell::IsHalo) << " " << c_neighborId(cellId, 0) << " " << c_neighborId(cellId, 1)
17681 << " " << c_neighborId(cellId, 2) << " " << c_neighborId(cellId, 3) << endl;
17682 ASSERT(a_hasProperty(cellId, SolverCell::AtStructuredRegion) || nearBnd(cellId)
17683 || (c_parentId(cellId) > -1 && a_hasProperty(c_parentId(cellId), SolverCell::AtStructuredRegion)),
17684 to_string(c_globalId(cellId)));
17685 }
17686
17687
17688 for(MInt level = minLevel(); level <= maxRefinementLevel(); level++) {
17689 const MFloat fdx = centralDiffConst[level];
17690 for(MUint c = 0; c < structuredCells[level - minLevel()].size(); c++) {
17691 MInt cellId = structuredCells[level - minLevel()][c];
17692 const MInt k = m_noSlopes * cellId;
17693 for(MInt i = 0; i < nDim; i++) {
17694 MInt n0 = c_neighborId(cellId, 2 * i);
17695 MInt n1 = c_neighborId(cellId, 2 * i + 1);
17696 ASSERT(!atBnd(n0) && !atBnd(n1) && !nearBnd(cellId), "");
17697 for(MInt v = 0; v < m_noPVars; v++) {
17698 slope[k + nDim * v + i] = fdx * (a_pvariable(n1, v) - a_pvariable(n0, v));
17699 }
17700 }
17701 if(!c_isLeafCell(cellId)) {
17702 for(MInt child = 0; child < m_noCellNodes; child++) {
17703 const MInt childId = c_childId(cellId, child);
17704 if(childId < 0) continue;
17705 if(a_hasProperty(childId, SolverCell::AtStructuredRegion)) continue;
17706 for(MInt i = 0; i < nDim; i++) {
17707 for(MInt v = 0; v < m_noPVars; v++) {
17708 a_slope(childId, v, i) = a_slope(cellId, v, i);
17709 }
17710 }
17711 }
17712 }
17713 }
17714 }
17715
17716#ifdef _OPENMP
17717#pragma omp parallel for
17718#endif
17719 for(MInt cellId = noCells; cellId > 0; cellId--) {
17720 if(!nearBnd(cellId)) continue;
17721
17722 const MInt k = m_noSlopes * cellId;
17723 const MInt offset = nDim * a_reconstructionData(cellId);
17724 std::fill_n(&slope[k], m_noPVars * nDim, F0);
17725 for(MInt n = a_noReconstructionNeighbors(cellId); n--;) {
17726 for(MInt v = m_noPVars; v--;) {
17727 IF_CONSTEXPR(nDim == 3) {
17728#ifdef _OPENMP
17729#pragma omp atomic
17730#endif
17731 slope[k + nDim * v + 2] +=
17732 m_reconstructionConstants[offset + n * nDim + 2]
17733 * (vars[m_noPVars * a_reconstructionNeighborId(cellId, n) + v] - vars[m_noPVars * cellId + v]);
17734 }
17735#ifdef _OPENMP
17736#pragma omp atomic
17737#endif
17738 slope[k + nDim * v + 1] +=
17739 m_reconstructionConstants[offset + n * nDim + 1]
17740 * (vars[m_noPVars * a_reconstructionNeighborId(cellId, n) + v] - vars[m_noPVars * cellId + v]);
17741#ifdef _OPENMP
17742#pragma omp atomic
17743#endif
17744 slope[k + nDim * v] +=
17745 m_reconstructionConstants[offset + n * nDim]
17746 * (vars[m_noPVars * a_reconstructionNeighborId(cellId, n) + v] - vars[m_noPVars * cellId + v]);
17747 }
17748 }
17749 }
17750
17751#ifndef NDEBUG
17752 static constexpr MBool test1 = false;
17753 static constexpr MBool test2 = false;
17754
17755 // TEST1
17756 if(test1) {
17757 // also central differences when only possible in single direction
17758 for(MInt level = minLevel(); level <= maxRefinementLevel(); level++) {
17759 for(MInt cellId = noCells; cellId--;) {
17760 if(atBnd(cellId)) continue;
17761 if(nearBnd(cellId)) continue;
17762 if(a_bndryId(cellId) < -1) continue;
17763 if(a_hasProperty(cellId, SolverCell::AtStructuredRegion)) continue;
17764 // MInt level = c_level(cellId);
17765 if(level != c_level(cellId)) continue;
17766 const MFloat fdx = centralDiffConst[level];
17767 const MInt k = m_noSlopes * cellId;
17768 for(MInt i = 0; i < nDim; i++) {
17769 MInt n0 = c_neighborId(cellId, 2 * i);
17770 MInt n1 = c_neighborId(cellId, 2 * i + 1);
17771 if(n0 > -1 && n1 > -1) {
17772 if(!atBnd(n0) && !atBnd(n1)) {
17773 ASSERT(!atBnd(n0) && !atBnd(n1) && !nearBnd(cellId), "");
17774 for(MInt v = 0; v < m_noPVars; v++) {
17775 slope[k + nDim * v + i] = fdx * (a_pvariable(n1, v) - a_pvariable(n0, v));
17776 // a_slope( cellId, v, i ) = fdx * ( a_pvariable(n1,v) - a_pvariable(n0,v) );
17777 }
17778
17779 if(!c_isLeafCell(cellId)) {
17780 for(MInt child = 0; child < m_noCellNodes; child++) {
17781 MInt childId = c_childId(cellId, child);
17782 if(childId < 0) continue;
17783 if(a_hasProperty(childId, SolverCell::AtStructuredRegion)) continue;
17784 for(MInt v = 0; v < m_noPVars; v++) {
17785 a_slope(childId, v, i) = a_slope(cellId, v, i);
17786 }
17787 }
17788 }
17789 }
17790 }
17791 }
17792 }
17793 }
17794 }
17795
17796 // TEST2
17797 if(test2) {
17798 // fine to coarse interace use least squares
17799 for(MInt cellId = noCells; cellId--;) {
17800 if(atBnd(cellId)) continue;
17801 if(nearBnd(cellId)) continue;
17802 if(a_bndryId(cellId) < -1) continue;
17803 if(!a_hasProperty(cellId, SolverCell::AtStructuredRegion)) continue;
17804 if(!c_isLeafCell(cellId)) {
17805 for(MInt child = 0; child < m_noCellNodes; child++) {
17806 MInt childId = c_childId(cellId, child);
17807 if(childId < 0) continue;
17808 if(a_hasProperty(childId, SolverCell::AtStructuredRegion)) continue;
17809
17810 const MInt k = m_noSlopes * childId;
17811 // const MInt offset = nDim * m_cells.noRecNghbrs() * childId;
17812 const MInt offset = nDim * a_reconstructionData(childId);
17813 std::fill_n(&slope[k], m_noPVars * nDim, F0);
17814 for(MInt n = a_noReconstructionNeighbors(childId); n--;) {
17815 for(MInt v = m_noPVars; v--;) {
17816 IF_CONSTEXPR(nDim == 3) {
17817 slope[k + nDim * v + 2] +=
17818 m_reconstructionConstants[offset + n * nDim + 2]
17819 * (vars[m_noPVars * a_reconstructionNeighborId(childId, n) + v] - vars[m_noPVars * childId + v]);
17820 }
17821 slope[k + nDim * v + 1] +=
17822 m_reconstructionConstants[offset + n * nDim + 1]
17823 * (vars[m_noPVars * a_reconstructionNeighborId(childId, n) + v] - vars[m_noPVars * childId + v]);
17824 slope[k + nDim * v] +=
17825 m_reconstructionConstants[offset + n * nDim]
17826 * (vars[m_noPVars * a_reconstructionNeighborId(childId, n) + v] - vars[m_noPVars * childId + v]);
17827 }
17828 }
17829 }
17830 }
17831 }
17832 }
17833#endif
17834}
17835
17836
17841template <MInt nDim, class SysEqn>
17843#ifndef NDEBUG
17844 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
17845 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++) {
17846 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
17847 ASSERT(a_associatedBodyIds(cellId, 0) > -1
17848 && a_associatedBodyIds(cellId, 0) < m_noEmbeddedBodies + m_noPeriodicGhostBodies,
17849 "associated body is invalid: " + to_string(0) + "/" + to_string(a_associatedBodyIds(cellId, 0)) + " "
17850 + to_string(c_globalId(cellId)));
17851 }
17852#endif
17853
17854 m_fvBndryCnd->updateGhostCellVariables();
17855}
17856
17857
17862template <MInt nDim, class SysEqn>
17864#ifndef NDEBUG
17865 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
17866 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++) {
17867 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
17868 ASSERT(a_associatedBodyIds(cellId, 0) > -1
17869 && a_associatedBodyIds(cellId, 0) < m_noEmbeddedBodies + m_noPeriodicGhostBodies,
17870 "associated body is invalid: " + to_string(0) + "/" + to_string(a_associatedBodyIds(cellId, 0)));
17871 }
17872#endif
17873
17874 m_fvBndryCnd->applyNeumannBoundaryCondition();
17875}
17876
17877
17883template <MInt nDim, class SysEqn>
17885 TRACE();
17886
17887 if(!m_constructGField) {
17888 // levelset forced motion
17889
17890 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
17891 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++) {
17892 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
17893
17894 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
17895 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
17896 const MInt bodyId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0];
17897 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
17898 for(MInt i = 0; i < nDim; i++) {
17899 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] =
17900 m_bodyVelocity[bodyId * nDim + i];
17901 }
17902
17903 if(m_LsRotate) {
17904 MFloat vrad[3] = {F0, F0, F0};
17905 MFloat dx[3] = {F0, F0, F0};
17906 MFloat omega[3] = {F0, F0, F0};
17907 for(MInt i = 0; i < nDim; i++) {
17908 dx[i] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i]
17909 - m_bodyCenter[bodyId * nDim + i];
17910 }
17911
17912 for(MInt i = 0; i < 3; i++) {
17913 omega[i] = m_bodyAngularVelocity[bodyId * 3 + i];
17914 }
17915
17916 vrad[0] = omega[1] * dx[2] - omega[2] * dx[1];
17917 vrad[1] = omega[2] * dx[0] - omega[0] * dx[2];
17918
17919 IF_CONSTEXPR(nDim == 3) { vrad[2] = omega[0] * dx[1] - omega[1] * dx[0]; }
17920 else {
17921 mTerm(1, AT_, "TODO");
17922 }
17923
17924 for(MInt i = 0; i < nDim; i++) {
17925 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] += vrad[i];
17926 }
17927 }
17928
17929 if(m_closeGaps && m_gapInitMethod == 0 && a_isGapCell(cellId)) {
17930 const MInt gapCellId = m_gapCellId[cellId];
17931 ASSERT(gapCellId > -1, "");
17932 for(MInt i = 0; i < nDim; i++) {
17933 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] =
17934 m_gapCells[gapCellId].surfaceVelocity[i];
17935 }
17936 }
17937 }
17938 }
17939 }
17940 } else {
17941 // translation and rotational body based on the fv-solver!
17942 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
17943 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++) {
17944 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
17945 const MInt bodyId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0];
17946 ASSERT(bodyId > -1 && bodyId < m_noEmbeddedBodies + m_noPeriodicGhostBodies, "");
17947 for(MInt i = 0; i < nDim; i++) {
17948 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] =
17949 m_bodyVelocity[bodyId * nDim + i];
17950 }
17951 MFloat dx[3] = {F0, F0, F0};
17952 MFloat omega[3] = {F0, F0, F0};
17953 MFloat vrad[3] = {F0, F0, F0};
17954 for(MInt i = 0; i < nDim; i++) {
17955 dx[i] =
17956 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[i] - m_bodyCenter[bodyId * nDim + i];
17957 }
17958 for(MInt i = 0; i < 3; i++) {
17959 omega[i] = m_bodyAngularVelocity[bodyId * 3 + i];
17960 }
17961 vrad[0] = omega[1] * dx[2] - omega[2] * dx[1];
17962 vrad[1] = omega[2] * dx[0] - omega[0] * dx[2];
17963 IF_CONSTEXPR(nDim == 3) { vrad[2] = omega[0] * dx[1] - omega[1] * dx[0]; }
17964 for(MInt i = 0; i < nDim; i++) {
17965 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] += vrad[i];
17966 }
17967
17968 if(m_euler) {
17969 MFloat vel[3];
17970 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
17971 for(MInt i = 0; i < nDim; i++) {
17972 vel[i] = a_pvariable(cellId, PV->VV[i]);
17973 for(MInt j = 0; j < nDim; j++) {
17974 vel[i] += m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]
17975 * (m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]]
17976 - a_pvariable(cellId, PV->VV[j]))
17977 * m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[j];
17978 }
17979 }
17980 for(MInt i = 0; i < nDim; i++) {
17981 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = vel[i];
17982 }
17983 }
17984 }
17985 }
17986 }
17987}
17988
17989
17994template <MInt nDim, class SysEqn>
17996 ASSERT(!m_deleteNeighbour, "");
17997
17998 std::function<MBool(const MInt, const MInt)> alwaysTrue = [&](const MInt, const MInt) { return true; };
17999
18000 for(MUint it = 0; it < m_gapCells.size(); it++) {
18001 const MInt cellId = m_gapCells[it].cellId;
18002 const MInt bndryId = a_bndryId(cellId);
18003 if(bndryId < 0) continue;
18004
18005 MInt gridCellId = cellId;
18006 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
18007 gridCellId = getAssociatedInternalCell(cellId);
18008 }
18009 const MInt regionId = m_gapCells[it].region;
18010 if(m_gapInitMethod > 0 && regionId != m_noGapRegions) continue;
18011
18012 const MInt body1 = a_associatedBodyIds(gridCellId, 0);
18013
18014 for(MInt i = 0; i < nDim; i++) {
18015 m_gapCells[it].surfaceVelocity[i] = m_bodyVelocity[body1 * nDim + i];
18016 }
18017
18018 const MInt body2 = m_gapCells[it].bodyIds[1];
18019 ASSERT(m_gapCells[it].bodyIds[0] == body1, "");
18020 if(body2 == -1) continue;
18021
18022 MFloat vel1 = F0;
18023 MFloat vel2 = F0;
18024 MInt interpolationCells[8] = {0, 0, 0, 0, 0, 0, 0, 0};
18025 this->setUpInterpolationStencil(gridCellId, interpolationCells, m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates,
18026 alwaysTrue, false);
18027
18028 const MFloat dist1 = interpolateLevelSet(interpolationCells, m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates,
18029 m_bodyToSetTable[body1]);
18030
18031 const MFloat dist2 = interpolateLevelSet(interpolationCells, m_bndryCells->a[bndryId].m_srfcs[0]->m_coordinates,
18032 m_bodyToSetTable[body2]);
18033
18034 for(MInt i = 0; i < nDim; i++) {
18035 vel1 += m_bodyVelocity[body1 * nDim + i] * m_bodyVelocity[body1 * nDim + i];
18036 vel2 += m_bodyVelocity[body2 * nDim + i] * m_bodyVelocity[body2 * nDim + i];
18037 }
18038
18039 MInt fixedBody = body1;
18040 MInt movingBody = body2;
18041 MFloat distFixed = dist1;
18042
18043 // use the more stationary velocity!
18044 if(m_gapInitMethod > 0 && vel1 < vel2) {
18045 continue;
18046 } else if(m_gapInitMethod > 0) {
18047 for(MInt i = 0; i < nDim; i++) {
18048 m_gapCells[it].surfaceVelocity[i] = m_bodyVelocity[body2 * nDim + i];
18049 }
18050 continue;
18051 }
18052
18053 if(vel1 > vel2) {
18054 fixedBody = body2;
18055 movingBody = body1;
18056 distFixed = dist2;
18057 }
18058
18059 MFloat F = distFixed / (2.0 * c_cellLengthAtLevel(m_lsCutCellBaseLevel));
18060 if(F < F0) F = F0;
18061 if(F > 1.0) F = 1.0;
18062
18063 // velocity interpolation in the cells close to both boundaries
18064 for(MInt i = 0; i < nDim; i++) {
18065 m_gapCells[it].surfaceVelocity[i] =
18066 (F * m_bodyVelocity[movingBody * nDim + i] + (1 - F) * m_bodyVelocity[fixedBody * nDim + i]);
18067 }
18068 }
18069}
18070
18071
18077template <MInt nDim, class SysEqn>
18079 MInt referenceSet) {
18080 TRACE();
18081
18082 std::function<MFloat(const MInt, const MInt)> scalarField = [&](const MInt cellId, const MInt set) {
18083 return static_cast<MFloat>(a_levelSetValuesMb(cellId, set));
18084 };
18085
18086 std::function<MFloat(const MInt, const MInt)> coordinate = [&](const MInt cellId, const MInt id) {
18087 return static_cast<MFloat>(c_coordinate(cellId, id));
18088 };
18089
18090 return this->template interpolateFieldData<true>(&interpolationCells[0], &point[0], referenceSet, scalarField,
18091 coordinate);
18092}
18093
18094
18099template <MInt nDim, class SysEqn>
18101 TRACE();
18102
18103 applyDirichletCondition(); // apply Dirichlet boundary conditions
18104 applyNeumannCondition(); // apply Neumann boundary conditions
18105
18106#if defined _MB_DEBUG_ || !defined NDEBUG
18107 m_solutionDiverged = false;
18108 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
18109 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++) {
18110 const MInt cellId = m_fvBndryCnd->m_bndryCell[bndryId].m_cellId;
18111 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
18112 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
18113 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
18114 for(MInt v = 0; v < m_noPVars; v++) {
18115 const MFloat val = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v];
18116 const MFloat val2 = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_normalDeriv[v];
18117 if(std::isnan(val) || std::isinf(val)) {
18118 cerr << setprecision(16) << domainId() << ": bnd surf var div after BC: " << globalTimeStep << "/" << m_RKStep
18119 << " " << cellId << " " << c_globalId(cellId) << " "
18120 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume / grid().gridCellVolume(a_level(cellId)) << " "
18121 << c_noChildren(cellId) << " " << a_isHalo(cellId) << " "
18122 << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " "
18123 << m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size() << " "
18124 << a_hasProperty(cellId, SolverCell::IsInactive) << ", " << srfc << " " << getPrimitiveVarName(v) << " "
18125 << val << " " << a_pvariable(cellId, v) << endl;
18126 m_solutionDiverged = true;
18127 }
18128 if(std::isnan(val2) || std::isinf(val2)) {
18129 cerr << domainId() << ": bnd surf grad div after BC: " << globalTimeStep << "/" << m_RKStep << " " << cellId
18130 << " " << c_globalId(cellId) << " " << m_volumeFraction[bndryId] << " " << c_noChildren(cellId) << " "
18131 << a_isHalo(cellId) << " " << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " "
18132 << m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size() << " "
18133 << a_hasProperty(cellId, SolverCell::IsInactive) << " / " << srfc << " " << getPrimitiveVarName(v) << " "
18134 << val2 << endl;
18135 m_solutionDiverged = true;
18136 }
18137 }
18138 if(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] < F0
18139 || m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO] < F0) {
18140 MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
18141 cerr << domainId() << ": bnd surf var negative after BC: " << globalTimeStep << "/" << m_RKStep << " " << cellId
18142 << " " << c_globalId(cellId) << " " << m_volumeFraction[bndryId] << " " << a_level(cellId) << " "
18143 << c_noChildren(cellId) << " " << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " "
18144 << a_isHalo(cellId) << " " << a_hasProperty(cellId, SolverCell::IsNotGradient) << " "
18145 << m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size() << " "
18146 << a_hasProperty(cellId, SolverCell::IsInactive) << " / " << srfc << " " << a_pvariable(cellId, PV->P)
18147 << " " << a_pvariable(cellId, PV->RHO) << " / "
18148 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P] << " "
18149 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO] << " / "
18150 << a_pvariable(ghostCellId, PV->P) << " " << a_pvariable(ghostCellId, PV->RHO) << " v "
18151 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[0]] << " "
18152 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[1]] << " "
18153 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[2]] << " "
18154 << c_coordinate(cellId, 0) << " " << c_coordinate(cellId, 1) << " " << c_coordinate(cellId, nDim - 1)
18155 << endl;
18156 m_solutionDiverged = true;
18157 }
18158 }
18159 }
18160 if(m_solutionDiverged) {
18161 cerr << "Solution diverged (BC) at solver " << domainId() << " " << globalTimeStep << " " << m_RKStep << endl;
18162 }
18163 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
18164 "m_solutionDiverged");
18165
18166 if(m_solutionDiverged) {
18167 writeVtkXmlFiles("QOUT", "GEOM", false, true);
18168 MPI_Barrier(mpiComm(), AT_);
18169 mTerm(1, AT_, "Solution diverged after BC handling.");
18170 }
18171#endif
18172}
18173
18174
18179template <MInt nDim, class SysEqn>
18181 m_fvBndryCnd->updateGhostCellSlopesInviscid();
18182}
18183
18184
18189template <MInt nDim, class SysEqn>
18191 if(m_euler) return;
18192 m_fvBndryCnd->updateGhostCellSlopesViscous();
18193}
18194
18195
18200template <MInt nDim, class SysEqn>
18202 TRACE();
18203
18204 m_fvBndryCnd->correctBoundarySurfaceVariables();
18205}
18206
18207
18208template <MInt nDim, class SysEqn>
18210 return (!(x < a) && !(x > b));
18211}
18212
18213
18218template <MInt nDim, class SysEqn>
18220 TRACE();
18221
18222 const MInt noSrfcs = a_noSurfaces();
18223 MInt nghbrCells[2];
18224 MFloat eps = 1e-10;
18225 MFloat totalDistance, distance;
18226 MFloat factor0, factor1;
18227 MFloat coords[2][nDim];
18228 MInt srfcId;
18229
18230 // compute the factors 0 and 1 for all surfaces
18231 // for( srfcId = m_initialSurfacesOffset; srfcId < noSrfcs; srfcId++ ) {
18232 for(srfcId = m_bndrySurfacesOffset; srfcId < noSrfcs; srfcId++) {
18233 nghbrCells[0] = a_surfaceNghbrCellId(srfcId, 0);
18234 nghbrCells[1] = a_surfaceNghbrCellId(srfcId, 1);
18235 distance = F0;
18236 totalDistance = F0;
18237
18238 for(MInt i = 0; i < nDim; i++) {
18239 coords[0][i] = a_coordinate(nghbrCells[0], i);
18240 coords[1][i] = a_coordinate(nghbrCells[1], i);
18241 }
18242
18243 for(MInt i = 0; i < nDim; i++) {
18244 distance += POW2(a_surfaceCoordinate(srfcId, i) - coords[0][i]);
18245 totalDistance += POW2(a_surfaceCoordinate(srfcId, i) - coords[1][i]);
18246 }
18247 distance = sqrt(distance);
18248 totalDistance = sqrt(totalDistance) + distance;
18249 factor1 = distance / mMax(eps, totalDistance);
18250 factor0 = F1 - factor1;
18251 a_surfaceFactor(srfcId, 0) = factor0;
18252 a_surfaceFactor(srfcId, 1) = factor1;
18253 }
18254
18255
18256 for(MInt bs = 0; bs < m_fvBndryCnd->m_noBoundarySurfaces; bs++) {
18257 srfcId = m_fvBndryCnd->m_boundarySurfaces[bs];
18258 if(a_surfaceBndryCndId(srfcId) != m_movingBndryCndId) continue;
18259
18260 a_surfaceFactor(srfcId, 0) = F1B2;
18261 a_surfaceFactor(srfcId, 1) = F1B2;
18262 }
18263}
18264
18265
18272template <MInt nDim, class SysEqn>
18274 TRACE();
18275
18276 const MInt DOFStencil[12] = {1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
18277
18278 const MInt signStencil[3][12] = {{-1, 1, 0, 0, -1, 1, 0, 0, -1, 1, -1, 1},
18279 {0, 0, -1, 1, 0, 0, -1, 1, -1, -1, 1, 1},
18280 {-1, -1, -1, -1, 1, 1, 1, 1, 0, 0, 0, 0}};
18281
18282 const MBool redirect = true;
18283 if(redirect && !m_constructGField) {
18284 vector<MInt> candidatesOrder;
18285
18286 m_geometryIntersection->computeCutPoints(m_cutCandidates, &m_bndryCandidateIds[0], candidatesOrder);
18287
18288 // rescale cutPoints to cell-size:
18289 if(m_geometryIntersection->m_scaledCutCell) {
18290 for(MInt cnd = 0; cnd < (signed)m_cutCandidates.size(); cnd++) {
18291 const MInt cellId = m_cutCandidates[cnd].cellId;
18292 const MFloat cellLength = c_cellLengthAtLevel(a_cutCellLevel(cellId));
18293 const MFloat cellHalfLength = F1B2 * cellLength;
18294
18295
18296 for(MInt cpId = 0; cpId < m_cutCandidates[cnd].noCutPoints; cpId++) {
18297 const MInt cutEdge = m_cutCandidates[cnd].cutEdges[cpId];
18298
18299 for(MInt i = 0; i < nDim; i++) {
18300 MFloat cutCoordinate = m_cutCandidates[cnd].cutPoints[cpId][i];
18301 const MInt sign = signStencil[i][cutEdge];
18302
18303 if(sign == 0) {
18304 cutCoordinate = a_coordinate(cellId, i) + cellHalfLength * m_cutCandidates[cnd].cutPoints[cpId][i];
18305 } else {
18306 cutCoordinate = a_coordinate(cellId, i) + signStencil[i][cutEdge] * cellHalfLength;
18307 }
18308 m_cutCandidates[cnd].cutPoints[cpId][i] = cutCoordinate;
18309 }
18310 }
18311 }
18312 }
18313
18314 // generate BndryCells based on the cutCandidates!
18315 // TODO labels:FVMB this should then be moved to the end of createCutFaceMb_MGC()
18316 // and instead the cutCells should be set!
18317
18318 // NOTE: bndryCell ordering appears to change the result for gapClosure!
18319 for(MInt i = 0; i < (signed)candidatesOrder.size(); i++) {
18320 const MInt cndt = candidatesOrder[i];
18321 const MInt cellId = m_cutCandidates[cndt].cellId;
18322 ASSERT(m_cutCandidates[cndt].noCutPoints > 0, "");
18323 MInt bndryId = -1;
18324 if(!a_isBndryCell(cellId)) {
18325 ASSERT(a_bndryId(cellId) == -1, to_string(a_bndryId(cellId)));
18326 bndryId = createBndryCellMb(cellId);
18327 } else {
18328 bndryId = a_bndryId(cellId);
18329 ASSERT(bndryId > -1, "");
18330 }
18331 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints = m_cutCandidates[cndt].noCutPoints;
18332
18333 for(MInt noCPs = 0; noCPs < m_cutCandidates[cndt].noCutPoints; noCPs++) {
18334 for(MInt dim = 0; dim < nDim; dim++) {
18335 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[noCPs][dim] =
18336 m_cutCandidates[cndt].cutPoints[noCPs][dim];
18337 }
18338 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[noCPs] = m_cutCandidates[cndt].cutBodyIds[noCPs];
18339 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[noCPs] = m_cutCandidates[cndt].cutEdges[noCPs];
18340 }
18341 }
18342
18343 return;
18344 }
18345
18346 const MInt edgesPerDim = IPOW2(nDim - 1);
18347
18348 const MInt faceStencil[2][12] = {{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 0, 1}, {4, 4, 4, 4, 5, 5, 5, 5, 2, 2, 3, 3}};
18349
18350 // edege -> opposing edge
18351 // 1: oppsing edge on the same higher face count
18352 // 2: opposing edge on the same lower face count
18353 // 3: oppsong edge accros the cube
18354 // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
18355 const MInt reverseEdgeStencil[3][12] = {{1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10},
18356 {4, 5, 6, 7, 0, 1, 2, 3, 10, 11, 8, 9},
18357 {5, 4, 7, 6, 1, 0, 3, 2, 11, 10, 9, 8}};
18358
18359
18360 // edeg -> corner: returns the two corners for any edge
18361 // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11
18362 const MInt nodeStencil[2][12] = {{0, 1, 0, 2, 4, 5, 4, 6, 0, 1, 2, 3}, {2, 3, 1, 3, 6, 7, 5, 7, 4, 5, 6, 7}};
18363
18364
18365 const MBool multiCutCell = false;
18366 const MFloat eps = multiCutCell ? 10 * m_eps : m_eps;
18367 MInt errorFlag = 0;
18368
18369
18370 ASSERT(m_noBndryCandidates == (signed)m_bndryCandidates.size(), "");
18371 ScratchSpace<MBool> edgeChecked(m_noBndryCandidates * m_noEdges, AT_, "edgeChecked");
18372 edgeChecked.fill(false);
18373
18374 for(MInt i = 0; i < m_noBndryCandidates; i++) {
18375 for(MInt e = 0; e < m_noEdges; e++) {
18376 edgeChecked.p[i * m_noEdges + e] = false;
18377 }
18378 }
18379 MIntScratchSpace noCutPointsOnEdge(m_fvBndryCnd->m_maxNoBndryCells, m_noEdges, AT_, "noCutPointsOnEdge");
18380 noCutPointsOnEdge.fill(0);
18381
18382 for(MInt i = 0; i < m_fvBndryCnd->m_maxNoBndryCells; i++)
18383 for(MInt e = 0; e < m_noEdges; e++)
18384 noCutPointsOnEdge(i, e) = 0;
18385
18386
18387 // loop over candidates, determine cutpoints, store bndryCell properties
18388 for(MInt cndt = 0; cndt < m_noBndryCandidates; cndt++) {
18389 MInt cellId = m_bndryCandidates[cndt];
18390
18391 const MFloat cellLength = c_cellLengthAtLevel(a_cutCellLevel(cellId));
18392 const MFloat cellHalfLength = F1B2 * cellLength;
18393
18394 MInt face[2];
18395 for(MInt edge = 0; edge < m_noEdges; edge++) {
18396 if(edgeChecked.p[cndt * m_noEdges + edge]) continue;
18397
18398 // first do some data structure related stuff
18399 face[0] = faceStencil[0][edge]; // in 2D: face == edge
18400 IF_CONSTEXPR(nDim == 3) {
18401 face[1] = faceStencil[1][edge]; // in 3D: each edge is connected to two faces
18402 }
18403 MInt edgeDOF = DOFStencil[edge]; // edge's degree of freedom
18404
18405 MInt directNeighbourIds[4]{-1, -1, -1, -1}; // direct neighbours of each edge -> requires that neighboring cells
18406 // are on same level!
18407 directNeighbourIds[0] = cellId;
18408 directNeighbourIds[1] = -1;
18409 if(a_hasNeighbor(cellId, face[0]) > 0) directNeighbourIds[1] = c_neighborId(cellId, face[0]);
18410
18411 MInt reverseEdge[4] = {0, 0, 0, 0};
18412 reverseEdge[0] = edge;
18413 reverseEdge[1] = reverseEdgeStencil[0][edge];
18414 IF_CONSTEXPR(nDim == 3) {
18415 directNeighbourIds[2] = -1;
18416 if(a_hasNeighbor(cellId, face[1]) > 0) {
18417 directNeighbourIds[2] = c_neighborId(cellId, face[1]);
18418 }
18419 directNeighbourIds[3] = -1;
18420 if(a_hasNeighbor(cellId, face[0]) > 0) {
18421 if(a_hasNeighbor(c_neighborId(cellId, face[0]), face[1]) > 0) {
18422 directNeighbourIds[3] = c_neighborId(c_neighborId(cellId, face[0]), face[1]);
18423 }
18424 }
18425 if(directNeighbourIds[3] < 0) {
18426 if(a_hasNeighbor(cellId, face[1]) > 0) {
18427 if(a_hasNeighbor(c_neighborId(cellId, face[1]), face[0]) > 0) {
18428 directNeighbourIds[3] = c_neighborId(c_neighborId(cellId, face[1]), face[0]);
18429 }
18430 }
18431 }
18432 reverseEdge[2] = reverseEdgeStencil[1][edge];
18433 reverseEdge[3] = reverseEdgeStencil[2][edge];
18434 }
18435
18436 // here, the real cut point computation begins
18437 MInt startSet = 0;
18438 MInt endSet = 1;
18439 MBool isGapCell = false;
18440 if(m_levelSet && m_closeGaps) {
18441 isGapCell = (a_hasProperty(cellId, SolverCell::IsGapCell));
18442 }
18443 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell)) {
18444 startSet = 1;
18445 endSet = m_noLevelSetsUsedForMb;
18446 } else if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (isGapCell)) {
18447 startSet = 0;
18448 endSet = 1;
18449 }
18450
18451
18452 for(MInt set = startSet; set < endSet; set++) {
18453 MFloat phi[2]; // signed-distance value on both vertices defining an edge
18454 phi[0] = m_candidateNodeValues[IDX_LSSETNODES(cndt, nodeStencil[0][edge], set)];
18455 phi[1] = m_candidateNodeValues[IDX_LSSETNODES(cndt, nodeStencil[1][edge], set)];
18456 if(!m_candidateNodeSet[cndt * m_noCellNodes + nodeStencil[0][edge]])
18457 cerr << domainId() << ": warning node value 0 not set at " << globalTimeStep << ", " << cellId << " " << cndt
18458 << " " << edge << " " << nodeStencil[0][edge] << " " << set << " " << a_isHalo(cellId) << endl;
18459 if(!m_candidateNodeSet[cndt * m_noCellNodes + nodeStencil[1][edge]])
18460 cerr << domainId() << ": warning node value 1 not set at " << globalTimeStep << ", " << cellId << " " << cndt
18461 << " " << edge << " " << nodeStencil[1][edge] << " " << set << " " << a_isHalo(cellId) << endl;
18462
18463 // added by Claudia to prevent zero-volume cells
18464 if(fabs(phi[0]) < eps) {
18465 if(phi[0] < F0)
18466 phi[0] = -eps;
18467 else
18468 phi[0] = eps;
18469 }
18470 if(fabs(phi[1]) < eps) {
18471 if(phi[1] < F0)
18472 phi[1] = -eps;
18473 else
18474 phi[1] = eps;
18475 }
18476
18477 // limit the distance of a cutPoint to any corner:
18478 // together with the above, this ensure that the CP
18479 // is always 2 eps appart from the corner!
18480 // necessary for multiCutCell but not included in the trunk!
18481 if(multiCutCell) {
18482 if(approx(fabs(phi[0]), cellHalfLength, eps)) {
18483 if(phi[0] > F0)
18484 phi[0] = cellHalfLength - eps;
18485 else
18486 phi[0] = -cellHalfLength + eps;
18487 }
18488 if(approx(fabs(phi[1]), cellHalfLength, eps)) {
18489 if(phi[1] > F0)
18490 phi[1] = cellHalfLength - eps;
18491 else
18492 phi[1] = -cellHalfLength + eps;
18493 }
18494 }
18495
18496 // found a cutpoint if sign differs
18497 if(phi[0] * phi[1] < 0) {
18498 MFloat cutpoint[nDim];
18499 // determine cutpoint coordinates
18500 MFloat deltaCutpoint = cellHalfLength * (phi[0] + phi[1]) / (phi[0] - phi[1]);
18501 ASSERT((phi[0] + phi[1]) / (phi[0] - phi[1]) < 1 && (phi[0] + phi[1]) / (phi[0] - phi[1]) > -1, "");
18502 for(MInt dim = 0; dim < nDim; dim++) {
18503 if(dim == edgeDOF) continue;
18504 cutpoint[dim] = a_coordinate(cellId, dim) + signStencil[dim][edge] * cellHalfLength;
18505 }
18506 cutpoint[edgeDOF] = a_coordinate(cellId, edgeDOF) + deltaCutpoint;
18507
18508 // store this cutpoint at all direct neighbours
18509 for(MInt nb = 0; nb < edgesPerDim; nb++) {
18510 MInt nbCell = directNeighbourIds[nb];
18511 if(nbCell < 0) continue;
18512 if(m_bndryCandidateIds[nbCell] < 0) {
18513 continue;
18514 }
18515 // may occur in multi-domain computations
18516 if(edgeChecked.p[m_bndryCandidateIds[nbCell] * m_noEdges + reverseEdge[nb]]) {
18517 cerr << "Strange behaviour! " << endl;
18518 continue;
18519 }
18520 // if neighbour isn't already moving boundary cell create a new one
18521 MInt nbBndryCell = -1;
18522 if(!a_isBndryCell(nbCell)) {
18523 if(a_bndryId(nbCell) != -1) {
18524 cerr << domainId() << "Missing boundary cell: " << cellId << " " << nbCell << " " << a_level(cellId)
18525 << " " << a_level(nbCell) << " " << c_neighborId(cellId, face[0]) << " " << face[0] << " "
18526 << a_isHalo(cellId) << " " << a_isHalo(nbCell) << endl;
18527 }
18528 ASSERT(a_bndryId(nbCell) == -1, to_string(a_bndryId(nbCell)));
18529 nbBndryCell = createBndryCellMb(nbCell);
18530 } else {
18531 nbBndryCell = a_bndryId(nbCell);
18532 if(nbBndryCell < 0) {
18533 errorFlag = 1;
18534 cerr << "Critical error in at " << globalTimeStep << ". Quit.";
18535 }
18536 }
18537
18538 // store relevant information
18539 MInt noCPs = m_fvBndryCnd->m_bndryCells->a[nbBndryCell].m_srfcs[0]->m_noCutPoints;
18540 if(noCPs == 2 * m_noEdges) {
18541 mTerm(1, AT_, "Error: Too many cut points, can't store more... Please check!");
18542 }
18543 if(noCutPointsOnEdge(nbBndryCell, reverseEdge[nb]) == 2) {
18544 mTerm(1, AT_, "Error: Already two cut points on edge, can't store more... Please check!");
18545 }
18546
18547 ASSERT(a_associatedBodyIds(cellId, set) > -1
18548 && a_associatedBodyIds(cellId, set) < m_noEmbeddedBodies + m_noPeriodicGhostBodies,
18549 "");
18550
18551 if(set >= m_startSet && a_associatedBodyIds(cellId, set) != a_associatedBodyIds(nbCell, set)) {
18552 cerr << domainId() << ": warning associated body mismatch! " << globalTimeStep << " " << set << " "
18553 << isGapCell << ", " << c_globalId(cellId) << " " << c_globalId(nbCell) << ", "
18554 << a_isPeriodic(cellId) << " " << a_isPeriodic(nbCell) << "/ " << a_associatedBodyIds(cellId, set)
18555 << " " << a_associatedBodyIds(nbCell, set) << ", " << a_associatedBodyIds(cellId, 0) << " "
18556 << a_associatedBodyIds(nbCell, 0) << "/ " << a_levelSetValuesMb(cellId, set) << " "
18557 << a_levelSetValuesMb(nbCell, set) << ", " << a_levelSetValuesMb(cellId, 0) << " "
18558 << a_levelSetValuesMb(nbCell, 0) << "/ " << a_hasProperty(cellId, Cell::IsHalo) << " "
18559 << a_hasProperty(nbCell, Cell::IsHalo) << ", " << a_hasProperty(cellId, SolverCell::IsGapCell) << " "
18560 << a_hasProperty(nbCell, SolverCell::IsGapCell) << endl;
18561 directNeighbourIds[nb] = -1;
18562 continue;
18563 }
18564
18565 for(MInt dim = 0; dim < nDim; dim++)
18566 m_fvBndryCnd->m_bndryCells->a[nbBndryCell].m_srfcs[0]->m_cutCoordinates[noCPs][dim] = cutpoint[dim];
18567
18568 m_fvBndryCnd->m_bndryCells->a[nbBndryCell].m_srfcs[0]->m_bodyId[noCPs] = a_associatedBodyIds(nbCell, set);
18569 m_fvBndryCnd->m_bndryCells->a[nbBndryCell].m_srfcs[0]->m_cutEdge[noCPs] = reverseEdge[nb];
18570 m_fvBndryCnd->m_bndryCells->a[nbBndryCell].m_srfcs[0]->m_noCutPoints++;
18571 noCutPointsOnEdge(nbBndryCell, reverseEdge[nb])++;
18572 } // for nb
18573 } // phi1*phi2<0
18574 } // for sets
18575
18576 // flag direct neighbours so that this edge is only checked once
18577 for(MInt nb = 0; nb < edgesPerDim; nb++) {
18578 if(directNeighbourIds[nb] < 0) continue;
18579 MInt nbCndt = m_bndryCandidateIds[directNeighbourIds[nb]];
18580 if(nbCndt < 0) continue;
18581 edgeChecked.p[nbCndt * m_noEdges + reverseEdge[nb]] = true;
18582 }
18583 } // for edge
18584 } // for cndt
18585
18586 /*
18587 // // debug: plot cut points:
18588 // const char* fileName = "AllCutPoints_";
18589 // stringstream fileName2;
18590 // fileName2 << fileName << domainId() << ".vtk";
18591 // ofstream ofl;
18592 // ofl.open((fileName2.str()).c_str(), ofstream::trunc );
18593 //
18594 // MInt noCutPoints = 0;
18595 // MInt noCells = m_bndryCells->size();
18596 //
18597 //
18598 //
18599 // // count the total number of cut points
18600 // for(MInt bndryId = 0; bndryId < noCells; bndryId++){
18601 // noCutPoints += m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints;
18602 // }
18603 //
18604 // if(ofl){
18605 //
18606 // ofl.setf(ios::fixed);
18607 // ofl.precision(7);
18608 //
18609 // ofl << "# vtk DataFile Version 3.0" << endl
18610 // << "MAIAD intersectionPoints file" << endl
18611 // << "ASCII" << endl
18612 // << "DATASET POLYDATA" << endl
18613 // << "POINTS " << noCutPoints << " float" << endl;
18614 //
18615 // // write each cut point in the data file
18616 // for(MInt bndryId = 0; bndryId < noCells; bndryId++){
18617 // if(m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints > 0){
18618 // for(MInt n = 0; n < m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints; n++){
18619 // for(MInt i = 0; i < nDim; i++){
18620 // ofl << m_bndryCells->a[ bndryId ].m_srfcs[0]->m_cutCoordinates[ n ][ i ] << " ";
18621 // }
18622 // IF_CONSTEXPR(nDim == 2)
18623 // ofl << F0 << " ";
18624 // ofl << endl;
18625 // }
18626 // }
18627 // }
18628 //
18629 // ofl << "VERTICES " << noCutPoints << " " << noCutPoints * 2 << endl;
18630 // for(MInt i = 0; i < noCutPoints; i++){
18631 // ofl << "1 " << i << endl;
18632 // }
18633 //
18634 // ofl << "POINT_DATA " << noCutPoints << endl;
18635 // ofl << "SCALARS bodyId int" << endl;
18636 // ofl << "LOOKUP_TABLE default" << endl;
18637 // for(MInt bndryId = 0; bndryId < noCells; bndryId++){
18638 // if(m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints > 0){
18639 // for(MInt n = 0; n < m_bndryCells->a[ bndryId ].m_srfcs[0]->m_noCutPoints; n++){
18640 // ofl << m_bndryCells->a[ bndryId ].m_srfcs[0]->m_bodyId[ n ] << " ";
18641 // }
18642 // }
18643 // }
18644 // ofl << endl;
18645 // }
18646 //
18647 // ofl.close();
18648 */
18649
18650#ifdef _MB_DEBUG_
18651 MPI_Allreduce(MPI_IN_PLACE, &errorFlag, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "errorFlag");
18652#endif
18653 if(errorFlag) {
18654 writeVtkDebug("error" + getIdentifier(false, "_", "_"));
18655 mTerm(1, AT_, "Critical error in computeCutPointsMb_MGC! Quit.");
18656 }
18657}
18658
18659
18665template <MInt nDim, class SysEqn>
18667 TRACE();
18668
18669 MFloat* RESTRICT RHS = (MFloat*)(&(a_rightHandSide(0, 0)));
18670 fill(RHS, RHS + (a_noCells() * m_noFVars), F0);
18671}
18672
18673
18676template <MInt nDim, class SysEqn>
18678 TRACE();
18679
18680#ifdef VISCOUS_FLUX_FREEZING
18681 MFloat* RESTRICT RHS = (MFloat*)(&(a_rightHandSide(0, 0)));
18682 MFloat* RESTRICT RHSV = (MFloat*)(&(m_rhsViscous[0][0]));
18683 MFloat* RESTRICT flux = (MFloat*)(&(a_surfaceFlux(0, 0)));
18684 const MInt xdim = m_noSurfaces;
18685 const MInt ydim = m_noFVars;
18686 const MInt size0 = m_noSurfaces * m_noFVars * sizeof(MFloat);
18687 const MInt size1 = a_noCells() * m_noFVars * sizeof(MFloat);
18688
18689 for(MInt srfcId = xdim; srfcId--;) {
18690 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 0] += flux[srfcId * ydim + 0];
18691 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 0] -= flux[srfcId * ydim + 0];
18692 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 1] += flux[srfcId * ydim + 1];
18693 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 1] -= flux[srfcId * ydim + 1];
18694 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 2] += flux[srfcId * ydim + 2];
18695 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 2] -= flux[srfcId * ydim + 2];
18696 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 3] += flux[srfcId * ydim + 3];
18697 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 3] -= flux[srfcId * ydim + 3];
18698 IF_CONSTEXPR(nDim == 3) {
18699 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 4] += flux[srfcId * ydim + 4];
18700 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 4] -= flux[srfcId * ydim + 4];
18701 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18702 for(MInt r = 0; r < m_noRansEquations; r++) {
18703 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 5 + r] += flux[srfcId * ydim + 5 + r];
18704 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 5 + r] -= flux[srfcId * ydim + 5 + r];
18705 }
18706 }
18707 for(MUint s = 0; s < noSpecies; ++s) {
18708 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 5 + m_noRansEquations + s] +=
18709 flux[srfcId * ydim + 5 + m_noRansEquations + s];
18710 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 5 + m_noRansEquations + s] -=
18711 flux[srfcId * ydim + 5 + m_noRansEquations + s];
18712 }
18713 }
18714 else {
18715 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18716 for(MInt r = 0; r < m_noRansEquations; r++) {
18717 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 4 + r] += flux[srfcId * ydim + 4 + r];
18718 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 4 + r] -= flux[srfcId * ydim + 4 + r];
18719 }
18720 }
18721 for(MUint s = 0; s < noSpecies; ++s) {
18722 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 4 + m_noRansEquations + s] +=
18723 flux[srfcId * ydim + 4 + m_noRansEquations + s] RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 4
18724 + m_noRansEquations + s] -=
18725 flux[srfcId * ydim + 4 + m_noRansEquations + s];
18726 }
18727 }
18728 }
18729
18730 if(m_RKStep == 1) { // freeze after first stage
18731 memset(flux, 0, size0);
18732 memset(RHSV, 0, size1);
18733 (this->*computeViscousFlux)();
18734
18735 for(MInt srfcId = xdim; srfcId--;) {
18736 RHSV[a_surfaceNghbrCellId(srfcId, 0) * ydim + 0] += flux[srfcId * ydim + 0];
18737 RHSV[a_surfaceNghbrCellId(srfcId, 1) * ydim + 0] -= flux[srfcId * ydim + 0];
18738 RHSV[a_surfaceNghbrCellId(srfcId, 0) * ydim + 1] += flux[srfcId * ydim + 1];
18739 RHSV[a_surfaceNghbrCellId(srfcId, 1) * ydim + 1] -= flux[srfcId * ydim + 1];
18740 RHSV[a_surfaceNghbrCellId(srfcId, 0) * ydim + 2] += flux[srfcId * ydim + 2];
18741 RHSV[a_surfaceNghbrCellId(srfcId, 1) * ydim + 2] -= flux[srfcId * ydim + 2];
18742 RHSV[a_surfaceNghbrCellId(srfcId, 0) * ydim + 3] += flux[srfcId * ydim + 3];
18743 RHSV[a_surfaceNghbrCellId(srfcId, 1) * ydim + 3] -= flux[srfcId * ydim + 3];
18744 IF_CONSTEXPR(nDim == 3) {
18745 RHSV[a_surfaceNghbrCellId(srfcId, 0) * ydim + 4] += flux[srfcId * ydim + 4];
18746 RHSV[a_surfaceNghbrCellId(srfcId, 1) * ydim + 4] -= flux[srfcId * ydim + 4];
18747 }
18748 }
18749 }
18750#else
18751 Base::viscousFlux();
18752#endif
18753}
18754
18755
18760template <MInt nDim, class SysEqn>
18762 TRACE();
18763
18764 MFloat* RESTRICT RHS = (MFloat*)(&(a_rightHandSide(0, 0)));
18765 MFloat* RESTRICT flux = (MFloat*)(&(a_surfaceFlux(0, 0)));
18766 const MInt xdim = m_noSurfaces;
18767 const MInt ydim = m_noFVars;
18768
18769#ifdef VISCOUS_FLUX_FREEZING
18770 MFloat* RESTRICT RHSV = (MFloat*)(&(m_rhsViscous[0][0]));
18771 const MInt xdim0 = a_noCells();
18772
18773 for(MInt i = xdim0; i--;) {
18774 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
18775 RHS[ydim * i + 0] += RHSV[ydim * i + 0];
18776 RHS[ydim * i + 1] += RHSV[ydim * i + 1];
18777 RHS[ydim * i + 2] += RHSV[ydim * i + 2];
18778 RHS[ydim * i + 3] += RHSV[ydim * i + 3];
18779 IF_CONSTEXPR(nDim == 3) {
18780 RHS[ydim * i + 4] += RHSV[ydim * i + 4];
18781 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18782 for(MInt r = 0; r < m_noRansEquations; ++r) {
18783 RHS[ydim * i + 5 + r] += RHSV[ydim * i + 5 + r];
18784 }
18785 }
18786 for(MInt s = 0; s < m_noSpecies; s++)
18787 RHS[ydim * i + 5 + s + m_noRansEquations] += RHSV[ydim * i + 5 + m_noRansEquations];
18788 }
18789 else {
18790 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18791 for(MInt r = 0; r < m_noRansEquations; ++r) {
18792 RHS[ydim * i + 4 + r] += RHSV[ydim * i + 4 + r];
18793 }
18794 }
18795 for(MInt s = 0; s < m_noSpecies; s++)
18796 RHS[ydim * i + 4 + s + m_noRansEquations] += RHSV[ydim * i + 4 + m_noRansEquations];
18797 }
18798 }
18799 return;
18800#endif
18801
18802//
18803#ifdef _MB_DEBUG_
18804 const MInt blk = -1;
18805 MInt cll = -1;
18806 const MInt gId = -1;
18807 const MInt varId = CV->RHO;
18808 const MInt pvarId = PV->RHO;
18809 MFloat area_check[3] = {F0, F0, F0};
18810 MFloat flux_check[3] = {F0, F0, F0};
18811#endif
18812 for(MInt srfcId = xdim; srfcId--;) {
18813#ifdef _MB_DEBUG_
18814 if((blk > -1 && domainId() == blk && a_surfaceNghbrCellId(srfcId, 0) == cll)
18815 || (gId > -1 && c_globalId(a_surfaceNghbrCellId(srfcId, 0)) == gId
18816 && !a_isHalo(a_surfaceNghbrCellId(srfcId, 0)))) {
18817 if(gId > -1) cll = a_surfaceNghbrCellId(srfcId, 0);
18818 MInt n0 = a_surfaceNghbrCellId(srfcId, 0);
18819 MInt n1 = a_surfaceNghbrCellId(srfcId, 1);
18820 cerr << domainId() << ": flux " << globalTimeStep << " " << m_RKStep << " " << srfcId << " "
18821 << /*m_isActiveSurface[ srfcId ]<< " " <<*/ flux[srfcId * ydim + varId] << " " << a_rightHandSide(cll, varId)
18822 << " /srf " << a_surfaceArea(srfcId) << " " << a_surfaceOrientation(srfcId) << " "
18823 << a_surfaceBndryCndId(srfcId) << " /ict "
18824 << a_hasProperty(a_surfaceNghbrCellId(srfcId, 0), SolverCell::IsInactive) << " "
18825 << a_hasProperty(a_surfaceNghbrCellId(srfcId, 1), SolverCell::IsInactive) << " /vol "
18826 << a_cellVolume(n0) / grid().gridCellVolume(a_level(n0)) << " "
18827 << a_cellVolume(n1) / grid().gridCellVolume(a_level(n1)) << " /vol0 " << a_cellVolume(n0) * a_FcellVolume(n0)
18828 << " " << a_cellVolume(n1) * a_FcellVolume(n1) << " /vol1 " << m_cellVolumesDt1[n0] * a_FcellVolume(n0)
18829 << " " << m_cellVolumesDt1[n1] * a_FcellVolume(n1) << " /ngb " << a_surfaceNghbrCellId(srfcId, 0) << " "
18830 << a_surfaceNghbrCellId(srfcId, 1) << " /ngbg " << c_globalId(a_surfaceNghbrCellId(srfcId, 0)) << " "
18831 << c_globalId(a_surfaceNghbrCellId(srfcId, 1)) << " /var "
18832 << a_variable(a_surfaceNghbrCellId(srfcId, 0), pvarId) << " "
18833 << a_variable(a_surfaceNghbrCellId(srfcId, 1), pvarId) << endl;
18834 area_check[a_surfaceOrientation(srfcId)] += a_surfaceArea(srfcId);
18835 flux_check[a_surfaceOrientation(srfcId)] += flux[srfcId * ydim + varId];
18836 }
18837 if((blk > -1 && domainId() == blk && a_surfaceNghbrCellId(srfcId, 1) == cll)
18838 || (gId > -1 && c_globalId(a_surfaceNghbrCellId(srfcId, 1)) == gId
18839 && !a_isHalo(a_surfaceNghbrCellId(srfcId, 1)))) {
18840 if(gId > -1) cll = a_surfaceNghbrCellId(srfcId, 1);
18841 MInt n0 = a_surfaceNghbrCellId(srfcId, 0);
18842 MInt n1 = a_surfaceNghbrCellId(srfcId, 1);
18843 cerr << domainId() << ": flux " << globalTimeStep << " " << m_RKStep << " " << srfcId << " "
18844 << /*m_isActiveSurface[ srfcId ] << " " <<*/ -flux[srfcId * ydim + varId] << " "
18845 << a_rightHandSide(cll, varId) << " /srf " << a_surfaceArea(srfcId) << " " << a_surfaceOrientation(srfcId)
18846 << " " << a_surfaceBndryCndId(srfcId) << " /ict "
18847 << a_hasProperty(a_surfaceNghbrCellId(srfcId, 0), SolverCell::IsInactive) << " "
18848 << a_hasProperty(a_surfaceNghbrCellId(srfcId, 1), SolverCell::IsInactive) << " /vol "
18849 << a_cellVolume(n0) / grid().gridCellVolume(a_level(n0)) << " "
18850 << a_cellVolume(n1) / grid().gridCellVolume(a_level(n1)) << " /vol0 " << a_cellVolume(n0) * a_FcellVolume(n0)
18851 << " " << a_cellVolume(n1) * a_FcellVolume(n1) << " /vol1 " << m_cellVolumesDt1[n0] * a_FcellVolume(n0)
18852 << " " << m_cellVolumesDt1[n1] * a_FcellVolume(n1) << " /ngb " << a_surfaceNghbrCellId(srfcId, 0) << " "
18853 << a_surfaceNghbrCellId(srfcId, 1) << " /var " << a_variable(a_surfaceNghbrCellId(srfcId, 0), pvarId) << " "
18854 << a_variable(a_surfaceNghbrCellId(srfcId, 1), pvarId);
18855 if(!a_isBndryGhostCell(a_surfaceNghbrCellId(srfcId, 0))) {
18856 cerr << " /ngbg " << c_globalId(a_surfaceNghbrCellId(srfcId, 0)) << " "
18857 << c_globalId(a_surfaceNghbrCellId(srfcId, 1));
18858 }
18859 cerr << endl;
18860 area_check[a_surfaceOrientation(srfcId)] -= a_surfaceArea(srfcId);
18861 flux_check[a_surfaceOrientation(srfcId)] -= flux[srfcId * ydim + varId];
18862 }
18863#endif
18864
18865 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim] += flux[srfcId * ydim];
18866 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim] -= flux[srfcId * ydim];
18867 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 1] += flux[srfcId * ydim + 1];
18868 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 1] -= flux[srfcId * ydim + 1];
18869 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 2] += flux[srfcId * ydim + 2];
18870 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 2] -= flux[srfcId * ydim + 2];
18871 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 3] += flux[srfcId * ydim + 3];
18872 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 3] -= flux[srfcId * ydim + 3];
18873 IF_CONSTEXPR(nDim == 3) {
18874 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 4] += flux[srfcId * ydim + 4];
18875 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 4] -= flux[srfcId * ydim + 4];
18876 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18877 for(MInt r = 0; r < m_noRansEquations; ++r) {
18878 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 5 + r] += flux[srfcId * ydim + 5 + r];
18879 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 5 + r] -= flux[srfcId * ydim + 5 + r];
18880 }
18881 }
18882 for(MInt s = 0; s < m_noSpecies; s++) {
18883 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 5 + s + m_noRansEquations] +=
18884 flux[srfcId * ydim + 5 + s + m_noRansEquations];
18885 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 5 + s + m_noRansEquations] -=
18886 flux[srfcId * ydim + 5 + s + m_noRansEquations];
18887 }
18888 }
18889 else {
18890 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18891 for(MInt r = 0; r < m_noRansEquations; ++r) {
18892 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 4 + r] += flux[srfcId * ydim + 4 + r];
18893 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 4 + r] -= flux[srfcId * ydim + 4 + r];
18894 }
18895 }
18896 for(MInt s = 0; s < m_noSpecies; s++) {
18897 RHS[a_surfaceNghbrCellId(srfcId, 0) * ydim + 4 + s + m_noRansEquations] +=
18898 flux[srfcId * ydim + 4 + s + m_noRansEquations];
18899 RHS[a_surfaceNghbrCellId(srfcId, 1) * ydim + 4 + s + m_noRansEquations] -=
18900 flux[srfcId * ydim + 4 + s + m_noRansEquations];
18901 }
18902 }
18903
18904
18905#ifdef _MB_DEBUG_
18906 for(MInt v = 0; v < m_noFVars; v++) {
18907 if(std::isnan(flux[srfcId * ydim + v])) {
18908 cerr << domainId() << ": flux is nan " << globalTimeStep << " " << m_RKStep << " " << srfcId << " "
18909 << getPrimitiveVarName(v) << " /n " << a_surfaceNghbrCellId(srfcId, 0) << " "
18910 << a_surfaceNghbrCellId(srfcId, 1) << " /v " << a_pvariable(a_surfaceNghbrCellId(srfcId, 0), v) << " "
18911 << a_pvariable(a_surfaceNghbrCellId(srfcId, 1), v) << " /b " << a_bndryId(a_surfaceNghbrCellId(srfcId, 0))
18912 << " " << a_bndryId(a_surfaceNghbrCellId(srfcId, 1)) << " /p " << a_isHalo(a_surfaceNghbrCellId(srfcId, 0))
18913 << " " << a_isHalo(a_surfaceNghbrCellId(srfcId, 1)) << " " << a_isWindow(a_surfaceNghbrCellId(srfcId, 0))
18914 << " " << a_isWindow(a_surfaceNghbrCellId(srfcId, 1)) << " /s "
18915 << a_slope(a_surfaceNghbrCellId(srfcId, 0), v, 0) << " " << a_slope(a_surfaceNghbrCellId(srfcId, 0), v, 1)
18916 << " " << a_slope(a_surfaceNghbrCellId(srfcId, 1), v, 0) << " "
18917 << a_slope(a_surfaceNghbrCellId(srfcId, 1), v, 1) << endl;
18918 // break;
18919 }
18920 }
18921#endif
18922 }
18923
18924#ifdef _MB_DEBUG_
18925 if((gId > -1 && cll > -1) && (blk > -1 && domainId() == blk)) {
18926 if(!a_hasProperty(cll, SolverCell::IsInactive)) {
18927 MInt bcll = a_bndryId(cll);
18928 cerr << domainId() << ": area check " << cll << ": " << area_check[0] << " " << area_check[1] << " "
18929 << area_check[2] << " / " << a_rightHandSide(cll, varId) << " /vols "
18930 << a_cellVolume(cll) / grid().gridCellVolume(a_level(cll)) << " "
18931 << m_cellVolumesDt1[cll] / grid().gridCellVolume(a_level(cll)) << " "
18932 << ((bcll > -1) ? m_fvBndryCnd->m_bndryCells->a[bcll].m_volume / grid().gridCellVolume(a_level(cll)) : -1)
18933 << " / " << a_isHalo(cll) << endl;
18934 cerr << domainId() << ": flux check " << cll << ": " << flux_check[0] << " " << flux_check[1] << " "
18935 << flux_check[2] << " / " << a_variable(cll, pvarId) << " "
18936 << a_variable(cll, pvarId) / a_variable(cll, CV->RHO) << endl;
18937 cerr << domainId() << ": rhs " << cll << " ";
18938 for(MInt v = 0; v < m_noFVars; v++) {
18939 cerr << a_rightHandSide(cll, v) << " ";
18940 }
18941 cerr << endl;
18942 for(MInt v = 0; v < m_noCVars; v++) {
18943 cerr << a_oldVariable(cll, v) << " ";
18944 }
18945 cerr << endl;
18946 for(MInt v = 0; v < m_noFVars; v++) {
18947 cerr << timeStep() * a_FcellVolume(cll) * a_rightHandSide(cll, v) << " ";
18948 }
18949 cerr << endl;
18950 for(MInt v = 0; v < m_noCVars; v++) {
18951 cerr << a_FcellVolume(cll)
18952 * (m_cellVolumesDt1[cll] * a_oldVariable(cll, v) - timeStep() * a_rightHandSide(cll, v))
18953 << " ";
18954 }
18955 cerr << endl;
18956 }
18957 }
18958#endif
18959
18960 if(m_pointParticleTwoWayCoupling && m_noPointParticles > 0) {
18961 for(MInt cellId = 0; cellId < maxNoGridCells(); cellId++) {
18962 for(MInt dim = 0; dim < nDim; dim++) {
18963 m_coupling[cellId][dim] = F0;
18964 }
18965 }
18966 const MInt noCouplingLayers = 2;
18967 const MInt maxNoNghbrs = 150;
18968 MIntScratchSpace nghbrList(maxNoNghbrs, AT_, "nghbrList");
18969 MIntScratchSpace layerId(maxNoNghbrs, AT_, "layerList");
18970 MFloatScratchSpace weights(maxNoNghbrs, AT_, "weights");
18971 nghbrList.fill(-1);
18972 m_couplingRate = F0;
18973 for(MInt i = 0; i < noNeighborDomains(); i++) {
18974 for(MInt j = 0; j < m_noMaxLevelHaloCells[i]; j++) {
18975 MInt cellId = m_maxLevelHaloCells[i][j];
18976 for(MInt v = 0; v < m_noFVars; v++) {
18977 a_rightHandSide(cellId, v) = F0;
18978 }
18979 }
18980 }
18981 MFloat expFac = F1B8;
18982 for(MUint p = 0; p < m_particleCellLink.size(); p++) {
18983 const MInt cellId = m_particleCellLink[p];
18984 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) cerr << "Warning: not a leaf cell!" << endl;
18985 const MFloat mass = F4B3 * PI * m_particleRadii[3 * p] * m_particleRadii[3 * p + 1] * m_particleRadii[3 * p + 2]
18986 * m_densityRatio * m_rhoInfinity;
18987 const MFloat diameter =
18988 F2 * pow(m_particleRadii[3 * p] * m_particleRadii[3 * p + 1] * m_particleRadii[3 * p + 2], F1B3);
18989 const MFloat T = sysEqn().temperature_ES(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
18990 const MFloat mue = SUTHERLANDLAW(T);
18991 const MFloat FAC = 18.0 * mue / (sysEqn().m_Re0 * m_densityRatio * m_rhoInfinity * POW2(diameter));
18992 const MInt counter =
18993 (noCouplingLayers > 0)
18994 ? 1 + this->template getAdjacentLeafCells<2>(cellId, noCouplingLayers, nghbrList, layerId)
18995 : 1;
18996
18997 const MFloat heatFlux =
18998 m_particleHeatFlux[p] * 1 / m_gamma * 1 / (m_gamma - 1) * mass * m_capacityConstantVolumeRatio;
18999
19000 if(noCouplingLayers > 0) nghbrList[counter - 1] = nghbrList[0];
19001 nghbrList[0] = cellId;
19002 MFloat sum = F0;
19003 for(MInt c = 0; c < counter; c++) {
19004 MFloat dx = F0;
19005 MInt nghbrId = nghbrList(c);
19006 for(MInt i = 0; i < nDim; i++) {
19007 dx += POW2(a_coordinate(nghbrId, i) - m_particleCoords[nDim * p + i]);
19008 }
19009 weights(c) = exp(-expFac * dx / POW2(c_cellLengthAtLevel(a_level(cellId))));
19010 sum += weights(c);
19011 }
19012 for(MInt c = 0; c < counter; c++) {
19013 weights(c) /= sum;
19014 }
19015 for(MInt c = 0; c < counter; c++) {
19016 MInt nghbrId = nghbrList(c);
19017 for(MInt i = 0; i < nDim; i++) {
19018 MFloat acc = m_particleAcceleration[nDim * p + i] - FAC * m_particleTerminalVelocity[i];
19019 a_rightHandSide(nghbrId, CV->RHO_VV[i]) += weights(c) * mass * acc;
19020 a_rightHandSide(nghbrId, CV->RHO_E) += weights(c) * a_pvariable(nghbrId, PV->VV[i]) * mass * acc;
19021 m_couplingRate -= weights(c) * mass * acc * a_pvariable(nghbrId, PV->VV[i]);
19022 m_coupling[nghbrId][i] -= weights(c) * mass * acc;
19023 }
19024 a_rightHandSide(nghbrId, CV->RHO_E) += weights(c) * heatFlux;
19025 }
19026 }
19027 MPI_Allreduce(MPI_IN_PLACE, &m_couplingRate, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
19028 "m_couplingRate");
19029 MIntScratchSpace haloBufferOffsets(noNeighborDomains() + 1, AT_, "haloBufferOffsets");
19030 MIntScratchSpace windowBufferOffsets(noNeighborDomains() + 1, AT_, "windowBufferOffsets");
19031 ScratchSpace<MPI_Request> sendReq(mMax(1, noNeighborDomains()), AT_, "sendReq");
19032 haloBufferOffsets.fill(0);
19033 windowBufferOffsets.fill(0);
19034 for(MInt i = 0; i < noNeighborDomains(); i++) {
19035 haloBufferOffsets(i + 1) = haloBufferOffsets(i) + m_noFVars * m_noMaxLevelHaloCells[i];
19036 windowBufferOffsets(i + 1) = windowBufferOffsets(i) + m_noFVars * m_noMaxLevelWindowCells[i];
19037 }
19038 MFloatScratchSpace haloBuffer(haloBufferOffsets(noNeighborDomains()), AT_, "haloBuffer");
19039 MFloatScratchSpace windowBuffer(windowBufferOffsets(noNeighborDomains()), AT_, "windowBuffer");
19040 haloBuffer.fill(F0);
19041 for(MInt i = 0; i < noNeighborDomains(); i++) {
19042 for(MInt j = 0; j < m_noMaxLevelHaloCells[i]; j++) {
19043 MInt cellId = m_maxLevelHaloCells[i][j];
19044 for(MInt v = 0; v < m_noFVars; v++) {
19045 haloBuffer(haloBufferOffsets(i) + m_noFVars * j + v) += a_rightHandSide(cellId, v);
19046 }
19047 }
19048 }
19049 sendReq.fill(MPI_REQUEST_NULL);
19050 for(MInt i = 0; i < noNeighborDomains(); i++) {
19051 MPI_Issend(&haloBuffer[haloBufferOffsets(i)], m_noFVars * m_noMaxLevelHaloCells[i], MPI_DOUBLE, neighborDomain(i),
19052 81, mpiComm(), &sendReq[i], AT_, "haloBuffer[haloBufferOffsets(i)]");
19053 }
19054 for(MInt i = 0; i < noNeighborDomains(); i++) {
19055 MPI_Recv(&windowBuffer[windowBufferOffsets(i)], m_noFVars * m_noMaxLevelWindowCells[i], MPI_DOUBLE,
19056 neighborDomain(i), 81, mpiComm(), MPI_STATUS_IGNORE, AT_, "windowBuffer[windowBufferOffsets(i)]");
19057 }
19058 MPI_Waitall(noNeighborDomains(), &sendReq[0], MPI_STATUSES_IGNORE, AT_);
19059 for(MInt i = 0; i < noNeighborDomains(); i++) {
19060 for(MInt j = 0; j < m_noMaxLevelWindowCells[i]; j++) {
19061 MInt cellId = m_maxLevelWindowCells[i][j];
19062 for(MInt v = 0; v < m_noFVars; v++) {
19063 a_rightHandSide(cellId, v) += windowBuffer(windowBufferOffsets(i) + m_noFVars * j + v);
19064 }
19065 for(MInt v = 0; v < nDim; v++) {
19066 m_coupling[cellId][v] -= windowBuffer(windowBufferOffsets(i) + m_noFVars * j + CV->RHO_VV[v]);
19067 }
19068 }
19069 }
19070 }
19071
19072
19073#ifdef _MB_DEBUG_
19074 m_solutionDiverged = false;
19075 for(MInt i = a_noCells(); i--;) {
19076 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
19077 if(!a_hasProperty(i, SolverCell::IsOnCurrentMGLevel)) continue;
19078 if(a_isHalo(i)) continue;
19079 if(a_isBndryGhostCell(i)) continue;
19080 for(MInt v = 0; v < m_noFVars; v++) {
19081 if(!(a_rightHandSide(i, v) >= F0 || a_rightHandSide(i, v) < F0) || std::isnan(a_rightHandSide(i, v))) {
19082 cerr << "RHS0 " << i << " " << a_bndryId(i) << " " << v << " " << a_rightHandSide(i, v) << " "
19083 << "cells[i].b_properties.to_string()" << endl;
19084 m_solutionDiverged = true;
19085 }
19086 }
19087 }
19088 if(m_solutionDiverged) {
19089 cerr << "Solution diverged (RHS0) at solver " << domainId() << " " << globalTimeStep << " " << m_RKStep << endl;
19090 // writeVtkErrorFile();
19091 }
19092 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
19093 "m_solutionDiverged");
19094 if(m_solutionDiverged) {
19095 writeVtkXmlFiles("QOUT", "GEOM", false, true);
19096 MPI_Barrier(mpiComm(), AT_);
19097 mTerm(1, AT_, "Solution diverged after RHS0 handling.");
19098 }
19099#endif
19100
19101 if(m_initialCondition == 452) {
19102 computeVolumeForces();
19103 }
19104}
19105
19106
19111template <MInt nDim, class SysEqn>
19114}
19115
19116
19121template <MInt nDim, class SysEqn>
19123 return (this->*execRungeKuttaStep)();
19124}
19125
19126
19135template <MInt nDim, class SysEqn>
19137 MLong noCells = 0;
19138 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
19139 if(!a_isHalo(cellId) && c_isLeafCell(cellId)) noCells++;
19140 }
19141
19142 if(mode > -1) {
19143 switch(mode) {
19144 case 0:
19145 MPI_Allreduce(MPI_IN_PLACE, &noCells, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noCells");
19146 break;
19147 case 1:
19148 MPI_Allreduce(MPI_IN_PLACE, &noCells, 1, MPI_LONG, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "noCells");
19149 break;
19150 case 2:
19151 MPI_Allreduce(MPI_IN_PLACE, &noCells, 1, MPI_LONG, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "noCells");
19152 break;
19153 case 3:
19154 MPI_Allreduce(MPI_IN_PLACE, &noCells, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noCells");
19155 noCells = (MLong)(((MFloat)noCells) / ((MFloat)noDomains()));
19156 break;
19157 default:
19158 mTerm(1, AT_, "Unknown case.");
19159 }
19160 }
19161
19162 return noCells;
19163}
19164
19165
19167
19175template <MInt nDim, class SysEqn>
19177 TRACE();
19178
19179 if(globalTimeStep % m_residualInterval != 0) {
19180 return true;
19181 }
19182
19183 if(mode == 0 && (!m_trackMovingBndry || globalTimeStep < m_trackMbStart || globalTimeStep > m_trackMbEnd)) {
19184 // NOTE: calling the original Fv residual function for stationary problems where the residual
19185 // can be used/outputted for convergence studies
19187 }
19188
19189 ScratchSpace<MFloat> bbox(m_noDirs, AT_, "bbox");
19190 for(MInt i = 0; i < nDim; i++) {
19191 bbox[i] = std::numeric_limits<MFloat>::max();
19192 bbox[nDim + i] = -std::numeric_limits<MFloat>::max();
19193 }
19194
19195 const MInt oldRKStep[5] = {4, 0, 1, 2, 3};
19196 MBool nan = false;
19197 MInt counter = 0;
19198 MFloat maxR = -F1;
19199 MInt maxRC = -1;
19200 MInt nanC = -1;
19201
19202 const MInt size = a_noCells();
19203 for(MInt cellId = size; cellId--;) {
19204 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19205 if(a_isBndryGhostCell(cellId)) continue;
19206 if(a_isHalo(cellId)) continue;
19207 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
19208 if(a_bndryId(cellId) == -2) continue;
19209
19210 if(fabs(a_rightHandSide(cellId, CV->RHO)) > maxR) {
19211 maxR = fabs(a_rightHandSide(cellId, CV->RHO));
19212 maxRC = cellId;
19213 }
19214
19215 if((!(a_rightHandSide(cellId, CV->RHO) >= F0 || a_rightHandSide(cellId, CV->RHO) < F0))) {
19216 m_log << "RHS[rho] is " << a_rightHandSide(cellId, CV->RHO) << " in cell " << cellId << "(" << a_bndryId(cellId)
19217 << ") "
19218 " "
19219 << a_hasProperty(cellId, SolverCell::IsInactive) << " " << a_levelSetValuesMb(cellId, 0)
19220 << " vol:" << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << " / ";
19221 for(MInt i = 0; i < nDim; i++)
19222 m_log << " " << a_coordinate(cellId, i);
19223 m_log << " " << a_hasProperty(cellId, SolverCell::NearWall);
19224 m_log << " / " << a_noReconstructionNeighbors(cellId);
19225 m_log << " " << a_isHalo(cellId);
19226 m_log << " " << a_hasProperty(cellId, SolverCell::IsNotGradient);
19227 IF_CONSTEXPR(nDim == 2) {
19228 m_log << " p7: " << a_isHalo(c_neighborId(cellId, 0)) << " " << a_isHalo(c_neighborId(cellId, 1)) << " "
19229 << a_isHalo(c_neighborId(cellId, 2)) << " " << a_isHalo(c_neighborId(cellId, 3));
19230 }
19231 else IF_CONSTEXPR(nDim == 3) {
19232 m_log << " p7: " << a_isHalo(c_neighborId(cellId, 0)) << " " << a_isHalo(c_neighborId(cellId, 1)) << " "
19233 << a_isHalo(c_neighborId(cellId, 2)) << " " << a_isHalo(c_neighborId(cellId, 3)) << " "
19234 << a_isHalo(c_neighborId(cellId, 4)) << " " << a_isHalo(c_neighborId(cellId, 5));
19235 }
19236 m_log << endl;
19237 for(MInt i = 0; i < nDim; i++) {
19238 bbox[i] = mMin(bbox[i], a_coordinate(cellId, i));
19239 bbox[nDim + i] = mMax(bbox[nDim + i], a_coordinate(cellId, i));
19240 }
19241 nan = true;
19242 nanC = cellId;
19243 counter++;
19244 }
19245
19246 if(counter > 1000) {
19247 m_log << "More than 1000 nan's; output suspended." << endl;
19248 break;
19249 }
19250 }
19251
19252#ifdef _MB_DEBUG_
19253 MPI_Allreduce(MPI_IN_PLACE, &bbox[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[0]");
19254 MPI_Allreduce(MPI_IN_PLACE, &bbox[nDim], nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[nDim]");
19255#endif
19256
19257 if(nan) {
19258 if(maxRC > -1) {
19259 m_log << "Maximum residual at time step " << globalTimeStep << " is " << maxR << " in cell " << maxRC << " at";
19260 for(MInt i = 0; i < nDim; i++)
19261 m_log << " " << a_coordinate(maxRC, i);
19262 m_log << ", res: " << scientific;
19263 for(MInt v = 0; v < m_noFVars; v++)
19264 m_log << " " << a_rightHandSide(maxRC, v);
19265 m_log << ", vol.: " << a_cellVolume(maxRC);
19266 m_log << ", vol.frac.: " << a_cellVolume(maxRC) / c_cellLengthAtLevel(a_level(maxRC));
19267 m_log << endl;
19268 }
19269
19270 MFloat minVol = std::numeric_limits<MFloat>::max();
19271 MFloat minVolFrac = std::numeric_limits<MFloat>::max();
19272 MInt partitionCell = -1;
19273 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
19274 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
19275 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume < minVol) {
19276 minVolFrac = m_volumeFraction[bndryId];
19277 minVol = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
19278 partitionCell = cellId;
19279 }
19280 }
19281 if(partitionCell > -1) {
19282 IF_CONSTEXPR(nDim == 2) {
19283 m_log << "Smallest cell: " << partitionCell << " " << minVol << " " << minVolFrac << " / "
19284 << m_fvBndryCnd->m_bndryCells->a[a_bndryId(partitionCell)].m_srfcs[0]->m_normalVector[0] << " "
19285 << m_fvBndryCnd->m_bndryCells->a[a_bndryId(partitionCell)].m_srfcs[0]->m_normalVector[1] << " "
19286 << " / " << a_rightHandSide(partitionCell, CV->RHO) << " " << a_rightHandSide(partitionCell, CV->RHO_U)
19287 << endl;
19288 }
19289 else IF_CONSTEXPR(nDim == 3) {
19290 m_log << "Smallest cell: " << partitionCell << " " << minVol << " " << minVolFrac << " / "
19291 << m_fvBndryCnd->m_bndryCells->a[a_bndryId(partitionCell)].m_srfcs[0]->m_normalVector[0] << " "
19292 << m_fvBndryCnd->m_bndryCells->a[a_bndryId(partitionCell)].m_srfcs[0]->m_normalVector[1] << " "
19293 << m_fvBndryCnd->m_bndryCells->a[a_bndryId(partitionCell)].m_srfcs[0]->m_normalVector[2] << " "
19294 << " / " << a_rightHandSide(partitionCell, CV->RHO) << " " << a_rightHandSide(partitionCell, CV->RHO_U)
19295 << endl;
19296 }
19297 }
19298 cerr << "========================" << endl;
19299 cerr << "time step " << globalTimeStep << ", Runge Kutta step " << oldRKStep[m_RKStep] << ", solver " << solverId()
19300 << endl;
19301 cerr << domainId() << ": Solution diverged (e.g. " << c_globalId(nanC) << ") in region ";
19302 for(MInt i = 0; i < nDim; i++) {
19303 cerr << "[" << bbox[i] << "," << bbox[nDim + i] << "]";
19304 if(i < nDim - 1) cerr << "x";
19305 }
19306 cerr << ". Quit." << endl;
19307 m_solutionDiverged = true;
19308 }
19309
19310 MPI_Allreduce(MPI_IN_PLACE, &m_solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
19311 "m_solutionDiverged");
19312
19313 if(m_solutionDiverged) {
19314#ifdef _MB_DEBUG_
19315 m_log << "=========== BOUNDARY LOG ================" << endl;
19316 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
19317 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBndryCells; bndryId++) {
19318 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
19319 m_log << bndryId << " " << cellId;
19320 for(MInt dir = 0; dir < m_noDirs; dir++) {
19321 MInt cId = (c_neighborId(cellId, dir) > -1) ? m_bndryCandidateIds[c_neighborId(cellId, dir)] : -1;
19322 m_log << " / " << dir << " " << a_hasNeighbor(cellId, dir) << " " << c_neighborId(cellId, dir) << " " << cId;
19323 }
19324 m_log << endl;
19325 }
19326#endif
19327 saveSolverSolution(1);
19328 /*
19329 #ifdef _MB_DEBUG_
19330 for ( MInt cellId = 0; cellId < a_noCells(); cellId++ ) {
19331 a_hasProperty( cellId , SolverCell::IsOnCurrentMGLevel) = true;
19332 }
19333 stringstream filen;
19334 filen << "out/QDIV_" << domainId() << ".vtk";
19335 m_fvBndryCnd->recorrectCellCoordinates();
19336 extractPointIdsFromGrid( m_extractedCells, m_gridPoints, true, m_splitChildToSplitCell);
19337 for( MInt c = 0; c < m_extractedCells->size(); c++ ) {
19338 a_pvariable(m_extractedCells->a[ c ].m_cellId, PV->RHO) = a_levelSetValuesMb(m_extractedCells->a[ c
19339 ].m_cellId, 0);
19340 }
19341 writeVtkOutput( (filen.str()).c_str() );
19342 m_fvBndryCnd->rerecorrectCellCoordinates();
19343 if ( m_extractedCells ) { delete m_extractedCells; m_extractedCells = nullptr; }
19344 if ( m_gridPoints ) { delete m_gridPoints; m_gridPoints = nullptr; }
19345 #endif
19346 */
19347 MPI_Barrier(mpiComm(), AT_);
19348 mTerm(1, AT_, "Solution diverged.");
19349 } else {
19350 // saveSolverSolution(1); MPI_Barrier(mpiComm(), AT_ ); mTerm(0,AT_, "test");
19351 if(nan) mTerm(1, AT_, "Solution diverged.");
19352
19353 return true;
19354 }
19355
19356 return false;
19357}
19358
19359
19364template <MInt nDim, class SysEqn>
19366 // if ( std::isnan( number ) ) return (-1e33);
19367 // else return number;
19368 return number;
19369}
19370
19371
19376template <MInt nDim, class SysEqn>
19378 if(cellId < 0) {
19379 cerr << "Critical error in createBndryCellMb: "
19380 << ", cell: " << cellId << endl;
19381 saveSolverSolution(1);
19382 mTerm(1, AT_, "Critical error in createBndryCellMb");
19383 }
19384
19385 ASSERT(!a_isBndryCell(cellId), "");
19386
19387 MInt bCellId = m_fvBndryCnd->m_bndryCells->size();
19388 m_fvBndryCnd->m_bndryCells->append();
19389
19390#if defined _MB_DEBUG_ || !defined NDEBUG
19391 if(globalTimeStep > m_restartTimeStep) {
19392 if(a_levelSetValuesMb(cellId, 0) < F0 && !a_hasProperty(cellId, SolverCell::IsSplitChild)) {
19393 // not surprising during Gap-Closure!
19394 if(!a_isGapCell(cellId)) {
19395 if(!a_hasProperty(cellId, SolverCell::IsInactive)) {
19396 cerr << "not inact " << c_globalId(cellId) << endl;
19397 }
19398 if(m_oldBndryCells.size() > 0 && !m_oldBndryCells.count(cellId)) {
19399 if(!a_hasProperty(cellId, SolverCell::WasInactive)) {
19400 auto it = std::find(m_refOldBndryCells.begin(), m_refOldBndryCells.end(), c_parentId(cellId));
19401 if(it == m_refOldBndryCells.end()) {
19402 cerr << "CellId " << cellId << " " << c_globalId(cellId) << " isHalo " << a_isHalo(cellId)
19403 << " is GapCell " << a_isGapCell(cellId) << " was GapCell " << a_wasGapCell(cellId)
19404 << " was not inactive before and is a new bndryCell with Id " << bCellId << " ls-value "
19405 << a_levelSetValuesMb(cellId, 0) << " at timeStep " << globalTimeStep << endl;
19406 }
19407 }
19408 }
19409 }
19410 }
19411 }
19412#endif
19413
19414 for(MInt face = 0; face < m_noDirs; face++)
19415 m_fvBndryCnd->m_bndryCells->a[bCellId].m_associatedSrfc[face] = -1;
19416
19417 a_bndryId(cellId) = bCellId;
19418 m_fvBndryCnd->m_bndryCells->a[bCellId].m_cellId = cellId;
19419
19420 for(MInt srfc = 0; srfc < FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces; srfc++) {
19421 m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcs[srfc]->m_noCutPoints = 0;
19422 m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_ghostCellId = -1;
19423 for(MInt i = 0; i < nDim; i++)
19424 m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_srfcId[i] = -1;
19425 m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcs[srfc]->m_bndryCndId = -1; // m_movingBndryCndId;
19426 for(MInt v = 0; v < m_noCVars; v++) {
19427 m_fvBndryCnd->m_bndryCell[bCellId].m_srfcVariables[srfc]->m_variablesType[v] = BC_UNSET;
19428 }
19429 m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcs[srfc]->m_area = F0;
19430 }
19431 m_fvBndryCnd->m_bndryCell[bCellId].m_recNghbrIds.clear();
19432 m_fvBndryCnd->m_bndryCell[bCellId].m_faceVertices.clear();
19433 m_fvBndryCnd->m_bndryCell[bCellId].m_faceStream.resize(0);
19434
19435 m_fvBndryCnd->m_bndryCells->a[bCellId].m_linkedCellId = -1;
19436 m_fvBndryCnd->m_bndryCells->a[bCellId].m_noSrfcs = 1;
19437 m_fvBndryCnd->m_bndryCells->a[bCellId].m_volume = F0;
19438
19439 m_sweptVolume[bCellId] = F0;
19440 m_sweptVolumeDt1[bCellId] = F0;
19441
19442 a_hasProperty(cellId, SolverCell::IsInactive) = false;
19443 a_hasProperty(cellId, SolverCell::IsFlux) = true;
19444 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = true;
19445 a_hasProperty(cellId, SolverCell::IsMovingBnd) = true;
19446
19447 for(MInt i = 0; i < nDim; i++) {
19448 m_fvBndryCnd->m_bndryCells->a[bCellId].m_coordinates[i] = F0;
19449 }
19450
19451 for(MInt dir = 0; dir < m_noDirs; dir++) {
19452 m_cutFaceArea[bCellId][dir] = F0;
19453 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
19454 if(srfcId > -1) {
19455 m_bndryCells->a[bCellId].m_associatedSrfc[dir] = m_cellSurfaceMapping[cellId][dir];
19456 }
19457 }
19458
19459 m_noLsMbBndryCells++;
19460
19461 return bCellId;
19462}
19463
19464
19469template <MInt nDim, class SysEqn>
19471 TRACE();
19472
19473 const MInt splitId = m_splitCells.size();
19474 m_splitCells.push_back(cellId);
19475 m_splitChilds.resize(m_splitCells.size());
19476 m_splitChilds[splitId].resize(noSplitChilds);
19477 a_hasProperty(cellId, SolverCell::IsSplitCell) = false;
19478
19479 for(MInt n = 0; n < noSplitChilds; n++) {
19480 const MInt splitChildId = a_noCells();
19481
19482 m_cells.append();
19483 m_totalnosplitchilds++;
19484
19485 ASSERT(splitChildId == a_noCells() - 1, "Error in the cell-count, for splitchilds!");
19486
19487 for(MInt dir = 0; dir < m_noDirs; dir++) {
19488 m_cellSurfaceMapping[splitChildId][dir] = -1;
19489 }
19490 a_cellVolume(splitChildId) = a_cellVolume(cellId);
19491 m_cellVolumesDt1[splitChildId] = m_cellVolumesDt1[cellId];
19492 for(MInt k = 0; k < nDim; k++) {
19493 a_coordinate(splitChildId, k) = a_coordinate(cellId, k);
19494 }
19495 a_level(splitChildId) = a_level(cellId);
19496
19497 a_isBndryGhostCell(splitChildId) = false;
19498 a_noReconstructionNeighbors(splitChildId) = 0;
19499
19500 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
19501 a_associatedBodyIds(splitChildId, set) = a_associatedBodyIds(cellId, set);
19502 a_levelSetValuesMb(splitChildId, set) = a_levelSetValuesMb(cellId, set);
19503 }
19504
19505 a_copyPropertiesSolver(cellId, splitChildId);
19506
19507 a_hasProperty(splitChildId, SolverCell::IsSplitCell) = false;
19508 a_hasProperty(splitChildId, SolverCell::IsSplitChild) = true;
19509 a_hasProperty(splitChildId, SolverCell::IsInactive) = false;
19510 a_hasProperty(splitChildId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::WasInactive);
19511
19512 for(MInt var = 0; var < CV->noVariables; var++) {
19513 a_variable(splitChildId, var) = a_variable(cellId, var);
19514 a_oldVariable(splitChildId, var) = a_variable(cellId, var);
19515 a_pvariable(splitChildId, var) = a_pvariable(cellId, var);
19516 }
19517
19518 a_bndryId(splitChildId) = createBndryCellMb(splitChildId);
19519 ASSERT(a_bndryId(splitChildId) > -1, "");
19520 MInt splitChildBndryId = a_bndryId(splitChildId);
19521 for(MInt dir = 0; dir < m_noDirs; dir++) {
19522 m_bndryCells->a[splitChildBndryId].m_associatedSrfc[dir] = -1;
19523 m_bndryCells->a[splitChildBndryId].m_externalFaces[dir] = false;
19524 }
19525 m_splitChilds[splitId][n] = splitChildId;
19526 m_splitChildToSplitCell.insert(pair<MInt, MInt>(splitChildId, cellId));
19527
19528 m_bndryLayerCells.push_back(splitChildId);
19529 a_hasProperty(splitChildId, SolverCell::NearWall) = true;
19530
19531 ASSERT(a_level(splitChildId) == a_level(m_splitChildToSplitCell.find(splitChildId)->second), "");
19532 }
19533
19534 a_hasProperty(cellId, SolverCell::IsSplitCell) = true;
19535
19536 ASSERT(splitId > -1, "");
19537 return splitId;
19538}
19539
19540
19545template <MInt nDim, class SysEqn>
19547 TRACE();
19548
19549 m_bndryGhostCellsOffset = a_noCells();
19550 m_fvBndryCnd->computeGhostCells();
19551
19552 for(MInt bndryId = 0; bndryId < m_noOuterBndryCells; bndryId++) {
19553 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
19554 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
19555 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
19556 a_reconstructionNeighborId(cellId, srfc) =
19557 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
19558 }
19559 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
19560 const MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
19561 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
19562 a_associatedBodyIds(ghostCellId, set) = -1;
19563 }
19564 }
19565 }
19566}
19567
19568
19573template <MInt nDim, class SysEqn>
19575 TRACE();
19576
19577 correctMasterSlaveSurfaces();
19578 m_bndrySurfacesOffset = a_noSurfaces();
19579 m_fvBndryCnd->addBoundarySurfaces();
19580
19581 for(MInt srfcId = m_bndrySurfacesOffset; srfcId < a_noSurfaces(); srfcId++) {
19582 a_surfaceUpwindCoefficient(srfcId) = m_globalUpwindCoefficient;
19583 a_surfaceFactor(srfcId, 0) = F1B2;
19584 a_surfaceFactor(srfcId, 1) = F1B2;
19585 for(MInt i = 0; i < nDim; i++) {
19586 a_surfaceDeltaX(srfcId, i) = a_surfaceCoordinate(srfcId, i) - a_coordinate(a_surfaceNghbrCellId(srfcId, 0), i);
19587 a_surfaceDeltaX(srfcId, nDim + i) =
19588 a_surfaceCoordinate(srfcId, i) - a_coordinate(a_surfaceNghbrCellId(srfcId, 1), i);
19589 }
19590 }
19591 m_noOuterBoundarySurfaces = m_fvBndryCnd->m_noBoundarySurfaces;
19592}
19593
19594
19601template <MInt nDim, class SysEqn>
19603 TRACE();
19604
19605 MInt noOuterBndryGhostCells = 0;
19606 for(MInt bndryId = 0; bndryId < m_noOuterBndryCells; bndryId++) {
19607 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
19608 noOuterBndryGhostCells++;
19609 }
19610 }
19611 m_associatedInternalCells.resize(noOuterBndryGhostCells);
19612
19613 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
19614 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
19615 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId = -1;
19616 }
19617 }
19618
19619 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
19620 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
19621
19622 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
19623 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19624 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19625
19626 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
19627 // append a cell to the fv-cell collectors
19628 m_cells.append();
19629 m_totalnoghostcells++;
19630
19631 MInt ghostCellId = a_noCells() - 1;
19632 m_associatedInternalCells.push_back(cellId);
19633
19634 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId = ghostCellId;
19635
19636 a_cellVolume(ghostCellId) = grid().gridCellVolume(a_level(cellId));
19637 m_cellVolumesDt1[ghostCellId] = grid().gridCellVolume(a_level(cellId));
19638 a_FcellVolume(ghostCellId) = F1 / a_cellVolume(ghostCellId);
19639
19640 const MFloat cellLength = c_cellLengthAtLevel(a_level(cellId));
19641 const MFloat cellHalfLength = F1B2 * cellLength;
19642
19643 MFloat dn = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
19644
19645 for(MInt i = 0; i < nDim; i++) {
19646 a_coordinate(ghostCellId, i) =
19647 a_coordinate(cellId, i)
19648 - mMax(F2 * dn, dn + cellHalfLength) * m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVectorCentroid[i];
19649 }
19650
19651 for(MInt set0 = 0; set0 < m_noLevelSetsUsedForMb; set0++) {
19652 a_associatedBodyIds(ghostCellId, set0) = -1;
19653 }
19654 a_resetPropertiesSolver(ghostCellId);
19655 a_noReconstructionNeighbors(ghostCellId) = 0;
19656 a_level(ghostCellId) = a_level(cellId);
19657
19658 for(MInt var = 0; var < CV->noVariables; var++) {
19659 a_variable(ghostCellId, var) = a_variable(cellId, var);
19660 a_oldVariable(ghostCellId, var) = a_variable(cellId, var);
19661 a_pvariable(ghostCellId, var) = a_pvariable(cellId, var);
19662 for(MInt i = 0; i < nDim; i++)
19663 a_slope(ghostCellId, var, i) = F0;
19664 }
19665
19666 a_bndryId(ghostCellId) = -2;
19667 a_isBndryGhostCell(ghostCellId) = 1;
19668 ASSERT(a_level(ghostCellId) == a_level(getAssociatedInternalCell(ghostCellId)), "");
19669 }
19670 }
19671
19672 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
19673 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
19674 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
19675 // if ( a_hasProperty(cellId, SolverCell::IsNotGradient) ) continue;
19676 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19677 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19678 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
19679 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId < 0)
19680 mTerm(1, AT_, "Ghost cell missing.");
19681 }
19682 for(MInt srfc = 1; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
19683 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId
19684 == m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc - 1]->m_ghostCellId)
19685 mTerm(1, AT_, "Ghost cell duplicate.");
19686 }
19687 }
19688}
19689
19690
19695template <MInt nDim, class SysEqn>
19697 TRACE();
19698
19699 if(noDomains() > 1) {
19700 const MFloat Y0 = F1B2 * (m_bbox[4] + m_bbox[1]);
19701 const MFloat DX = c_cellLengthAtLevel(maxRefinementLevel());
19702 const MInt bodyId = 0;
19703 const MInt noPoints = (MInt)((m_bbox[3] - m_bbox[0]) / DX);
19704 const MInt noAngles = (MInt)(m_bodyDiameter[bodyId] / DX);
19705 const MFloat DA = PI / ((MFloat)noAngles);
19706
19707 ScratchSpace<MFloat> lineData(noPoints, m_noPVars, AT_, "lineData");
19708 ScratchSpace<MFloat> lineCoords(noPoints, nDim, AT_, "lineCoords");
19709 ScratchSpace<MFloat> lineCnt(noPoints, AT_, "lineCnt");
19710 ScratchSpace<MFloat> angleData(noAngles, 3, AT_, "angleData");
19711 ScratchSpace<MFloat> angleCnt(noAngles, AT_, "angleCnt");
19712
19713 lineData.fill(F0);
19714 lineCoords.fill(F0);
19715 lineCnt.fill(F0);
19716 angleData.fill(F0);
19717 angleCnt.fill(F0);
19718 MFloat TfluidMean = F0;
19719 MFloat meanBodyTemp = F0;
19720
19721 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
19722 if(a_isBndryGhostCell(cellId)) continue;
19723 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19724 if(a_isHalo(cellId)) continue;
19725 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19726
19727 MBool isInside = false;
19728 IF_CONSTEXPR(nDim == 2) {
19729 if(fabs(a_coordinate(cellId, 1) - Y0) < c_cellLengthAtCell(cellId)) {
19730 isInside = true;
19731 }
19732 }
19733 IF_CONSTEXPR(nDim == 3) {
19734 const MFloat Z0 = F1B2 * (m_bbox[5] + m_bbox[2]);
19735 if(fabs(a_coordinate(cellId, 1) - Y0) < c_cellLengthAtCell(cellId)
19736 && fabs(a_coordinate(cellId, 2) - Z0) < c_cellLengthAtCell(cellId)) {
19737 isInside = true;
19738 }
19739 }
19740
19741 if(isInside) {
19742 if(fabs(a_coordinate(cellId, 1) - Y0) < c_cellLengthAtCell(cellId)) {
19743 MInt id = (MInt)((a_coordinate(cellId, 0) - m_bbox[0]) / DX);
19744 if(id < 0 || id >= noPoints) {
19745 continue;
19746 // mTerm(1,AT_, "index out of range (line data).");
19747 }
19748 for(MInt i = 0; i < nDim; i++)
19749 lineCoords(id, i) += a_coordinate(cellId, i);
19750 for(MInt i = 0; i < nDim; i++)
19751 lineData(id, i) += a_pvariable(cellId, PV->VV[i]) / m_UInfinity;
19752 lineData(id, nDim) += a_pvariable(cellId, PV->P) / m_PInfinity;
19753 lineData(id, nDim + 1) += a_pvariable(cellId, PV->RHO) / m_rhoInfinity;
19754 lineCnt(id) += F1;
19755 }
19756 }
19757 }
19758
19759 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
19760 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
19761 if(a_isHalo(cellId)) continue;
19762 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
19763 if(m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bodyId[0] != bodyId) continue;
19764 MFloat dx =
19765 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[0] - m_bodyCenter[bodyId * nDim];
19766 // if ( fabs(m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_coordinates[2]) > 0.8*DX ) continue;
19767 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area < 0.001 * m_gridCellArea[maxRefinementLevel()])
19768 continue;
19769 MFloat dr = F0;
19770 IF_CONSTEXPR(nDim == 2) {
19771 dr = sqrt(POW2(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[1]
19772 - m_bodyCenter[bodyId * nDim + 1]));
19773 }
19774 else IF_CONSTEXPR(nDim == 3) {
19775 dr = sqrt(POW2(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[1]
19776 - m_bodyCenter[bodyId * nDim + 1])
19777 + POW2(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[2]
19778 - m_bodyCenter[bodyId * nDim + 2]));
19779 }
19780 MFloat angle = atan2(dr, dx);
19781 MInt id = (MInt)(angle / DA);
19782 if(id < 0 || id >= noAngles) mTerm(1, AT_, "index out of range (angle data): " + to_string(id));
19783 MFloat rhoU2 = F0;
19784 for(MInt i = 0; i < nDim; i++) {
19785 rhoU2 += POW2(m_VVInfinity[i]);
19786 }
19787 rhoU2 *= m_rhoInfinity;
19788 MFloat rhoSurface = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->RHO];
19789 MFloat pSurface = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->P];
19790 MFloat T = sysEqn().temperature_ES(rhoSurface, pSurface);
19791 MFloat cp = (pSurface - m_PInfinity) / (F1B2 * rhoU2);
19792
19793 MFloat shear[3]{};
19794 MFloat mue = SUTHERLANDLAW(T) / sysEqn().m_Re0;
19795 for(MInt i = 0; i < nDim; i++) {
19796 MFloat grad = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[i]];
19797 shear[i] = mue * grad;
19798 }
19799
19800 MFloat cf = sqrt(POW2(shear[0]) + POW2(shear[1]) + POW2(shear[2])) / (F1B2 * rhoU2);
19801 if(m_euler) cf = (a_pvariable(cellId, PV->P) - m_PInfinity) / (F1B2 * rhoU2);
19802
19803 MFloat weight = F1;
19804 angleData(id, 0) += weight * cp;
19805 angleData(id, 1) += weight * cf;
19806 angleData(id, 2) += weight * m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
19807 angleCnt(id) += weight;
19808 }
19809 }
19810
19811 MPI_Allreduce(MPI_IN_PLACE, &lineCoords[0], noPoints * nDim, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
19812 "lineCoords[0]");
19813 MPI_Allreduce(MPI_IN_PLACE, &lineData[0], noPoints * m_noPVars, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
19814 "lineData[0]");
19815 MPI_Allreduce(MPI_IN_PLACE, &lineCnt[0], noPoints, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
19816 "lineCnt[0]");
19817 MPI_Allreduce(MPI_IN_PLACE, &angleData[0], noAngles * 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
19818 "angleData[0]");
19819 MPI_Allreduce(MPI_IN_PLACE, &angleCnt[0], noAngles, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
19820 "angleCnt[0]");
19821
19822 if(domainId() == 0) {
19823 ofstream ofl;
19824 ofl.open(fileName);
19825 if(ofl.is_open() && ofl.good()) {
19826 const MInt maxSkipCnt = IPOW2(maxRefinementLevel() - maxUniformRefinementLevel());
19827 MInt skipCnt = 0;
19828 for(MInt p = 0; p < noPoints; p++) {
19829 if(lineCnt(p) < F1) {
19830 skipCnt++;
19831 if(skipCnt == maxSkipCnt) ofl << endl;
19832 continue;
19833 }
19834 skipCnt = 0;
19835 // ofl << m_bbox[0] + ((MFloat)p)*DX + F1B2*DX;
19836 for(MInt i = 0; i < nDim; i++) {
19837 ofl << " " << lineCoords(p, i) / lineCnt(p);
19838 }
19839 for(MInt i = 0; i < m_noPVars; i++) {
19840 ofl << " " << lineData(p, i) / lineCnt(p);
19841 }
19842 ofl << " " << lineCnt(p) << endl;
19843 }
19844 ofl.close();
19845 ofl.clear();
19846 } else {
19847 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing!" << endl;
19848 }
19849 }
19850 if(domainId() == 1) {
19851 ofstream ofl;
19852 ofl.open("surfaceData");
19853 if(ofl.is_open() && ofl.good()) {
19854 for(MInt p = 0; p < noAngles; p++) {
19855 if(angleCnt(p) < 1e-10) continue;
19856 MFloat angle = PI - (((MFloat)p) * DA + F1B2 * DA);
19857 ofl << angle;
19858 ofl << " " << angleData(p, 0) / angleCnt(p);
19859 ofl << " " << angleData(p, 1) / angleCnt(p);
19860 ofl << " " << angleData(p, 2) / (angleCnt(p) * m_gridCellArea[maxRefinementLevel()]);
19861 ofl << " " << angleCnt(p) << endl;
19862 }
19863 ofl.close();
19864 ofl.clear();
19865 }
19866 if(globalTimeStep == 0) {
19867 ofl.open("surfaceTemp", ios_base::out | ios_base::trunc);
19868 ofl << "# 1:ts 2:t 3:tf 4:Tf 5:Tp" << endl;
19869 } else
19870 ofl.open("surfaceTemp", ios_base::out | ios_base::app);
19871 if(ofl.is_open() && ofl.good()) {
19872 ofl << globalTimeStep << " " << m_time << " " << m_physicalTime // <-- time (1-3)
19873 << " " << setprecision(12) << TfluidMean / m_TInfinity << " " << setprecision(12)
19874 << meanBodyTemp / m_TInfinity // (69-70)
19875 << endl;
19876 ofl.close();
19877 } else {
19878 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing!" << endl;
19879 }
19880 }
19881 } else {
19882 MInt noCells = a_noCells();
19883 // MInt cellId, counter, nghbrId;
19884 ofstream ofl;
19885 MBool centerLine, centerLine2;
19886 MFloat u, v;
19887 ScratchSpace<MFloat> cellIdList(2, noCells, AT_, "cellIdList");
19888 MFloat tmpCellId, tmpCellCoordinate;
19889
19890 MInt counter = 0;
19891 for(MInt cellId = 0; cellId < noCells; cellId++) {
19892 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19893 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19894 if(a_isBndryGhostCell(cellId)) continue;
19895 centerLine = false;
19896 centerLine2 = false;
19897
19898 if(a_coordinate(cellId, 1) >= F0 && a_hasNeighbor(cellId, 2) > 0
19899 && a_coordinate(c_neighborId(cellId, 2), 1) < F0) {
19900 centerLine = true;
19901 // nghbrId = c_neighborId( cellId , 2 );
19902 }
19903 IF_CONSTEXPR(nDim == 2) { centerLine2 = true; }
19904 IF_CONSTEXPR(nDim == 3) {
19905 if(a_coordinate(cellId, 2) >= F0 && a_hasNeighbor(cellId, 4) > 0
19906 && a_coordinate(c_neighborId(cellId, 4), 2) < F0) {
19907 centerLine2 = true;
19908 }
19909 }
19910 if(!centerLine || !centerLine2) continue;
19911
19912 cellIdList(0, counter) = (MFloat)cellId;
19913 cellIdList(1, counter) = a_coordinate(cellId, 0);
19914 counter++;
19915 }
19916
19917 for(MInt c = 0; c < counter; c++) {
19918 for(MInt d = c + 1; d < counter; d++) {
19919 if(cellIdList(1, d) < cellIdList(1, c)) {
19920 tmpCellId = cellIdList(0, c);
19921 tmpCellCoordinate = cellIdList(1, c);
19922 cellIdList(0, c) = cellIdList(0, d);
19923 cellIdList(1, c) = cellIdList(1, d);
19924 cellIdList(0, d) = tmpCellId;
19925 cellIdList(1, d) = tmpCellCoordinate;
19926 }
19927 }
19928 }
19929
19930 ofl.open(fileName);
19931 if(ofl.is_open() && ofl.good()) {
19932 for(MInt c = 0; c < counter; c++) {
19933 MInt cellId = (MInt)cellIdList(0, c);
19934
19935 u = a_variable(cellId, 0) / a_variable(cellId, CV->RHO) - a_coordinate(cellId, 1) * a_slope(cellId, PV->U, 1);
19936 v = a_variable(cellId, 1) / a_variable(cellId, CV->RHO) - a_coordinate(cellId, 1) * a_slope(cellId, PV->V, 1);
19937
19938 IF_CONSTEXPR(nDim == 3) {
19939 u -= a_coordinate(cellId, 2) * a_slope(cellId, PV->U, 2);
19940 v -= a_coordinate(cellId, 2) * a_slope(cellId, PV->V, 2);
19941 }
19942
19943 ofl << a_coordinate(cellId, 0) << " ";
19944 ofl << u / m_UInfinity << " ";
19945 ofl << v / m_UInfinity << " ";
19946 ofl << a_variable(cellId, CV->RHO) << " ";
19947 ofl << a_pvariable(cellId, PV->P) << " ";
19948 ofl << a_variable(cellId, CV->RHO) / m_rhoInfinity << " ";
19949 ofl << a_pvariable(cellId, PV->P) / m_PInfinity << " ";
19950 ofl << endl;
19951 }
19952 ofl.close();
19953 ofl.clear();
19954 } else {
19955 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing!" << endl;
19956 }
19957
19958 MFloat pavg = F0;
19959 MFloat rhoavg = F0;
19960 MFloat uavg = F0;
19961 MFloat cnt = F0;
19962 MFloat pavg2 = F0;
19963 MFloat rhoavg2 = F0;
19964 MFloat uavg2 = F0;
19965 MFloat vol = F0;
19966 MFloat vel = F0;
19967 MFloat temp = F0;
19968 MFloat xsa = F0;
19969 MFloat p0 = F0;
19970 MFloat p00 = F0;
19971 MFloat p00cnt = F0;
19972 const MFloat vs = m_Ma * (m_gamma + F1) / F4 + sqrt(POW2(m_Ma * (m_gamma + F1) / F4) + F1);
19973 const MFloat xs = F1B2 + vs * (m_physicalTime - timeStep());
19974 const MFloat xp = m_Ma * (m_physicalTime - timeStep());
19975
19976 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
19977 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
19978 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
19979 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
19980 if(a_isPeriodic(cellId)) continue;
19981 if(a_isBndryGhostCell(cellId)) continue;
19982 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
19983 if(a_coordinate(cellId, 0) > xp) {
19984 xsa += a_pvariable(cellId, PV->U) * a_cellVolume(cellId);
19985 }
19986 if(a_coordinate(cellId, 0) < xp) {
19987 p0 += a_pvariable(cellId, PV->P) * a_cellVolume(cellId);
19988 if(!checkNeighborActive(cellId, 1) || a_hasNeighbor(cellId, 1) == 0) {
19989 p00 += a_pvariable(cellId, PV->P);
19990 p00cnt += F1;
19991 }
19992 }
19993 if(a_coordinate(cellId, 0) > xp && a_coordinate(cellId, 0) < xs) {
19994 vel += a_cellVolume(cellId) * a_pvariable(cellId, PV->U);
19995 temp +=
19996 a_cellVolume(cellId) * sysEqn().temperature_ES(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
19997 vol += a_cellVolume(cellId);
19998 }
19999 if(a_coordinate(cellId, 0) < xp || a_coordinate(cellId, 0) > xp + 5.0) continue;
20000 pavg += a_pvariable(cellId, PV->P);
20001 rhoavg += a_pvariable(cellId, PV->RHO);
20002 uavg += a_pvariable(cellId, PV->U);
20003 cnt += F1;
20004 if(a_coordinate(cellId, 0) < xp || a_coordinate(cellId, 0) > xp + 2.5) continue;
20005 pavg2 += a_pvariable(cellId, PV->P);
20006 rhoavg2 += a_pvariable(cellId, PV->RHO);
20007 uavg2 += a_pvariable(cellId, PV->U);
20008 }
20009 cerr << "piston front vars: " << setprecision(14) << xp << " " << xs << " "
20010 << timeStep() * m_Ma / c_cellLengthAtLevel(maxRefinementLevel()) << " " << pavg / cnt << " " << rhoavg / cnt
20011 << " "
20012 << uavg / cnt
20013 << " " << vel / mMax(1e-14, vol) << " " << temp / mMax(1e-14, vol) << " " << xp + F1B2 + xsa / (m_Ma * 16.0)
20014 << " " << p0 / 16.0 << " " << p00 / p00cnt << endl;
20015 }
20016}
20017
20018
20023template <MInt nDim, class SysEqn>
20025 TRACE();
20026
20028
20029 for(MInt cellId = 0; cellId < maxNoGridCells(); cellId++) {
20030 for(MInt v = 0; v < m_noFVars; v++) {
20031 m_rhs0[cellId][v] = F0;
20032 }
20033 for(MInt dir = 0; dir < m_noDirs; dir++) {
20034 m_cellSurfaceMapping[cellId][dir] = -1;
20035 }
20036 m_cellVolumesDt1[cellId] = F0;
20037 a_levelSetValuesMb(cellId, 0) = c_cellLengthAtLevel(0);
20038 }
20039
20040 m_initialSurfacesOffset = 0;
20041 m_nearBoundaryBackup.clear();
20042 m_oldBndryCells.clear();
20043
20044 std::map<MInt, std::vector<MFloat>>().swap(m_nearBoundaryBackup);
20045 std::map<MInt, MFloat>().swap(m_oldBndryCells);
20046 std::vector<MInt>().swap(m_bndryCandidateIds);
20047 std::vector<MInt>().swap(m_bndryCandidates);
20048 std::vector<MFloat>().swap(m_candidateNodeValues);
20049 std::vector<MInt>().swap(m_candidateNodeSet);
20050 std::set<MInt>().swap(m_splitSurfaces);
20051 std::vector<CutCandidate<nDim>>().swap(m_cutCandidates);
20052}
20053
20054
20059template <MInt nDim, class SysEqn>
20061 if(m_fvBndryCnd->m_cellCoordinatesCorrected) m_fvBndryCnd->recorrectCellCoordinates();
20062
20063 restoreNeighbourLinks();
20065}
20066
20067
20072template <MInt nDim, class SysEqn>
20074 TRACE();
20075
20076 if(m_deleteNeighbour) {
20077 restoreNeighbourLinks();
20078 }
20079
20080 for(MInt bs = 0; bs < m_fvBndryCnd->m_noBoundarySurfaces; bs++) {
20081 MInt srfcId = m_fvBndryCnd->m_boundarySurfaces[bs];
20082 a_surfaceNghbrCellId(srfcId, 0) = -1;
20083 a_surfaceNghbrCellId(srfcId, 1) = -1;
20084 }
20085 m_fvBndryCnd->m_noBoundarySurfaces = 0;
20086
20087 m_surfaces.size(m_bndrySurfacesOffset);
20088
20089 if(m_fvBndryCnd->m_cellCoordinatesCorrected) m_fvBndryCnd->recorrectCellCoordinates();
20090
20091 set<MInt> tmpSplitSurf(m_splitSurfaces);
20092 m_splitSurfaces.clear();
20093 for(set<MInt>::iterator it = tmpSplitSurf.begin(); it != tmpSplitSurf.end(); ++it) {
20094 MInt srfcId = *it;
20095 deleteSurface(srfcId);
20096 }
20097
20098 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
20099 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
20100 if(a_isBndryGhostCell(cellId) || a_hasProperty(cellId, SolverCell::IsSplitChild)) {
20101 removeSurfaces(cellId);
20102 continue;
20103 }
20104 resetSurfaces(cellId);
20105 for(MInt dir = 0; dir < m_noDirs; dir++) {
20106 m_cutFaceArea[bndryId][dir] = F0;
20107 }
20108 }
20109
20111 m_noLsMbBndryCells = 0;
20112}
20113
20114
20119template <MInt nDim, class SysEqn>
20121 TRACE();
20122
20124
20125 for(MInt cellId = 0; cellId < maxNoGridCells(); cellId++) {
20126 for(MInt dir = 0; dir < m_noDirs; dir++) {
20127 m_cellSurfaceMapping[cellId][dir] = -1;
20128 }
20129 }
20130 m_freeSurfaceIndices.clear();
20131 m_noSurfaces = 0;
20132}
20133
20134
20139template <MInt nDim, class SysEqn>
20141 TRACE();
20142
20143 MInt size;
20144 MInt noCells = m_fvBndryCnd->m_bndryCells->size();
20145
20146 // delete previous moving boundary cells
20147 for(MInt bndryId = noCells - 1; bndryId >= m_noOuterBndryCells; bndryId--) {
20148 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
20149
20150 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
20151 MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
20152 if(ghostCellId > -1) {
20153 ASSERT(a_bndryId(ghostCellId) == -2, "");
20154 a_bndryId(ghostCellId) = -1;
20155 }
20156 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId = -1;
20157 }
20158
20159 a_bndryId(cellId) = -1;
20160
20161 size = m_fvBndryCnd->m_bndryCells->size();
20162 m_fvBndryCnd->m_bndryCells->resetSize(size - 1);
20163
20164 a_hasProperty(cellId, SolverCell::IsSplitCell) = false;
20165 a_hasProperty(cellId, SolverCell::IsSplitChild) = false;
20166 a_hasProperty(cellId, SolverCell::HasSplitFace) = false;
20167 a_hasProperty(cellId, SolverCell::IsTempLinked) = false;
20168 a_hasProperty(cellId, SolverCell::IsMovingBnd) = false;
20169
20170 a_noReconstructionNeighbors(cellId) = 0;
20171 m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.resize(0);
20172 m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst.resize(0);
20173 m_fvBndryCnd->m_bndryCell[bndryId].m_faceVertices.clear();
20174 for(MUint i = 0; i < m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream.size(); i++) {
20175 m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream[i].resize(0);
20176 }
20177 m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream.resize(0);
20178 for(MInt srfc = 0; srfc < FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces; srfc++) {
20179 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.resize(0);
20180 for(MInt v = 0; v < m_noCVars; v++) {
20181 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] = BC_UNSET;
20182 }
20183 }
20184
20185 for(MInt dir = 0; dir < m_noDirs; dir++) {
20186 m_cutFaceArea[bndryId][dir] = F0;
20187 }
20188
20189 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > -1) {
20190 cerr << "linking not expected" << endl;
20191 MInt pm = m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId;
20192 a_cellVolume(pm) = grid().gridCellVolume(a_level(pm));
20193 a_FcellVolume(pm) = F1 / mMax(m_volumeThreshold, a_cellVolume(pm));
20194 m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId = -1;
20195 }
20196 }
20197 m_noLsMbBndryCells = 0;
20198
20199 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
20200 ASSERT(!a_hasProperty(cellId, SolverCell::IsMovingBnd), "");
20201 }
20202}
20203
20204
20209template <MInt nDim, class SysEqn>
20211 TRACE();
20212
20213 // 1. delete neighbour links towards inactive levelset region
20214 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
20215 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
20216
20217 // check all directions for neighbours in inactive levelset region
20218 for(MInt dir = 0; dir < m_noDirs; dir++) {
20219 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && a_hasNeighbor(cellId, dir) > 0) {
20220 const MInt nghbrId = c_neighborId(cellId, dir);
20221 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) {
20222 a_hasProperty(cellId, SolverCell::IsBndryActive) = true;
20223 break;
20224 }
20225 }
20226 }
20227 }
20228 m_deleteNeighbour = true;
20229}
20230
20231
20236template <MInt nDim, class SysEqn>
20238 TRACE();
20239
20240 m_deleteNeighbour = false;
20241 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
20242 a_hasProperty(cellId, SolverCell::IsBndryActive) = false;
20243 }
20244}
20245
20246
20253template <MInt nDim, class SysEqn>
20255 TRACE();
20256
20257 cerr << globalTimeStep << " Calling initializeEmergedCells(), due to Gap-opening " << endl;
20258
20259 MIntScratchSpace nghbrList(150, AT_, "nghbrList");
20260 MIntScratchSpace layerId(150, AT_, "layerList");
20261 MBoolScratchSpace gapCell(a_noCells(), AT_, "gapCell");
20262
20263 // a) mark all cells which were an inactive GapCell
20264 // and are now an active and are not a GapCell anymore!
20265 // CAUTION: this includes BndryGhostCells!
20266 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
20267 gapCell[cellId] = false;
20268 if(m_levelSet && m_closeGaps) {
20269 if(a_hasProperty(cellId, SolverCell::WasGapCell) && !a_hasProperty(cellId, SolverCell::IsGapCell)
20270 && a_hasProperty(cellId, SolverCell::WasInactive) && !a_hasProperty(cellId, SolverCell::IsInactive)) {
20271 gapCell[cellId] = true;
20272
20273 cerr << "initializeEmergedCells: GapCells are " << cellId << " " << c_globalId(cellId) << " bndry-ghostCell "
20274 << a_isBndryGhostCell(cellId) << endl;
20275 }
20276 }
20277 }
20278
20279 // b) labels:FVMB claudia temporary bugfix for initialization of nan outside cells...
20280
20281 // All cells that are active, but were inactive before are initialized!
20282 // Also non-Gap-Cells!
20283 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
20284 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
20285
20286 if(a_isHalo(cellId)) continue;
20287 if(a_isPeriodic(cellId)) continue;
20288 if(!a_hasProperty(cellId, SolverCell::WasInactive)) continue;
20289 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
20290
20291 // resetting all emerging Cells!
20292 cerr << "initializeEmergedCell: resetting Gap-Cells " << cellId << " " << c_globalId(cellId) << endl;
20293
20294 a_variable(cellId, CV->RHO) = m_rhoInfinity;
20295 a_variable(cellId, CV->RHO_E) = m_rhoEInfinity;
20296 a_pvariable(cellId, PV->RHO) = m_rhoInfinity;
20297 a_pvariable(cellId, PV->P) = m_PInfinity;
20298
20299 for(MInt v = 0; v < nDim; v++) {
20300 a_variable(cellId, CV->RHO_VV[v]) = F0;
20301 a_pvariable(cellId, PV->VV[v]) = F0;
20302 }
20303 }
20304
20305 // Initialize all cells newly created in the valve gap
20306 if(m_gapOpened) {
20307 initEmergingGapCells();
20308 }
20309
20310 m_noEmergedCells = 0;
20311 m_noEmergedWindowCells = 0;
20312
20313 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
20314 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
20315 ASSERT(cellId < a_noCells(), "");
20316 if(a_isHalo(cellId)) continue;
20317 if(a_isPeriodic(cellId)) continue;
20318 if(!a_hasProperty(cellId, SolverCell::WasInactive)) continue;
20319 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
20320 m_noEmergedCells++;
20321 if(a_isWindow(cellId)) m_noEmergedWindowCells++;
20322
20323 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) {
20324 for(MInt v = 0; v < m_noCVars; v++) {
20325 a_variable(cellId, v) = F0;
20326 }
20327 for(MInt v = 0; v < m_noPVars; v++) {
20328 a_pvariable(cellId, v) = F0;
20329 }
20330 continue;
20331 }
20332
20333 cerr << "initializeEmergedCell: init Cells " << cellId << " " << c_globalId(cellId) << endl;
20334
20335
20336 if(!gapCell[cellId]) {
20337 MFloatScratchSpace vars(m_noCVars, AT_, "vars");
20338 const MInt counter = this->template getAdjacentLeafCells<2>(cellId, 1, nghbrList, layerId);
20339 MFloat facCnt = F0;
20340 for(MInt v = 0; v < m_noCVars; v++)
20341 vars[v] = F0;
20342
20343 for(MInt n = 0; n < counter; n++) {
20344 MInt nghbrId = nghbrList[n];
20345 if(nghbrId < 0) continue;
20346 if(a_hasProperty(nghbrId, SolverCell::WasInactive)) continue;
20347 MFloat fac = m_cellVolumesDt1[nghbrId];
20348 for(MInt v = 0; v < m_noCVars; v++) {
20349 vars[v] += fac * a_oldVariable(nghbrId, v);
20350 }
20351 facCnt += fac;
20352 }
20353 if(fabs(facCnt) / c_cellLengthAtCell(cellId) > 0.1) {
20354 for(MInt v = 0; v < m_noCVars; v++) {
20355 vars[v] /= facCnt;
20356 a_variable(cellId, v) = vars[v];
20357 }
20358 setPrimitiveVariables(cellId);
20359 } else {
20360 cerr << "Warning cell init " << fabs(facCnt) / c_cellLengthAtCell(cellId) << endl;
20361 if(m_levelSet && m_closeGaps) {
20362 cerr << m_closeGaps << " " << a_hasProperty(cellId, SolverCell::WasGapCell) << " "
20363 << a_hasProperty(cellId, SolverCell::IsGapCell) << " " << a_hasProperty(cellId, SolverCell::WasInactive)
20364 << " " << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
20365 }
20366 a_variable(cellId, CV->RHO) = m_rhoInfinity;
20367 a_variable(cellId, CV->RHO_E) = m_rhoEInfinity;
20368 a_pvariable(cellId, PV->RHO) = m_rhoInfinity;
20369 a_pvariable(cellId, PV->P) = m_PInfinity;
20370 for(MInt v = 0; v < nDim; v++) {
20371 a_variable(cellId, CV->RHO_VV[v]) = F0;
20372 a_pvariable(cellId, PV->VV[v]) = F0;
20373 }
20374 }
20375 MFloat delta = maia::math::deltaFun(m_volumeFraction[bndryId], F0, F1);
20376 for(MInt i = 0; i < nDim; i++) {
20377 a_pvariable(cellId, PV->VV[i]) =
20378 delta * a_pvariable(cellId, PV->VV[i])
20379 + (F1 - delta) * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->VV[i]];
20380 }
20381 }
20382
20383 setConservativeVariables(cellId);
20384
20385 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
20386 MInt splitParent = getAssociatedInternalCell(cellId);
20387 MInt splitParentBndryId = a_bndryId(splitParent);
20388 ASSERT(splitParentBndryId > -1, " this is too bad... split cells inconsistency");
20389 MFloat factor = m_bndryCells->a[bndryId].m_volume / mMax(m_eps, m_bndryCells->a[splitParentBndryId].m_volume);
20390 for(MInt v = 0; v < m_noCVars; v++) {
20391 a_variable(splitParent, v) += factor * a_variable(cellId, v);
20392 }
20393 for(MInt v = 0; v < m_noPVars; v++) {
20394 a_pvariable(splitParent, v) += factor * a_pvariable(cellId, v);
20395 }
20396 }
20397
20398 // CAUTION: this renders the scheme nonconservative!
20399 for(MInt varId = 0; varId < CV->noVariables; varId++) {
20400 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
20401 }
20402 if(m_dualTimeStepping) {
20403 for(MInt varId = 0; varId < CV->noVariables; varId++) {
20404 // a_dt2Variable( cellId , varId ) = a_variable( cellId , varId );
20405 // a_dt1Variable( cellId , varId ) = a_variable( cellId , varId );
20406 }
20407 }
20408 }
20409
20410 if(globalTimeStep > 0) {
20411 MInt globalNoEmerged = m_noEmergedWindowCells + m_gapOpened;
20412 MPI_Allreduce(MPI_IN_PLACE, &globalNoEmerged, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
20413 "globalNoEmerged");
20414 if(globalNoEmerged > 0) {
20415 exchange();
20416 for(MInt i = 0; i < noNeighborDomains(); i++) {
20417 for(MInt j = 0; j < noHaloCells(i); j++) {
20418 setConservativeVariables(haloCellId(i, j));
20419 }
20420 }
20421 }
20422 }
20423
20424 cerr << "initializeEmergedCell: noEmergedCells " << m_noEmergedCells << endl;
20425}
20426
20427
20432template <MInt nDim, class SysEqn>
20434 TRACE();
20435
20436 ASSERT(m_gapOpened, "");
20437
20438 MIntScratchSpace gapCells(m_fvBndryCnd->m_maxNoBndryCells, AT_, "gapCells");
20439 MIntScratchSpace DCells(m_fvBndryCnd->m_maxNoBndryCells, AT_, "DCells");
20440 MIntScratchSpace NCells(m_fvBndryCnd->m_maxNoBndryCells, AT_, "NCells");
20441 MIntScratchSpace NNghbrs(m_fvBndryCnd->m_maxNoBndryCells, AT_, "NNghbrs");
20442 MIntScratchSpace NNghbrs2(m_fvBndryCnd->m_maxNoBndryCells * nDim, AT_, "NNghbrs2");
20443 MFloatScratchSpace NFactors(m_fvBndryCnd->m_maxNoBndryCells * nDim, AT_, "NFactors");
20444 MBoolScratchSpace isGapCell(a_noCells(), AT_, "isGapCell");
20445 MBoolScratchSpace isDCell(a_noCells(), AT_, "isDCell");
20446 MBoolScratchSpace isNCell(a_noCells(), AT_, "isNCell");
20447 MInt noGapCells = 0;
20448 MInt noDCells = 0;
20449 MInt noNCells = 0;
20450 MFloat maxNormal = F0;
20451 MInt normalDir = 0;
20452 MInt noSteps = 100;
20453 MBool NeumannVariante = true;
20454 MFloatScratchSpace tmpVars(m_fvBndryCnd->m_maxNoBndryCells * 2, AT_, "tmpVars");
20455
20456 const MFloat eps = sqrt(nDim) * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
20457
20458 if(domainId() == 0) {
20459 cerr << "Initializing emerging gap cells at time step " << globalTimeStep << endl;
20460 }
20461
20462
20463 // neighbor links are used for FD iteration
20464 restoreNeighbourLinks();
20465
20466 // a) initialisation
20467 for(MInt c = 0; c < a_noCells(); c++) {
20468 isGapCell.p[c] = false;
20469 isDCell.p[c] = false;
20470 isNCell.p[c] = false;
20471 }
20472
20473 // b) Identify gap cells
20474 // in this sense all cells with wasGapCell, !IsGapCell, WasInactive, !IsInactive
20475 // and Ls-value above eps
20476 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
20477 if(a_isBndryGhostCell(cellId)) continue;
20478 if(!a_hasProperty(cellId, SolverCell::WasGapCell)) continue;
20479 if(a_levelSetValuesMb(cellId, 0) < -eps) continue;
20480 if(!a_hasProperty(cellId, SolverCell::IsGapCell) && !a_hasProperty(cellId, SolverCell::IsInactive)
20481 && a_hasProperty(cellId, SolverCell::WasInactive)) {
20482 gapCells.p[noGapCells++] = cellId;
20483 isGapCell.p[cellId] = true;
20484 cerr << "initEmergingGapCell: Gap-CellId" << cellId << " " << c_globalId(cellId) << endl;
20485 }
20486 }
20487
20488 // 2.) Identify neighbor cells, of the Gap-Cells and which hold a boundary conditions
20489 for(MInt c = 0; c < noGapCells; c++) {
20490 MInt cellId = gapCells.p[c];
20491 if(a_isHalo(cellId)) continue;
20492 for(MInt dir = 0; dir < m_noDirs; dir++) {
20493 if(!a_hasNeighbor(cellId, dir)) {
20494 cerr << " [" << domainId() << "]: Error in FvMbCartesianSolverXD::initEmergingGapCells(): no nghbr in dir "
20495 << dir << " found for cell " << cellId << ". Please check! " << endl;
20496 continue;
20497 }
20498 MInt nghbrId = c_neighborId(cellId, dir);
20499 if(isGapCell.p[nghbrId]) continue;
20500 if(isDCell.p[nghbrId]) continue;
20501 if(isNCell.p[nghbrId]) continue;
20502 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
20503 if(a_bndryId(nghbrId) > -1) {
20504 if(!a_hasProperty(nghbrId, SolverCell::WasInactive)) {
20505 // a) cell is a bndryCell and has a valid value from previous time step
20506 // -> dirichlet cell!
20507 isDCell.p[nghbrId] = true;
20508 DCells.p[noDCells++] = nghbrId;
20509 cerr << "initEmergingGapCell: D-CellId" << nghbrId << " " << c_globalId(nghbrId) << endl;
20510
20511
20512 continue;
20513 } else if(a_levelSetValuesMb(nghbrId, 0) < F0) {
20514 // b) cell is a bndryCell and has no valid value from previous time step
20515 // -> neumann cell!
20516 isNCell.p[nghbrId] = true;
20517 NCells.p[noNCells++] = nghbrId;
20518 cerr << "initEmergingGapCell: N-CellId" << nghbrId << " " << c_globalId(nghbrId) << endl;
20519
20520 continue;
20521 } else {
20522 cerr << " [" << domainId() << "]: Warning in FvMbCartesianSolverXD::initEmergingGapCells(): nghbr in dir "
20523 << dir << " with id " << nghbrId << " of cell " << cellId
20524 << " is no Gap cell, no D and no N cell (was inactive, is bndryCell, has levelset >= 0 but is no gap "
20525 "cell)! Please check! "
20526 << endl;
20527 mTerm(1, AT_, "Error 1");
20528 }
20529 } else {
20530 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) {
20531 // c) cell is not a bndryCell but is inactive -> neumann cell!
20532 isNCell.p[nghbrId] = true;
20533 NCells.p[noNCells++] = nghbrId;
20534 cerr << "initEmergingGapCell: N-CellId" << nghbrId << " " << c_globalId(nghbrId) << endl;
20535 continue;
20536 } else {
20537 if(!a_hasProperty(nghbrId, SolverCell::WasInactive)) {
20538 // d) cell is not a bndryCell and is/was active before -> dirichlet cell!
20539 isDCell.p[nghbrId] = true;
20540 DCells.p[noDCells++] = nghbrId;
20541 cerr << "initEmergingGapCell: D-CellId" << nghbrId << " " << c_globalId(nghbrId) << endl;
20542 continue;
20543 } else {
20544 cerr << " [" << domainId() << "]: Warning in FvMbCartesianSolverXD::initEmergingGapCells(): nghbr in dir "
20545 << dir << " with id " << nghbrId << " of cell " << cellId
20546 << " is no Gap cell, no D and no N cell (is active, was inactive, but is no gap cell and no bndry "
20547 "cell! Please check! "
20548 << endl;
20549 mTerm(1, AT_, "Error 2");
20550 }
20551 }
20552 }
20553 }
20554 }
20555
20556
20557 // 3) set up Gap-exchange:
20558 // exchangeWindowCells holds all windowCells that are either a Gap-Cell,
20559 // a Dirichlet Cell or a Neumann-Cell
20560 MIntScratchSpace noExchangeWindowCells(noNeighborDomains(), AT_, "noExchangeWindowCells");
20561 MIntScratchSpace noExchangeHaloCells(noNeighborDomains(), AT_, "noExchangeHaloCells");
20562 MIntScratchSpace exchangeWindowCells(noNeighborDomains(), noGapCells + noDCells + noNCells, AT_,
20563 "exchangeWindowCells");
20564
20565 // a) set noExchangeWindowCells and exchangeWindowCells
20566 for(MInt i = 0; i < noNeighborDomains(); i++) {
20567 noExchangeWindowCells[i] = 0;
20568 for(MInt j = 0; j < noWindowCells(i); j++) {
20569 MInt cellId = windowCellId(i, j);
20570 if(isDCell[cellId] || isNCell[cellId] || isGapCell[cellId]) {
20571 exchangeWindowCells(i, noExchangeWindowCells[i]++) = j;
20572 }
20573 }
20574 }
20575 // b) exchange noExchangeWindowCells to determine maxNoExchangeHaloCells
20576 MPI_Status status;
20577 for(MInt i = 0; i < noNeighborDomains(); i++) {
20578 MPI_Issend(&noExchangeWindowCells.p[i], 1, MPI_INT, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
20579 "noExchangeWindowCells.p[i]");
20580 }
20581 for(MInt i = 0; i < noNeighborDomains(); i++) {
20582 MPI_Recv(&noExchangeHaloCells.p[i], 1, MPI_INT, neighborDomain(i), 0, mpiComm(), &status, AT_,
20583 "noExchangeHaloCells.p[i]");
20584 }
20585 for(MInt i = 0; i < noNeighborDomains(); i++) {
20586 MPI_Wait(&g_mpiRequestMb[i], &status, AT_);
20587 }
20588
20589 MInt maxNoExchangeHaloCells = 0;
20590 for(MInt i = 0; i < noNeighborDomains(); i++) {
20591 if(noExchangeHaloCells[i] > maxNoExchangeHaloCells) maxNoExchangeHaloCells = noExchangeHaloCells[i];
20592 }
20593 MIntScratchSpace exchangeHaloCells(noNeighborDomains(), maxNoExchangeHaloCells, AT_, "exchangeHaloCells");
20594
20595 // c) exchange exchangeWindowCells to determine exchangeHaloCells
20596 for(MInt i = 0; i < noNeighborDomains(); i++) {
20597 for(MInt j = 0; j < noExchangeWindowCells[i]; j++) {
20598 m_sendBuffers[i][j] = exchangeWindowCells(i, j);
20599 }
20600 }
20601 for(MInt i = 0; i < noNeighborDomains(); i++) {
20602 MPI_Issend(m_sendBuffers[i], noExchangeWindowCells[i], MPI_DOUBLE, neighborDomain(i), 0, mpiComm(),
20603 &g_mpiRequestMb[i], AT_, "m_sendBuffers[i]");
20604 }
20605 for(MInt i = 0; i < noNeighborDomains(); i++) {
20606 MPI_Recv(m_receiveBuffers[i], noExchangeHaloCells[i], MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &status, AT_,
20607 "m_receiveBuffers[i]");
20608 }
20609 for(MInt i = 0; i < noNeighborDomains(); i++) {
20610 MPI_Wait(&g_mpiRequestMb[i], &status, AT_);
20611 }
20612 for(MInt i = 0; i < noNeighborDomains(); i++) {
20613 for(MInt j = 0; j < noExchangeHaloCells[i]; j++) {
20614 exchangeHaloCells(i, j) = m_receiveBuffers[i][j];
20615 }
20616 }
20617
20618 // 4.) Setup Boundary conditions with 2 options
20619 // default is NeumannVariante = true;
20620 if(!NeumannVariante) {
20621 for(MInt nc = 0; nc < noNCells; nc++) {
20622 MInt cellId = NCells.p[nc];
20623 if(a_bndryId(cellId) > -1) {
20624 MInt bndryId = a_bndryId(cellId);
20625 maxNormal = F0;
20626 normalDir = -1;
20627 for(MInt d = 0; d < nDim; d++) {
20628 if(abs(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[d]) > maxNormal) {
20629 maxNormal = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[d];
20630 normalDir = 2 * d;
20631 if(maxNormal > F0) normalDir += 1;
20632 maxNormal = abs(maxNormal);
20633 }
20634 }
20635 if(!a_hasNeighbor(cellId, normalDir)) {
20636 cerr << " [" << domainId() << "]:"
20637 << " Error in FvMbCartesianSolverXD::initEmergingGapCells(): no nghbr in primary dir " << normalDir
20638 << " found for cell " << cellId << ". Please check! " << endl;
20639 mTerm(1, AT_, "Error 3");
20640 }
20641 NNghbrs.p[nc] = c_neighborId(cellId, normalDir);
20642 } else {
20643 normalDir = -1;
20644 maxNormal = F0;
20645 for(MInt dir = 0; dir < m_noDirs; dir++) {
20646 if(!a_hasNeighbor(cellId, dir)) {
20647 continue;
20648 }
20649 MInt nghbrId = c_neighborId(cellId, dir);
20650 MInt bndryId = a_bndryId(nghbrId);
20651 if(!isGapCell.p[nghbrId] && !isDCell.p[nghbrId]) continue;
20652 if(bndryId < 0) continue;
20653 for(MInt d = 0; d < nDim; d++) {
20654 if(abs(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[d]) > maxNormal) {
20655 maxNormal = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[d];
20656 normalDir = 2 * d;
20657 if(maxNormal > F0) normalDir += 1;
20658 maxNormal = abs(maxNormal);
20659 }
20660 }
20661 }
20662 NNghbrs.p[nc] = c_neighborId(cellId, normalDir);
20663 if(!a_hasNeighbor(cellId, normalDir)) {
20664 cerr << " [" << domainId() << "]:"
20665 << " Error in FvMbCartesianSolverXD::initEmergingGapCells(): no nghbr in primary dir " << normalDir
20666 << " found for cell " << cellId << ". Please check! " << endl;
20667 mTerm(1, AT_, "Error 4");
20668 }
20669 }
20670 }
20671 } else {
20672 // 4.1) NeumannVariante:
20673 // setUp NNghbrs2 and NFactors
20674 // NNghbrs2 are neighbors of N-Cells
20675 for(MInt nc = 0; nc < noNCells; nc++) {
20676 MInt cellId = NCells.p[nc];
20677 if(a_bndryId(cellId) > -1) {
20678 // a) Neumann-Cells which are boundary-Cells
20679 // (cells which used to be inactive and have a negative Ls-value)
20680 MInt bndryId = a_bndryId(cellId);
20681 for(MInt d = 0; d < nDim; d++) {
20682 normalDir = 2 * d;
20683 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[d] > F0) {
20684 normalDir += 1;
20685 }
20686 ASSERT(a_hasNeighbor(cellId, normalDir), "NCell has no neighbor in normalDir!");
20687 NNghbrs2.p[nc * nDim + d] = c_neighborId(cellId, normalDir);
20688 NFactors.p[nc * nDim + d] = POW2(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[d]);
20689 }
20690 } else {
20691 // b) Neumann-Cells which are non boundary-Cells and are inactive
20692 MFloat nablaAbs = F0;
20693 MFloat nablaPhi[nDim];
20694 for(MInt i = 0; i < nDim; i++) {
20695 nablaPhi[i] = (a_levelSetValuesMb(c_neighborId(cellId, 2 * i), 0)
20696 - a_levelSetValuesMb(c_neighborId(cellId, 2 * i + 1), 0))
20697 / (F2 * c_cellLengthAtLevel(a_level(cellId)));
20698 nablaAbs += POW2(nablaPhi[i]);
20699 }
20700 nablaAbs = sqrt(nablaAbs);
20701 for(MInt i = 0; i < nDim; i++) {
20702 nablaPhi[i] /= nablaAbs;
20703 }
20704 for(MInt d = 0; d < nDim; d++) {
20705 normalDir = 2 * d;
20706 if(nablaPhi[d] > F0) {
20707 normalDir += 1;
20708 }
20709 ASSERT(a_hasNeighbor(cellId, normalDir), "NCell has no neighbor in normalDir!");
20710 NNghbrs2.p[nc * nDim + d] = c_neighborId(cellId, normalDir);
20711 NFactors.p[nc * nDim + d] = POW2(nablaPhi[d]);
20712 }
20713 }
20714 }
20715 }
20716
20717 // 5) check all NNghbrs for NCells in all directions
20718 // these neighbors should be either a NCell, DCell or GapCell
20719 for(MInt nc = 0; nc < noNCells; nc++) {
20720 if(!NeumannVariante) {
20721 MInt cellId = NCells.p[nc];
20722 MInt nghbrId = NNghbrs.p[nc];
20723 if(isNCell.p[nghbrId] || (a_hasProperty(nghbrId, SolverCell::WasInactive) && !isGapCell.p[nghbrId])) {
20724 cerr << " [" << domainId() << "]:"
20725 << " Error in FvMbCartesianSolverXD::initEmergingGapCells(): nghbr " << nghbrId << " found for cell "
20726 << cellId << " is no gap cell and no dirichlet cell. Please check! " << endl;
20727 mTerm(1, AT_, "Error 7");
20728 }
20729 } else if(NeumannVariante) {
20730 MInt cellId = NCells.p[nc];
20731 for(MInt d = 0; d < nDim; d++) {
20732 MInt nghbrId = NNghbrs2.p[nc * nDim + d];
20733 if(!isNCell.p[nghbrId] && !isDCell.p[nghbrId] && !isGapCell.p[nghbrId] && a_levelSetValuesMb(nghbrId, 0) < F0) {
20734 cerr << domainId() << ": Warning NNghbrs2 " << nghbrId << " found for cell " << cellId
20735 << " is no gap cell and no dirichlet cell! " << endl;
20736 if(!a_hasProperty(nghbrId, SolverCell::WasInactive)) {
20737 cerr << " Nghbr was not inactive, so has a valid time history. Setting as Dirichlet cell... " << endl;
20738 isDCell.p[nghbrId] = true;
20739 DCells.p[noDCells++] = nghbrId;
20740 } else {
20741 cerr << " Nghbr was inactive, so problem can not be resolved.. try nevertheless..." << endl;
20742 }
20743 }
20744 }
20745 }
20746 }
20747
20748 // 6) Set velocity in Neumann cells as the bodyVelocity!
20749 for(MInt nc = 0; nc < noNCells; nc++) {
20750 const MInt cellId = NCells.p[nc];
20751 const MInt bodyId = a_associatedBodyIds(cellId, 0);
20752 ASSERT(bodyId >= 0, "associated body Id not matching!");
20753 for(MInt dir = 0; dir < nDim; dir++) {
20754 a_pvariable(cellId, PV->VV[dir]) = m_bodyVelocity[bodyId * nDim + dir];
20755 }
20756 }
20757
20758 MFloatScratchSpace resL2(m_noPVars, FUN_, "resL2");
20759 MFloatScratchSpace resMax(m_noPVars, FUN_, "resMax");
20760 MFloatScratchSpace tmp(m_noPVars, FUN_, "tmp");
20761 MFloat lambdaRelax = 1.2;
20762 MInt backupSteps = noSteps;
20763
20764 // 7) Gauss Seidel over-relaxated and neumann boundary conditions
20765 // loop- so that all Gap-Cells will be reached!
20766 for(MInt step = noSteps; step > 0; step--) {
20767 // a) exchange of pvariables in all Gap-, N-, or D-Cells
20768 for(MInt i = 0; i < noNeighborDomains(); i++) {
20769 MInt sendBufferCounter = 0;
20770 for(MInt j = 0; j < noExchangeWindowCells[i]; j++) {
20771 MInt cellId = windowCellId(i, exchangeWindowCells(i, j));
20772 memcpy((void*)&m_sendBuffers[i][sendBufferCounter], (void*)&a_pvariable(cellId, 0),
20773 m_dataBlockSize * sizeof(MFloat));
20774 sendBufferCounter += m_dataBlockSize;
20775 }
20776 }
20777
20778 for(MInt i = 0; i < noNeighborDomains(); i++) {
20779 MInt bufSize = noExchangeWindowCells[i] * m_dataBlockSize;
20780 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
20781 "m_sendBuffers[i]");
20782 }
20783
20784 for(MInt i = 0; i < noNeighborDomains(); i++) {
20785 MInt bufSize = noExchangeHaloCells[i] * m_dataBlockSize;
20786 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &status, AT_,
20787 "m_receiveBuffers[i]");
20788 }
20789 for(MInt i = 0; i < noNeighborDomains(); i++) {
20790 MPI_Wait(&g_mpiRequestMb[i], &status, AT_);
20791 }
20792
20793 for(MInt i = 0; i < noNeighborDomains(); i++) {
20794 MInt receiveBufferCounter = 0;
20795 for(MInt j = 0; j < noExchangeHaloCells[i]; j++) {
20796 MInt cellId = haloCellId(i, exchangeHaloCells(i, j));
20797 memcpy((void*)&a_pvariable(cellId, 0), (void*)&m_receiveBuffers[i][receiveBufferCounter],
20798 m_dataBlockSize * sizeof(MFloat));
20799 receiveBufferCounter += m_dataBlockSize;
20800 }
20801 }
20802
20803 for(MInt var = 0; var < m_noPVars; var++) {
20804 resL2[var] = F0;
20805 resMax[var] = F0;
20806 }
20807
20808
20809 // b) update variables in alle N-Cells based on the variables in NNghbrs2
20810 if(!NeumannVariante) {
20811 for(MInt n = 0; n < noNCells; n++) {
20812 MInt cellId = NCells.p[n];
20813 MInt nghbrId = NNghbrs.p[n];
20814 a_pvariable(cellId, PV->RHO) = a_pvariable(nghbrId, PV->RHO);
20815 a_pvariable(cellId, PV->P) = a_pvariable(nghbrId, PV->P);
20816 }
20817 } else {
20818 // NeumannVariante
20819 for(MInt n = 0; n < noNCells; n++) {
20820 tmpVars.p[n * 2 + 0] = F0;
20821 tmpVars.p[n * 2 + 1] = F0;
20822 for(MInt d = 0; d < nDim; d++) {
20823 MInt nghbrId = NNghbrs2.p[n * nDim + d];
20824 tmpVars.p[n * 2 + 0] += a_pvariable(nghbrId, PV->RHO) * NFactors.p[n * nDim + d];
20825 tmpVars.p[n * 2 + 1] += a_pvariable(nghbrId, PV->P) * NFactors.p[n * nDim + d];
20826 }
20827 }
20828 for(MInt n = 0; n < noNCells; n++) {
20829 MInt cellId = NCells.p[n];
20830 a_pvariable(cellId, PV->RHO) = tmpVars.p[n * 2 + 0];
20831 a_pvariable(cellId, PV->P) = tmpVars.p[n * 2 + 1];
20832 }
20833 }
20834
20835
20836 // c) update variables for all gap cells
20837 for(MInt g = 0; g < noGapCells; g++) {
20838 MInt cellId = gapCells.p[g];
20839 if(a_isHalo(cellId)) continue;
20840 for(MInt var = 0; var < m_noPVars; var++) {
20841 tmp[var] = a_pvariable(cellId, var);
20842 a_pvariable(cellId, var) = F0;
20843 }
20844 for(MInt dir = 0; dir < m_noDirs; dir++) {
20845 MInt nghbrId = c_neighborId(cellId, dir);
20846 for(MInt var = 0; var < m_noPVars; var++) {
20847 a_pvariable(cellId, var) += a_pvariable(nghbrId, var) / m_noDirs;
20848 }
20849 }
20850 for(MInt var = 0; var < m_noPVars; var++) {
20851 a_pvariable(cellId, var) = (F1 - lambdaRelax) * tmp[var] + lambdaRelax * a_pvariable(cellId, var);
20852 resL2[var] += POW2(a_pvariable(cellId, var) - tmp[var]);
20853 resMax[var] = mMax(resMax[var], fabs(a_pvariable(cellId, var) - tmp[var]));
20854 }
20855 }
20856
20857 for(MInt var = 0; var < m_noPVars; var++) {
20858 resL2[var] = sqrt(resL2[var]);
20859 }
20860
20861 if((backupSteps - step) % (backupSteps / 10) == 0) {
20862 m_log << " * " << 100 * (backupSteps - step) / backupSteps << " % - residual (L2) rho: " << resL2[PV->RHO]
20863 << " - residual (max) rho: " << resMax[PV->RHO] << endl;
20864 }
20865 }
20866
20867 m_log << " * "
20868 << "100"
20869 << " % - residual (L2) rho: " << resL2[PV->RHO] << " - residual (max) rho: " << resMax[PV->RHO] << endl;
20870
20871 for(MInt i = 0; i < noNeighborDomains(); i++) {
20872 MInt sendBufferCounter = 0;
20873 for(MInt j = 0; j < noExchangeWindowCells[i]; j++) {
20874 MInt cellId = windowCellId(i, exchangeWindowCells(i, j));
20875 memcpy((void*)&m_sendBuffers[i][sendBufferCounter], (void*)&a_pvariable(cellId, 0),
20876 m_dataBlockSize * sizeof(MFloat));
20877 sendBufferCounter += m_dataBlockSize;
20878 }
20879 }
20880
20881 for(MInt i = 0; i < noNeighborDomains(); i++) {
20882 MInt bufSize = noExchangeWindowCells[i] * m_dataBlockSize;
20883 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
20884 "m_sendBuffers[i]");
20885 }
20886
20887 for(MInt i = 0; i < noNeighborDomains(); i++) {
20888 MInt bufSize = noExchangeHaloCells[i] * m_dataBlockSize;
20889 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &status, AT_,
20890 "m_receiveBuffers[i]");
20891 }
20892 for(MInt i = 0; i < noNeighborDomains(); i++) {
20893 MPI_Wait(&g_mpiRequestMb[i], &status, AT_);
20894 }
20895
20896 for(MInt i = 0; i < noNeighborDomains(); i++) {
20897 MInt receiveBufferCounter = 0;
20898 for(MInt j = 0; j < noExchangeHaloCells[i]; j++) {
20899 MInt cellId = haloCellId(i, exchangeHaloCells(i, j));
20900 memcpy((void*)&a_pvariable(cellId, 0), (void*)&m_receiveBuffers[i][receiveBufferCounter],
20901 m_dataBlockSize * sizeof(MFloat));
20902 receiveBufferCounter += m_dataBlockSize;
20903 }
20904 }
20905
20906 // restore the correct neighboring information for further MB computation
20907 deleteNeighbourLinks();
20908
20909 for(MInt g = 0; g < noGapCells; g++) {
20910 MInt cellId = gapCells.p[g];
20911
20912 setConservativeVariables(cellId);
20913
20914 for(MInt varId = 0; varId < CV->noVariables; varId++) {
20915 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
20916 }
20917
20918 if(m_dualTimeStepping) {
20919 for(MInt varId = 0; varId < CV->noVariables; varId++) {
20920 a_dt2Variable(cellId, varId) = a_variable(cellId, varId);
20921 a_dt1Variable(cellId, varId) = a_variable(cellId, varId);
20922 }
20923 }
20924
20925 if(c_isLeafCell(cellId)) {
20926 a_hasProperty(cellId, SolverCell::IsFlux) = true;
20927 a_hasProperty(cellId, SolverCell::IsActive) = true;
20928 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = true;
20929 }
20930 }
20931}
20932
20933
20934/*
20935 * \brief generates finite-volume (not-moving) boundary cells
20936 *
20937 * \author Lennart Schneiders
20938 * \date 01/2012
20939 */
20940template <MInt nDim, class SysEqn>
20942 TRACE();
20943
20944 m_log << "Generating FV boundary cells..." << endl;
20945
20946 if(m_generateOuterBndryCells) {
20947 // reset isActive/isInactive and isOnCurrentMGLevel for outerBndryCells:
20948 // if the lsValue is in the range of (-limitDistance , 0] and the cell has at least
20949 // one active corner
20950 if(!m_constructGField) {
20951 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
20952 const MFloat limitDistance = c_cellLengthAtLevel(a_level(cellId) + 1) * sqrt(nDim) + 0.0001;
20953 if(a_levelSetValuesMb(cellId, 0) < F0 && a_levelSetValuesMb(cellId, 0) > -limitDistance) {
20954 // check that it is a cell at the outer-domainBoundary
20955 // which means that neither the cell nor its parent has a neighbor in a certain direction!
20956 // and the cell is not a halo cell!
20957 MBool needsCheck = false;
20958 for(MInt dir = 0; dir < m_noDirs; dir++) {
20959 if(a_hasNeighbor(cellId, dir, false)) continue;
20960 if(c_parentId(cellId) > -1 && a_hasNeighbor(c_parentId(cellId), dir, false)) continue;
20961 needsCheck = true;
20962 break;
20963 }
20964 if(!needsCheck) continue;
20965 MInt noActiveCorners = returnNoActiveCorners(cellId);
20966 if(noActiveCorners > 0) {
20967 a_hasProperty(cellId, SolverCell::IsInactive) = false;
20968 if(c_noChildren(cellId) == 0 && c_isLeafCell(cellId)) {
20969 a_hasProperty(cellId, SolverCell::IsActive) = true;
20970 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = true;
20971 }
20972 }
20973 }
20974 }
20975
20976 // exchange the properties to ensure the correct values at all haloCells!
20977 MIntScratchSpace exchangeD(a_noCells(), 3, AT_, "cellCheck");
20978 exchangeD.fill(-1);
20979 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
20980 exchangeD(cellId, 0) = (MInt)a_hasProperty(cellId, SolverCell::IsInactive);
20981 exchangeD(cellId, 1) = (MInt)a_hasProperty(cellId, SolverCell::IsActive);
20982 exchangeD(cellId, 2) = (MInt)a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel);
20983 }
20984
20985 exchangeDataFV(&exchangeD(0), 3, false);
20986
20987 for(MInt cellId = noInternalCells(); cellId < c_noCells(); cellId++) {
20988 a_hasProperty(cellId, SolverCell::IsInactive) = (MBool)exchangeD(cellId, 0);
20989 a_hasProperty(cellId, SolverCell::IsActive) = (MBool)exchangeD(cellId, 1);
20990 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = (MBool)exchangeD(cellId, 2);
20991 }
20992
20993 if(grid().azimuthalPeriodicity()) {
20994 // Correct azimuthal near boundary cells. Azimuthal window/halos are no exact copy
20995 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
20996 for(MInt j = 0; j < grid().noAzimuthalHaloCells(i); j++) {
20997 MInt cellId = grid().azimuthalHaloCell(i, j);
20998 const MFloat limitDistance = c_cellLengthAtLevel(a_level(cellId) + 1) * sqrt(nDim) + 0.0001;
20999 if(a_levelSetValuesMb(cellId, 0) < F0 && a_levelSetValuesMb(cellId, 0) > -limitDistance) {
21000 // check that it is a cell at the outer-domainBoundary
21001 // which means that neither the cell nor its parent has a neighbor in a certain direction!
21002 // and the cell is not a halo cell!
21003 MBool needsCheck = false;
21004 for(MInt dir = 0; dir < m_noDirs; dir++) {
21005 if(a_hasNeighbor(cellId, dir, false)) continue;
21006 if(c_parentId(cellId) > -1 && a_hasNeighbor(c_parentId(cellId), dir, false)) continue;
21007 needsCheck = true;
21008 break;
21009 }
21010 if(!needsCheck) continue;
21011 MInt noActiveCorners = returnNoActiveCorners(cellId);
21012 if(noActiveCorners > 0) {
21013 a_hasProperty(cellId, SolverCell::IsInactive) = false;
21014 if(c_noChildren(cellId) == 0 && c_isLeafCell(cellId)) {
21015 a_hasProperty(cellId, SolverCell::IsActive) = true;
21016 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = true;
21017 }
21018 }
21019 }
21020 }
21021 }
21022 // What about unmapped halos?
21023 // They are irrelevant in fvMb if level-set boundaries are used!
21024 }
21025 }
21026
21027 createBoundaryCells();
21028
21029 m_fvBndryCnd->generateBndryCells();
21030
21031 ASSERT(a_noCells() == c_noCells(), "");
21032 }
21033
21034#if defined _MB_DEBUG_ || !defined NDEBUG
21035 MInt noOuterBoundaryCells = m_fvBndryCnd->m_bndryCells->size();
21036 m_log << noOuterBoundaryCells << " boundary cells created" << endl;
21037 MPI_Allreduce(MPI_IN_PLACE, &noOuterBoundaryCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
21038 "noOuterBoundaryCells");
21039 cerr0 << "No of outer-boundary-Cells: " << noOuterBoundaryCells << endl;
21040
21041#endif
21042}
21043
21044
21051template <MInt nDim, class SysEqn>
21053 TRACE();
21054
21055 MInt nghbrIds[m_noCorners];
21056 MFloat lsValues[m_noCorners];
21057 MInt noActiveCorners = 0;
21058 const MInt nodeStencil[3][8] = {{0, 1, 0, 1, 0, 1, 0, 1}, {2, 2, 3, 3, 2, 2, 3, 3}, {4, 4, 4, 4, 5, 5, 5, 5}};
21059 std::set<std::pair<MInt, MInt>> nghbrSet;
21060
21061 for(MInt node = 0; node < m_noCorners; node++) {
21062 // a) Add all neighbors and the corresponding nodes from the node-loop to the list
21063 nghbrSet.clear();
21064 nghbrSet.insert(std::make_pair(cellId, node));
21065
21066 for(MInt i = 0; i < nDim; i++) {
21067 MInt firstDir = nodeStencil[i][node];
21068 MInt firstNghbrId = c_neighborId(cellId, firstDir);
21069 if(firstNghbrId > -1) {
21070 nghbrSet.insert(make_pair(firstNghbrId, node));
21071 for(MInt j = 0; j < nDim; j++) {
21072 MInt secondDir = nodeStencil[j][node];
21073 if(secondDir == firstDir) continue;
21074 MInt secondNghbrId = c_neighborId(firstNghbrId, secondDir);
21075 if(secondNghbrId > -1) {
21076 nghbrSet.insert(make_pair(secondNghbrId, node));
21077 IF_CONSTEXPR(nDim == 3) {
21078 for(MInt k = 0; k < nDim; k++) {
21079 MInt thirdDir = nodeStencil[k][node];
21080 if(thirdDir == firstDir || thirdDir == secondDir) continue;
21081 MInt thirdNghbrId = c_neighborId(secondNghbrId, thirdDir);
21082 if(thirdNghbrId > -1) {
21083 nghbrSet.insert(make_pair(thirdNghbrId, node));
21084 }
21085 }
21086 }
21087 }
21088 }
21089 }
21090 }
21091
21092 // b) reorder list by nodes, and calculate noNeighborsPerNode
21093 // note: previously determined neighbors might be added multiple-times to the map
21094 // and overwrite existing and identical information...
21095 MInt noNeighborsPerNode = 0;
21096 for(const auto& it : nghbrSet) {
21097 nghbrIds[noNeighborsPerNode] = it.first;
21098 noNeighborsPerNode++;
21099 }
21100
21101 // c) interpolate the levelSet value at the node, based on the levelSet values at
21102 // the neighboring cell-centers
21103 MFloat phi = F0;
21104 for(MInt nghbrNode = 0; nghbrNode < noNeighborsPerNode; nghbrNode++) {
21105 phi += a_levelSetValuesMb(nghbrIds[nghbrNode], 0);
21106 }
21107 phi /= noNeighborsPerNode;
21108 lsValues[node] = phi;
21109 }
21110
21111 // d) return the number of active notes
21112 for(MInt node = 0; node < m_noCorners; node++) {
21113 if(lsValues[node] > F0) {
21114 noActiveCorners++;
21115 }
21116 }
21117 ASSERT(noActiveCorners >= 0 && noActiveCorners <= m_noCorners, " ");
21118
21119 return noActiveCorners;
21120}
21121
21122
21127template <MInt nDim, class SysEqn>
21129 TRACE();
21130
21131 const MInt noSrfcs = a_noSurfaces();
21132
21133 for(MInt s = m_bndrySurfacesOffset; s < noSrfcs; s++) {
21134 for(MInt i = 0; i < nDim; i++) {
21135 a_surfaceDeltaX(s, i) = a_surfaceCoordinate(s, i) - a_coordinate(a_surfaceNghbrCellId(s, 0), i);
21136 a_surfaceDeltaX(s, nDim + i) = a_surfaceCoordinate(s, i) - a_coordinate(a_surfaceNghbrCellId(s, 1), i);
21137 }
21138 }
21139}
21140
21141
21146template <MInt nDim, class SysEqn>
21148 MFloat fac0 = F0;
21149 MFloat fac1 = F0;
21150
21151 for(MInt i = 0; i < nDim; i++) {
21152 a_surfaceDeltaX(srfcId, i) = a_surfaceCoordinate(srfcId, i) - a_coordinate(a_surfaceNghbrCellId(srfcId, 0), i);
21153 a_surfaceDeltaX(srfcId, nDim + i) =
21154 a_surfaceCoordinate(srfcId, i) - a_coordinate(a_surfaceNghbrCellId(srfcId, 1), i);
21155 fac0 += POW2(a_surfaceDeltaX(srfcId, i));
21156 fac1 += POW2(a_surfaceDeltaX(srfcId, nDim + i));
21157 }
21158 fac0 = sqrt(fac0);
21159 fac1 = sqrt(fac1);
21160 IF_CONSTEXPR(nDim == 3) { // TODO_rmxd labels:FVMB
21161 a_surfaceFactor(srfcId, 0) = fac1 / (fac0 + fac1);
21162 a_surfaceFactor(srfcId, 1) = F1 - a_surfaceFactor(srfcId, 0);
21163 }
21164}
21165
21166
21167template <MInt nDim, class SysEqn>
21169 ASSERT(exId > -1 && exId < m_extractedCells->size() && node > -1 && node < IPOW2(nDim), "");
21170
21171 MInt cellId = m_extractedCells->a[exId].m_cellId;
21172 MInt bndryId = a_bndryId(cellId);
21173 if(bndryId < 0) return false;
21174
21175 if(bndryId < m_noOuterBndryCells) {
21177 } else {
21178 return m_pointIsInside[bndryId][IDX_LSSETMB(node, 0)];
21179 }
21180}
21181
21182
21187template <MInt nDim, class SysEqn>
21189 cerr << "FvMbCartesianSolverXD::computeForceCoefficients(..) is empty. " << forceCoefficients[0] << endl;
21190}
21191
21192
21197template <MInt nDim, class SysEqn>
21199 TRACE();
21200
21201 MInt noCells = m_fvBndryCnd->m_bndryCells->size();
21202 MFloat epsilon = pow(10.0, -13.0);
21203 m_fvBndryCnd->m_noBoundarySurfaces = m_noOuterBoundarySurfaces;
21204
21205 for(MInt bndryId = m_noOuterBndryCells; bndryId < noCells; bndryId++) {
21206 for(MInt srfc = 0; srfc < FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces; srfc++) {
21207 for(MInt i = 0; i < nDim; i++) {
21208 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = -1;
21209 }
21210 }
21211 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
21212
21213 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21214 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
21215 if(a_isHalo(cellId)) continue;
21216 if(a_isPeriodic(cellId)) continue;
21217
21218 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > -1) {
21219 cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId;
21220 }
21221
21222 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
21223 const MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
21224 if(a_hasProperty(cellId, SolverCell::IsSplitChild)
21225 || (c_noChildren(cellId) == 0 && a_level(cellId) <= maxRefinementLevel())
21226 || (c_noChildren(cellId) > 0 && a_level(cellId) == maxRefinementLevel())) {
21227 // create one surface per space direction
21228 for(MInt i = 0; i < nDim; i++) {
21229 // if the surface is inclined, replace it by its projections
21230 // into the Cartesian frame of reference
21231 if(fabs(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]) > epsilon) {
21232 m_surfaces.append();
21233 const MInt srfcId = a_noSurfaces() - 1;
21234
21235 // add the boundary surface
21236 m_fvBndryCnd->m_boundarySurfaces[m_fvBndryCnd->m_noBoundarySurfaces] = srfcId;
21237 m_fvBndryCnd->m_noBoundarySurfaces++;
21238
21239 // set the boundary condition
21240 a_surfaceBndryCndId(srfcId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId;
21241
21242 // the coordinates of the new surface are shifted...
21243 for(MInt j = 0; j < nDim; j++) {
21244 a_surfaceCoordinate(srfcId, j) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[j];
21245 }
21246
21247 // projection to compute the area of the surface
21248 a_surfaceArea(srfcId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area
21249 * fabs(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]);
21250
21251 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = srfcId;
21252
21253 if(a_surfaceArea(srfcId) < F0) {
21254 cerr << "Warning: negative surface area of surface " << srfcId << " at time step " << globalTimeStep
21255 << " !!!!!!" << endl;
21256 }
21257
21258 // set the surface orientation
21259 a_surfaceOrientation(srfcId) = i;
21260 a_surfaceUpwindCoefficient(srfcId) = m_globalUpwindCoefficient;
21261
21262 MFloat dn = F0;
21263 for(MInt k = 0; k < nDim; k++) {
21264 dn +=
21265 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[k]
21266 * (a_coordinate(cellId, k) - m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[k]);
21267 }
21268
21269 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i] > F0) {
21270 a_surfaceNghbrCellId(srfcId, 0) = ghostCellId;
21271 a_surfaceNghbrCellId(srfcId, 1) = cellId;
21272 a_surfaceFactor(srfcId, 0) = F1B2; // don't modify, crucial for accurate fluid-structure coupling!
21273 a_surfaceFactor(srfcId, 1) = F1B2;
21274 } else {
21275 a_surfaceNghbrCellId(srfcId, 1) = ghostCellId;
21276 a_surfaceNghbrCellId(srfcId, 0) = cellId;
21277 a_surfaceFactor(srfcId, 1) = F1B2;
21278 a_surfaceFactor(srfcId, 0) = F1B2;
21279 }
21280
21281 for(MInt k = 0; k < nDim; k++) {
21282 a_surfaceDeltaX(srfcId, k) =
21283 a_surfaceCoordinate(srfcId, k) - a_coordinate(a_surfaceNghbrCellId(srfcId, 0), k);
21284 a_surfaceDeltaX(srfcId, nDim + k) =
21285 a_surfaceCoordinate(srfcId, k) - a_coordinate(a_surfaceNghbrCellId(srfcId, 1), k);
21286 }
21287 }
21288 }
21289 }
21290 }
21291 }
21292}
21293
21294
21299template <MInt nDim, class SysEqn>
21301 TRACE();
21302
21303 std::fill(&a_slope(0, 0, 0), &a_slope(0, 0, 0) + a_noCells() * m_noPVars * nDim, F0);
21304}
21305
21306
21311template <MInt nDim, class SysEqn>
21313 TRACE();
21314
21315 leastSquaresReconstruction();
21316}
21317
21318
21323template <MInt nDim, class SysEqn>
21325 TRACE();
21326
21327 ScratchSpace<MInt> globalSignal(1, AT_, "globalSignal");
21328 globalSignal.p[0] = signal;
21329 MPI_Bcast(globalSignal.getPointer(), 1, MPI_INT, sender, mpiComm(), AT_, "globalSignal.getPointer()");
21330
21331 return globalSignal.p[0];
21332}
21333
21334
21340template <MInt nDim, class SysEqn>
21341void FvMbCartesianSolverXD<nDim, SysEqn>::saveSolverSolution(MBool forceOutput, const MBool NotUsed(finalTimeStep)) {
21342 TRACE();
21343
21344
21345 if(m_engineSetup && m_solutionInterval > 0) {
21346 crankAngleSolutionOutput();
21347 }
21348
21349 MBool& firstRun = m_static_saveSolverSolutionxd_firstRun;
21350 if(m_restartFile) firstRun = false;
21351
21352 if(m_bodySamplingInterval > 0 && globalTimeStep % m_bodySamplingInterval == 0) {
21353 saveBodySamples();
21354 }
21355 if(m_particleSamplingInterval > 0 && globalTimeStep % m_particleSamplingInterval == 0) {
21356 saveParticleSamples();
21357 }
21358
21359 // Taylor Green vortex or DHIT
21360 if(m_initialCondition == 15 || m_initialCondition == 16) {
21361 computeFlowStatistics(false);
21362 }
21363
21364 if((m_dragOutputInterval > 0) && (globalTimeStep % m_dragOutputInterval) == 0 && m_noEmbeddedBodies > 0) {
21365 if(m_writeCenterLineData) {
21366 MString fileName = "centerLineData_" + to_string(globalTimeStep);
21367 writeCenterLineVel(fileName.c_str());
21368 }
21369
21370 MFloat bodyRotation[3] = {F0, F0, F0};
21371 MFloatScratchSpace pressureForce(mMax(1, nDim * m_noEmbeddedBodies), AT_, "pressureForce");
21372 getBodyRotation(0, bodyRotation);
21373 computeBodySurfaceData(&pressureForce[0]);
21374 printDynamicCoefficients(firstRun, &pressureForce[0]);
21375 if(m_recordBodyData) recordBodyData(firstRun);
21376 }
21377 // solution output
21378 MInt noComputedTimeSteps = globalTimeStep - m_solutionOffset;
21379 if(((noComputedTimeSteps % m_solutionInterval) == 0 && globalTimeStep >= m_solutionOffset && m_solutionInterval > -1)
21380 || forceOutput || (m_solutionTimeSteps.count(globalTimeStep) > 0)) {
21381 writeVtkXmlFiles("QOUT", "GEOM", !forceOutput, m_solutionDiverged);
21382 if(string2enum(m_outputFormat) == NETCDF) {
21383 mTerm(1, AT_, "NETCDF output not defined, see FvMbCartesianSolverXD::saveGridFlowVariablesMB");
21384 }
21385 }
21386
21387 firstRun = false;
21388}
21389
21390
21391template <MInt nDim, class SysEqn>
21393 TRACE();
21394
21395 // only the coefficient of the first body will be printed here.
21396 MInt bodyId = 0;
21397 MFloat forceCoeffs[3] = {F0, F0, F0};
21398 MFloat pressureForceCoeffs[3] = {F0, F0, F0};
21399 MFloat momentCoeffs[3] = {F0, F0, F0};
21400 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
21401 forceCoeffs[spaceId] = m_hydroForce[bodyId * nDim + spaceId] / (F1B2 * m_rhoU2);
21402 IF_CONSTEXPR(nDim == 2) {
21403 forceCoeffs[spaceId] /= m_bodyDiameter[bodyId];
21404 pressureForceCoeffs[spaceId] = pressureForce[bodyId * nDim + spaceId] / m_bodyDiameter[bodyId];
21405 }
21406 else IF_CONSTEXPR(nDim == 3) {
21407 forceCoeffs[spaceId] /= PI * POW2(F1B2 * m_bodyDiameter[bodyId]);
21408 pressureForceCoeffs[spaceId] =
21409 pressureForce[bodyId * nDim + spaceId] / (PI * POW2(F1B2 * m_bodyDiameter[bodyId]));
21410 }
21411 }
21412 for(MInt i = 0; i < 3; i++) {
21413 momentCoeffs[i] = m_bodyTorque[bodyId * 3 + i] / (F1B2 * m_rhoU2);
21414 IF_CONSTEXPR(nDim == 2) { momentCoeffs[i] /= m_bodyDiameter[bodyId]; }
21415 else IF_CONSTEXPR(nDim == 3) {
21416 momentCoeffs[i] /= PI * POW3(F1B2 * m_bodyDiameter[bodyId]);
21417 }
21418 }
21419
21420 MString surname;
21421 if(!m_multipleFvSolver) {
21422 surname = "forceCoef";
21423 } else {
21424 surname = "forceCoef_s" + to_string(solverId());
21425 }
21426
21427 ofstream ofl;
21428 if(domainId() == 0) {
21429 if(firstRun && globalTimeStep <= m_dragOutputInterval) {
21430 MString surnameBAK = surname + "_BAK";
21431 MString surnameBAK0 = surname + "_BAK0";
21432 MString surnameBAK1 = surname + "_BAK1";
21433 MString surnameBAK2 = surname + "_BAK2";
21434 rename(surnameBAK1.c_str(), surnameBAK2.c_str());
21435 rename(surnameBAK0.c_str(), surnameBAK1.c_str());
21436 rename(surnameBAK.c_str(), surnameBAK0.c_str());
21437 rename(surname.c_str(), surnameBAK.c_str());
21438 ofl.open(surname.c_str(), ios_base::out | ios_base::trunc);
21439 ofl << "# Header valid for nDim = 3" << endl;
21440 ofl << "#1:ts 2:tf 3:t 4-6:forceCoeffs 7-9:momentCoeffs 10-12:pressureForceCoeffs";
21441 ofl << endl;
21442 } else {
21443 ofl.open(surname.c_str(), ios_base::out | ios_base::app);
21444 }
21445 if(ofl.is_open() && ofl.good()) {
21446 ofl << setprecision(8) << globalTimeStep << " " << m_physicalTime << " " << m_time << " ";
21447 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
21448 ofl << forceCoeffs[spaceId] << " ";
21449 }
21450 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
21451 ofl << momentCoeffs[spaceId] << " ";
21452 }
21453 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
21454 ofl << pressureForceCoeffs[spaceId] << " ";
21455 }
21456 ofl << endl;
21457 ofl.close();
21458 }
21459 }
21460}
21461
21462template <MInt nDim, class SysEqn>
21464 TRACE();
21465 ofstream ofl;
21466
21467 MString surname;
21468 if(!m_multipleFvSolver) {
21469 surname = "bodyPosition";
21470 } else {
21471 surname = "bodyPosition_s" + to_string(solverId());
21472 }
21473
21474 if(domainId() == 0) {
21475 if(firstRun && globalTimeStep <= m_dragOutputInterval) {
21476 MString surnameBAK = surname + "_BAK";
21477 MString surnameBAK0 = surname + "_BAK0";
21478 MString surnameBAK1 = surname + "_BAK1";
21479 MString surnameBAK2 = surname + "_BAK2";
21480 rename(surnameBAK1.c_str(), surnameBAK2.c_str());
21481 rename(surnameBAK0.c_str(), surnameBAK1.c_str());
21482 rename(surnameBAK.c_str(), surnameBAK0.c_str());
21483 rename(surname.c_str(), surnameBAK.c_str());
21484 ofl.open(surname.c_str(), ios_base::out | ios_base::trunc);
21485 ofl << "# 1:ts 2:tf 3:t 4-6:bodyCenter 7-9:bodyVelocity 10-12:bodyOrientation 13-15: bodyAngularVelocity";
21486 ofl << endl;
21487 ofl << "# For more than 2 bodies, the output is performed for the first two bodies" << endl;
21488 ofl << "# (>2bodies) 16-18:bodyCenter 19-21:bodyVelocity 22-24:bodyOrientation 25-27: bodyAngularVelocity";
21489 ofl << endl;
21490 } else {
21491 ofl.open(surname.c_str(), ios_base::out | ios_base::app);
21492 }
21493 if(ofl.is_open() && ofl.good()) {
21494 ofl << setprecision(8) << globalTimeStep << " " << m_physicalTime << " " << m_time << " ";
21495 MFloatScratchSpace R(3, 3, AT_, "R");
21496 MFloat tmp[3] = {F0, F0, F1};
21497 MFloat zHat[3];
21498 for(MInt k = 0; k < mMin(2, m_noEmbeddedBodies); k++) {
21499 computeRotationMatrix(R, &(m_bodyQuaternion[4 * k]));
21500 matrixVectorProductTranspose(zHat, R, tmp); // orientation of z-principal axis
21501 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
21502 ofl << m_bodyCenter[k * nDim + spaceId] << " ";
21503 }
21504 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
21505 ofl << m_bodyVelocity[k * nDim + spaceId] << " ";
21506 }
21507 for(MInt spaceId = 0; spaceId < 3; spaceId++) {
21508 ofl << zHat[spaceId] << " ";
21509 }
21510 for(MInt spaceId = 0; spaceId < 3; spaceId++) {
21511 ofl << m_bodyAngularVelocity[k * 3 + spaceId] << " ";
21512 }
21513 }
21514 ofl << endl;
21515 ofl.close();
21516 }
21517 }
21518}
21519
21520
21525template <MInt nDim, class SysEqn>
21527 TRACE();
21528 NEW_TIMER_GROUP(t_statistics, "statistics");
21529 NEW_TIMER(t_timertotal, "statistics", t_statistics);
21530 NEW_SUB_TIMER(t_slip, "slip", t_timertotal);
21531 NEW_SUB_TIMER(t_states, "states", t_timertotal);
21532 NEW_SUB_TIMER(t_odf, "odf", t_timertotal);
21533 NEW_SUB_TIMER(t_pdf, "pdf", t_timertotal);
21534 NEW_SUB_TIMER(t_near, "near", t_timertotal);
21535 NEW_SUB_TIMER(t_near_bodydat, "near_bodydat", t_near);
21536 NEW_SUB_TIMER(t_near_bodydat2, "near_bodydat2", t_near);
21537 NEW_SUB_TIMER(t_near_output, "near_output", t_near);
21538 NEW_SUB_TIMER(t_fft, "fft", t_timertotal);
21539
21540 TERMM_IF_COND(m_reConstSVDWeightMode == 3 || m_reConstSVDWeightMode == 4, "Not yet implemented!");
21541
21542 // short-cut for property input with defaultValue
21543 auto getIntProp = [&](const char* name, const MInt defaultValue) {
21544 return (Context::propertyExists(name, 0)) ? Context::getSolverProperty<MInt>(name, m_solverId, AT_) : defaultValue;
21545 };
21546
21547 // regular output intervals with default values
21548 const MInt statsInterval = getIntProp("statsInterval", m_dragOutputInterval);
21549 const MInt pdfInterval = getIntProp("pdfInterval", 0);
21550 const MInt angleInterval = getIntProp("angleInterval", 0);
21551 const MInt nearBodyInterval = getIntProp("nearBodyInterval", 0);
21552 const MInt scatterInterval = getIntProp("scatterInterval", 0);
21553 const MInt fftInterval = getIntProp("fftInterval", 0);
21554
21555 // check which statistics have to be computed at the current time step
21556 MBool computeStats = (statsInterval > 0 && globalTimeStep % statsInterval == 0);
21557 MBool computeSlipStats = (m_slipInterval > 0 && globalTimeStep % m_slipInterval == 0);
21558 MBool outputSlipStats = (m_saveSlipInterval > 0 && globalTimeStep % m_saveSlipInterval == 0);
21559 MBool computePdf = (pdfInterval > 0 && globalTimeStep % pdfInterval == 0);
21560 MBool computeAngles = (angleInterval > 0 && globalTimeStep % angleInterval == 0);
21561 MBool computeNearBody = (nearBodyInterval > 0 && globalTimeStep % nearBodyInterval == 0);
21562 MBool computeScatter = (scatterInterval > 0 && globalTimeStep % scatterInterval == 0);
21563 MBool computeFFT = (fftInterval > 0 && globalTimeStep % fftInterval == 0);
21564
21565 // manual output time steps, overrides regular output intervals
21566 MBool forceOutput = false;
21567 if(m_forceFVMBStatistics.size() == 0 && Context::propertyExists("forceFVMBStatistics", 0)) {
21568 const MInt cnt = Context::propertyLength("forceFVMBStatistics", m_solverId);
21569 for(MInt k = 0; k < cnt; k++) {
21570 MInt ts = Context::getSolverProperty<MInt>("forceFVMBStatistics", m_solverId, AT_, k);
21571 m_forceFVMBStatistics.push_back(ts);
21572 }
21573 }
21574 for(MUint i = 0; i < m_forceFVMBStatistics.size(); i++) {
21575 if(globalTimeStep == m_forceFVMBStatistics[i]) forceOutput = true;
21576 }
21577
21578 if(forceOutput == true) {
21579 computeStats = (statsInterval > 0);
21580 computeSlipStats = (m_slipInterval > 0);
21581 outputSlipStats = (m_saveSlipInterval > 0);
21582 computePdf = (pdfInterval > 0);
21583 computeAngles = (angleInterval > 0);
21584 computeNearBody = (nearBodyInterval > 0);
21585 computeScatter = (scatterInterval > 0);
21586 computeFFT = (fftInterval > 0);
21587 }
21588
21589 // computeStats is required for further statistics
21590 if(computePdf || computeSlipStats || computeAngles || computeNearBody || computeScatter || computeFFT || force)
21591 computeStats = true;
21592
21593 if(!computeStats) return;
21594
21595 if(domainId() == 0) {
21596 cerr << globalTimeStep << " " << m_restartTimeStep << " "
21597 << "computeStats " << computeStats << " "
21598 << "computeSlipStats " << computeSlipStats << " "
21599 << "outputSlipStats " << outputSlipStats << " "
21600 << "computePdf " << computePdf << " "
21601 << "computeAngles " << computeAngles << " "
21602 << "computeNearBody " << computeNearBody << " "
21603 << "computeScatter " << computeScatter << " "
21604 << "computeFFT " << computeFFT << endl;
21605 }
21606
21607 RECORD_TIMER_START(t_timertotal);
21608 leastSquaresReconstruction(); // update the slopes
21609 RECORD_TIMER_START(t_slip); // t_slip contains all calls of computeNearBodyFluidVelocity()
21610 MInt noParticles = 0;
21611 if(m_noPointParticles > 0)
21612 noParticles = m_noPointParticlesLocal;
21613 else if(m_noEmbeddedBodies > 0)
21614 noParticles = m_noEmbeddedBodies;
21615 const MBool computeBodyVol = true;
21616 MFloatScratchSpace partVol(mMax(1, noParticles), AT_, "partVol");
21617 // Unified data access for Lagrangian point-particles / and embedded Bodies
21618 MFloat* vel = nullptr;
21619 MFloat* velGradient = nullptr;
21620 MFloat* quats = nullptr;
21621 MFloat* pvel = nullptr;
21622 MFloat* pvelDt1 = nullptr;
21623 MFloat* protVelHat = nullptr;
21624 MFloat* protVelHatDt1 = nullptr;
21625 MFloat* nearBodyState = nullptr;
21626 MFloat* pRadii = nullptr;
21627 MFloat* pTemperature = nullptr;
21628 const MInt noNearBodyState = 5;
21629 // memory nearBodyData
21630 MFloatScratchSpace velMem(mMax(1, m_noEmbeddedBodies) * nDim, AT_, "velMem");
21631 MFloatScratchSpace velGradMem(mMax(1, m_noEmbeddedBodies) * nDim * nDim, AT_, "velGradMem");
21632 MFloatScratchSpace pOmegaHat(mMax(1, noParticles) * nDim, AT_, "pOmegaHat");
21633 MFloatScratchSpace protVelHatMem(mMax(1, noParticles) * nDim, AT_, "protVelHatMem");
21634 MFloatScratchSpace protVelHatMemDt1(mMax(1, noParticles) * nDim, AT_, "protVelHatMemDt1");
21635 MFloatScratchSpace velShearHat(mMax(1, noParticles) * nDim, AT_, "velShearHat");
21636 MFloatScratchSpace particleFluidRotation(mMax(1, m_noEmbeddedBodies), nDim, AT_, "particleFluidRotation");
21637 MFloatScratchSpace nbStateMem(mMax(1, m_noEmbeddedBodies) * noNearBodyState, AT_, "nbStateMem");
21638 MFloatScratchSpace particleFluidPressure(mMax(1, noParticles), AT_, "particleFluidPressure");
21639 MIntScratchSpace nearestBodies((m_noPointParticles > 0 ? 1 : m_maxNearestBodies * a_noCells()), AT_, "nearestBodies");
21640 MFloatScratchSpace nearestDist((m_noPointParticles > 0 ? 1 : m_maxNearestBodies * a_noCells()), AT_, "nearestDist");
21641 MFloatScratchSpace nearestFac((m_noPointParticles > 0 ? 1 : m_maxNearestBodies * a_noCells()), AT_, "nearestFac");
21642 const MFloat maxDistConstruct = (m_noEmbeddedBodies <= 0 ? -1 : 5.0 * m_bodyDiameter[0]);
21643 MIntScratchSpace skipParticle(mMax(1, noParticles), AT_, "skipParticle");
21644 skipParticle.fill(0);
21645 if(m_noPointParticles > 0) {
21646 setParticleFluidVelocities(&(particleFluidPressure[0]));
21647 vel = &(m_particleVelocityFluid[0]);
21648 velGradient = &(m_particleVelocityGradientFluid[0]);
21649 quats = &(m_particleQuaternions[0]);
21650 pvel = &(m_particleVelocity[0]);
21651 pvelDt1 = &(m_particleVelocityDt1[0]);
21652 protVelHat = &(m_particleAngularVelocity[0]);
21653 protVelHatDt1 = &(m_particleAngularVelocityDt1[0]);
21654 pRadii = &(m_particleRadii[0]);
21655 pTemperature = &(m_particleTemperature[0]);
21656 } else if(m_noEmbeddedBodies > 0) {
21657 MInt maxBodyCnt = 0;
21658 nearestBodies.fill(-1);
21659 nearestDist.fill(numeric_limits<MFloat>::max());
21660 maxBodyCnt = constructDistance(maxDistConstruct, nearestBodies, nearestDist);
21661 if(maxBodyCnt > m_maxNearestBodies) {
21662 cerr << "constructDistance: maxBodyCnt " << maxBodyCnt << " exceeds m_maxNearestBodies " << m_maxNearestBodies
21663 << " computeNearBodyFluidVelocity will be affected in the statistics on domainId " << domainId() << endl;
21664 }
21665 const MFloat minDist = 2.0;
21666 const MFloat maxDist = minDist + 1.0;
21667 constexpr MFloat maxAngleVel = 0.0;
21668 constexpr MFloat maxAngleRot = 0.0;
21669 vector<MFloat> setup = {minDist, maxDist, maxAngleVel, maxAngleRot};
21670 if(computePdf || computeNearBody) {
21671 computeNearBodyFluidVelocity(nearestBodies, nearestDist, &velMem[0], &velGradMem[0], &particleFluidRotation[0],
21672 setup, &skipParticle[0], &nbStateMem[0], &particleFluidPressure[0], &nearestFac[0]);
21673 } else {
21674 computeNearBodyFluidVelocity(nearestBodies, nearestDist, &velMem[0], &velGradMem[0], &particleFluidRotation[0],
21675 setup, &skipParticle[0]);
21676 }
21677 quats = &(m_bodyQuaternion[0]);
21678 pvel = &(m_bodyVelocity[0]);
21679 pvelDt1 = &(m_bodyVelocityDt1[0]);
21680 protVelHat = &(protVelHatMem[0]);
21681 protVelHatDt1 = &(protVelHatMemDt1[0]);
21682 vel = &velMem[0];
21683 velGradient = &velGradMem[0];
21684 // fluid rotation is evaluated using velGradient, particleFluidRotation would be an alternative
21685 nearBodyState = &nbStateMem[0];
21686 pRadii = &(m_bodyRadii[0]);
21687 pTemperature = &(m_bodyTemperature[0]);
21688 }
21689 // Transform values for rotational dynamics from inertial frame into body frame of reference for fully-resolved
21690 // particles
21691 if(m_noEmbeddedBodies > 0) {
21692 for(MInt p = 0; p < noParticles; p++) {
21693 MFloat qiRotvel[3];
21694 MFloat qiRotvelDt1[3];
21695 MFloat qiRotFluid[3];
21696 MFloat qiShear[3];
21697 MFloat qbRotvel[3];
21698 MFloat qbRotvelDt1[3];
21699 MFloat qbRot[3];
21700 MFloat qbShear[3];
21701 for(MInt i = 0; i < nDim; i++) {
21702 MInt id0 = (i + 1) % 3;
21703 MInt id1 = (id0 + 1) % 3;
21704 qiRotFluid[i] = F1B2 * (velGradient[9 * p + 3 * id1 + id0] - velGradient[9 * p + 3 * id0 + id1]);
21705 qiShear[i] = F1B2 * (velGradient[9 * p + 3 * id1 + id0] + velGradient[9 * p + 3 * id0 + id1]);
21706 qiRotvel[i] = m_bodyAngularVelocity[3 * p + i];
21707 qiRotvelDt1[i] = m_bodyAngularVelocityDt1[3 * p + i];
21708 }
21709 MFloatScratchSpace R(3, 3, AT_, "R");
21710 computeRotationMatrix(R, &(quats[4 * p]));
21711 matrixVectorProduct(qbRot, R, qiRotFluid);
21712 matrixVectorProduct(qbShear, R, qiShear);
21713 matrixVectorProduct(qbRotvel, R, qiRotvel);
21714 matrixVectorProduct(qbRotvelDt1, R, qiRotvelDt1);
21715 for(MInt i = 0; i < nDim; i++) {
21716 pOmegaHat[p * nDim + i] = qbRot[i];
21717 velShearHat[p * nDim + i] = qbShear[i];
21718 protVelHat[p * nDim + i] = qbRotvel[i];
21719 protVelHatDt1[p * nDim + i] = qbRotvelDt1[i];
21720 }
21721 }
21722 } else {
21723 for(MInt p = 0; p < noParticles; p++) {
21724 for(MInt i = 0; i < nDim; i++) {
21725 MInt id0 = (i + 1) % 3;
21726 MInt id1 = (id0 + 1) % 3;
21727 pOmegaHat[p * nDim + i] = F1B2 * (velGradient[9 * p + 3 * id1 + id0] - velGradient[9 * p + 3 * id0 + id1]);
21728 velShearHat[p * nDim + i] = F1B2 * (velGradient[9 * p + 3 * id1 + id0] + velGradient[9 * p + 3 * id0 + id1]);
21729 }
21730 }
21731 }
21732 // Compute time-resolved particle-induced dissipation
21733 if(computeSlipStats) computeSlipStatistics(nearestBodies, nearestDist, maxDistConstruct);
21734 if(outputSlipStats) saveParticleSlipData();
21735 RECORD_TIMER_STOP(t_slip);
21736
21737 const MFloat DX = (m_bbox[3] - m_bbox[0]);
21738 partVol.fill(F0);
21739 if(m_noEmbeddedBodies > 0) {
21740 if(computeBodyVol) {
21741 computeBodyVolume(partVol);
21742 } else {
21743 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
21744 partVol[b] = m_bodyVolume[b];
21745 }
21746 }
21747 } else {
21748 for(MInt p = 0; p < m_noPointParticlesLocal; p++) {
21749 partVol[p] = F4B3 * PI * m_particleRadii[3 * p] * m_particleRadii[3 * p + 1] * m_particleRadii[3 * p + 2];
21750 }
21751 }
21752 MIntScratchSpace leafCells(a_noCells(), AT_, "leafCells");
21753 MInt noLeafCells = 0;
21754 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
21755 if(a_isBndryGhostCell(cellId)) continue;
21756 if(a_isHalo(cellId)) continue;
21757 if(a_isPeriodic(cellId)) continue;
21758 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21759 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
21760 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(cellId) > 0) continue;
21761 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && a_hasProperty(cellId, SolverCell::IsInactive)) continue;
21762 if(a_bndryId(cellId) < 0 && a_levelSetValuesMb(cellId, 0) < F0) cerr << "warn: neg LS " << endl;
21763 leafCells(noLeafCells++) = cellId;
21764 }
21765 RECORD_TIMER_START(t_states);
21766 vector<MFloat> eKinFlowDataMean(17, F0);
21767 MFloatScratchSpace meanState(4, AT_, "meanState");
21768 for(MInt stat = 0; stat < m_noMeanStatistics; stat++) {
21769 const MFloat refRadius = (noParticles > 0 ? pow(pRadii[0] * pRadii[1] * pRadii[2], F1B3) : 0);
21770 // gather fluid statistics
21771 for(MInt c = 0; c < noLeafCells; c++) {
21772 MInt cellId = leafCells(c);
21773 MFloat volume = a_cellVolume(cellId);
21774 if(volume < 1e-14) continue;
21775 if(stat > 0 && a_levelSetValuesMb(cellId, 0) < m_distThresholdStat[stat] * refRadius) continue;
21776 MFloat U2 = F0;
21777 MFloat U20 = F0;
21778 MFloat w2 = F0;
21779 MFloat s2 = F0;
21780 for(MInt i = 0; i < nDim; i++) {
21781 U2 += POW2(a_variable(cellId, CV->RHO_VV[i]) / a_variable(cellId, CV->RHO));
21782 U20 += POW2(a_oldVariable(cellId, CV->RHO_VV[i]) / a_oldVariable(cellId, CV->RHO));
21783 w2 += POW2(a_slope(cellId, PV->VV[(i + 1) % nDim], (i + 2) % nDim)
21784 - a_slope(cellId, PV->VV[(i + 2) % nDim], (i + 1) % nDim));
21785 s2 += POW2(a_slope(cellId, PV->VV[(i + 1) % nDim], (i + 2) % nDim)
21786 + a_slope(cellId, PV->VV[(i + 2) % nDim], (i + 1) % nDim));
21787 }
21788 MFloat T = sysEqn().temperature_ES(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
21789 MFloat mue = SUTHERLANDLAW(T) / sysEqn().m_Re0;
21790
21791 MFloat div = F0;
21792 for(MInt i = 0; i < nDim; i++) {
21793 div += a_slope(cellId, PV->VV[i], i);
21794 }
21795 eKinFlowDataMean[0] += F1B2 * volume * U2;
21796 eKinFlowDataMean[1] += F1B2 * volume * a_variable(cellId, CV->RHO) * U2;
21797 eKinFlowDataMean[2] += F1B2 * m_cellVolumesDt1[cellId] * U20;
21798 eKinFlowDataMean[3] += F1B2 * m_cellVolumesDt1[cellId] * a_oldVariable(cellId, CV->RHO) * U20;
21799 eKinFlowDataMean[4] += volume * fabs(div);
21800 eKinFlowDataMean[5] += volume * w2;
21801 for(MInt i = 0; i < nDim; i++) {
21802 for(MInt j = 0; j < nDim; j++) {
21803 eKinFlowDataMean[6] += volume * mue * (a_slope(cellId, PV->VV[i], j) + a_slope(cellId, PV->VV[j], i))
21804 * a_slope(cellId, PV->VV[i], j);
21805 eKinFlowDataMean[7] +=
21806 volume * F1B2 * mue * POW2(a_slope(cellId, PV->VV[i], j) + a_slope(cellId, PV->VV[j], i));
21807 eKinFlowDataMean[8] += volume * mue * a_slope(cellId, PV->VV[i], j) * a_slope(cellId, PV->VV[i], j);
21808 }
21809 eKinFlowDataMean[9] += volume * POW2(a_slope(cellId, PV->VV[i], i));
21810 eKinFlowDataMean[10] += volume * POW3(a_slope(cellId, PV->VV[i], i));
21811 }
21812 eKinFlowDataMean[11] += volume * mue;
21813 eKinFlowDataMean[12] += volume * a_variable(cellId, CV->RHO);
21814 eKinFlowDataMean[13] += T * volume;
21815 eKinFlowDataMean[14] += volume;
21816 eKinFlowDataMean[15] += volume * POW2(div);
21817 eKinFlowDataMean[16] += volume * POW2(a_variable(cellId, CV->RHO));
21818 }
21819 MPI_Allreduce(MPI_IN_PLACE, eKinFlowDataMean.data(), eKinFlowDataMean.size(), MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
21820 "MPI_IN_PLACE", "eKinFlowDataMean[0]");
21821
21822 // gather solid statistics
21823 vector<MFloat> eKinPartDataMean(25, F0);
21824 for(MInt p = 0; p < noParticles; p++) {
21825 eKinPartDataMean[0] += F1;
21826 eKinPartDataMean[1] += partVol[p];
21827 eKinPartDataMean[2] += pvel[p * nDim];
21828 eKinPartDataMean[3] += pvel[p * nDim + 1];
21829 eKinPartDataMean[4] += pvel[p * nDim + 2];
21830 eKinPartDataMean[5] += POW2(pvel[p * nDim]);
21831 eKinPartDataMean[6] += POW2(pvel[p * nDim + 1]);
21832 eKinPartDataMean[7] += POW2(pvel[p * nDim + 2]);
21833 eKinPartDataMean[8] += protVelHat[p * nDim + 0];
21834 eKinPartDataMean[9] += protVelHat[p * nDim + 1];
21835 eKinPartDataMean[10] += protVelHat[p * nDim + 2];
21836 eKinPartDataMean[11] += POW2(protVelHat[p * nDim + 0]);
21837 eKinPartDataMean[12] += POW2(protVelHat[p * nDim + 1]);
21838 eKinPartDataMean[13] += POW2(protVelHat[p * nDim + 2]);
21839 MFloatScratchSpace R(3, 3, AT_, "R");
21840 computeRotationMatrix(R, &(quats[4 * p]));
21841 // assuming zHat as major axis of ellipsoid which is fixed for point-particles and variable for fully resolved
21842 // fv_mb_cleanup
21843 MFloat tmp[3] = {F1, F0, F0};
21844 MFloat zHat[3];
21845 matrixVectorProductTranspose(zHat, R, tmp); // orientation of z-principal axis
21846 for(MInt i = 0; i < nDim; i++) {
21847 zHat[i] /= mMax(1e-12, sqrt(zHat[0] * zHat[0] + zHat[1] * zHat[1] + zHat[2] * zHat[2]));
21848 }
21849 eKinPartDataMean[14] += fabs(zHat[2]); // assuming z-axis is direction of anisotropy, e.g. direction of gravity
21850 MFloat diameter = F2 * pow(pRadii[3 * p] * pRadii[3 * p + 1] * pRadii[3 * p + 2], F1B3);
21851 MFloat Rep = F0;
21852 for(MInt i = 0; i < nDim; i++) {
21853 Rep += POW2(vel[3 * p + i] - pvel[3 * p + i]);
21854 }
21855 Rep = sqrt(Rep) * diameter * m_rhoInfinity * sysEqn().m_Re0 / sysEqn().m_muInfinity; // isothermal
21856 eKinPartDataMean[15] += Rep;
21857 eKinPartDataMean[16] += POW2(Rep);
21858 MFloat pmass = partVol[p] * m_densityRatio * m_rhoInfinity;
21859 eKinPartDataMean[17] += pmass;
21860 MFloat momI[3] = {F0, F0, F0};
21861 momI[0] = F1B5 * (POW2(pRadii[3 * p + 1]) + POW2(pRadii[3 * p + 2]));
21862 momI[1] = F1B5 * (POW2(pRadii[3 * p + 0]) + POW2(pRadii[3 * p + 2]));
21863 momI[2] = F1B5 * (POW2(pRadii[3 * p + 0]) + POW2(pRadii[3 * p + 1]));
21864 for(MInt i = 0; i < nDim; i++) {
21865 eKinPartDataMean[18] += partVol[p] * F1B2 * POW2(pvel[p * nDim + i]);
21866 eKinPartDataMean[19] += partVol[p] * F1B2 * momI[i] * POW2(protVelHat[p * nDim + i]);
21867 eKinPartDataMean[20] += partVol[p] * F1B2 * POW2(pvelDt1[p * nDim + i]);
21868 eKinPartDataMean[21] += partVol[p] * F1B2 * momI[i] * POW2(protVelHatDt1[p * nDim + i]);
21869 }
21870 MFloat vrel[3] = {F0, F0, F0};
21871 MFloat omegaRel[3] = {F0, F0, F0};
21872 for(MInt i = 0; i < nDim; i++) {
21873 vrel[i] = vel[nDim * p + i] - pvel[nDim * p + i];
21874 omegaRel[i] = pOmegaHat[i] - protVelHat[p * 3 + i];
21875 }
21876 if(m_noEmbeddedBodies > 0) {
21877 eKinPartDataMean[22] += (m_hydroForce[nDim * p + 0] * vrel[0] + m_hydroForce[nDim * p + 1] * vrel[1]
21878 + m_hydroForce[nDim * p + 2] * vrel[2]);
21879 eKinPartDataMean[23] += (m_bodyTorque[nDim * p + 0] * omegaRel[0] + m_bodyTorque[nDim * p + 1] * omegaRel[1]
21880 + m_bodyTorque[nDim * p + 2] * omegaRel[2]);
21881 } else {
21882 eKinPartDataMean[22] +=
21883 pmass
21884 * (m_particleAcceleration[nDim * p + 0] * vrel[0] + m_particleAcceleration[nDim * p + 1] * vrel[1]
21885 + m_particleAcceleration[nDim * p + 2] * vrel[2]);
21886 eKinPartDataMean[23] += F0; // no source terms because of particle rotation
21887 }
21888 eKinPartDataMean[24] += pTemperature[p];
21889 }
21890 if(m_noPointParticles > 0) {
21891 if(domainId() == 0) {
21892 MPI_Reduce(MPI_IN_PLACE, eKinPartDataMean.data(), eKinPartDataMean.size(), MPI_DOUBLE, MPI_SUM, 0, mpiComm(),
21893 AT_, "MPI_IN_PLACE", "eKinPartDataMean");
21894 } else {
21895 MPI_Reduce(eKinPartDataMean.data(), eKinPartDataMean.data(), eKinPartDataMean.size(), MPI_DOUBLE, MPI_SUM, 0,
21896 mpiComm(), AT_, "MPI_IN_PLACE", "eKinPartDataMean");
21897 }
21898 }
21899
21900 const MFloat volF = eKinFlowDataMean[14];
21901 const MFloat fluidMass = eKinFlowDataMean[12];
21902 const MFloat volP = eKinPartDataMean[1];
21903 const MFloat totalMass = fluidMass + eKinPartDataMean[17];
21904 const MInt cnt = eKinPartDataMean[0];
21905 const MFloat partLinDiss = eKinPartDataMean[22] / POW3(DX);
21906 const MFloat partRotDiss = eKinPartDataMean[23] / POW3(DX);
21907 if(cnt != noParticles) {
21908 cerr << "Number of particles in statistics is wrong " << cnt << " " << m_noEmbeddedBodies << " "
21909 << m_noPointParticles << " " << noParticles << endl;
21910 }
21911
21912 MFloat EkT = eKinFlowDataMean[1] + (eKinPartDataMean[18] + eKinPartDataMean[19]) * m_densityRatio * m_rhoInfinity;
21913 MFloat EkB = (eKinPartDataMean[18] + eKinPartDataMean[19]) / volP;
21914
21915 for(MUint i = 0; i < eKinFlowDataMean.size(); i++) {
21916 eKinFlowDataMean[i] /= volF;
21917 }
21918 for(MUint i = 0; i < eKinPartDataMean.size(); i++) {
21919 eKinPartDataMean[i] /= cnt;
21920 }
21921
21922 // store mean values for later statistics (e.g., nearBodyData)
21923 if(stat == 0) {
21924 meanState(0) = eKinFlowDataMean[0]; // Ek
21925 meanState(1) = EkT / totalMass; // EkT
21926 meanState(2) = EkB; // Ekb
21927 meanState(3) = (5.0 * (sysEqn().m_muInfinity / sysEqn().m_Re0) * (eKinFlowDataMean[9] / F3)); // eps1
21928 }
21929 if(m_firstStats) {
21930 m_oldMeanState[stat][0] = meanState(0); // Ek
21931 m_oldMeanState[stat][1] = meanState(1); // EkT
21932 m_oldMeanState[stat][2] = meanState(2); // EkB
21933 m_oldMeanState[stat][3] = meanState(3); // eps1
21934 }
21935 if(domainId() == 0) {
21936 MFloat mue = eKinFlowDataMean[11];
21937 MFloat dudx = eKinFlowDataMean[9];
21938 MFloat eps4 = F5 * mue * dudx;
21939 MFloat skewness = (eKinFlowDataMean[10] / F3) / pow(dudx / F3, F3B2);
21940 MFloat eta = pow(mue, 0.75) / pow(eps4, 0.25);
21941 MFloat lambda = sqrt(F2B3 * eKinFlowDataMean[0]) / sqrt(dudx / F3);
21942 MFloat reLambda = lambda * sqrt(F2B3 * eKinFlowDataMean[0]) * eKinFlowDataMean[12] / mue;
21943 MFloat coupling = m_couplingRate / (volF + volP);
21944 MFloat* termVel = nullptr;
21945 MFloat defaultTermVel[3] = {F0, F0, F0};
21946 if(m_noPointParticles > 0 && m_particleRadii.size() > 0) {
21947 termVel = m_particleTerminalVelocity;
21948 } else if(m_noEmbeddedBodies > 0) {
21949 termVel = m_bodyTerminalVelocity;
21950 } else {
21951 termVel = defaultTermVel;
21952 }
21953 const MFloat taup = F2 * m_densityRatio * POW2(refRadius) / (9.0 * sysEqn().m_muInfinity / sysEqn().m_Re0);
21954 const MFloat epsRef = DX / (POW3(m_UInfinity));
21955 // gather value-header pairs
21956 vector<pair<string, double>> eKinOutput;
21957 eKinOutput.push_back(make_pair("ts", globalTimeStep));
21958 eKinOutput.push_back(make_pair("t", m_time));
21959 eKinOutput.push_back(make_pair("tf", m_physicalTime));
21960 eKinOutput.push_back(make_pair("Ek", eKinFlowDataMean[0] / POW2(m_UInfinity)));
21961 eKinOutput.push_back(make_pair("EkB", EkB / POW2(m_UInfinity)));
21962 eKinOutput.push_back(make_pair("EkT", EkT / (POW2(m_UInfinity) * totalMass)));
21963 eKinOutput.push_back(make_pair("-d(Ek)dt", -(meanState(0) - m_oldMeanState[stat][0]) * epsRef
21964 / (timeStep() * m_dragOutputInterval)));
21965 eKinOutput.push_back(make_pair("-d(EkB)dt", -(meanState(2) - m_oldMeanState[stat][2]) * epsRef
21966 / (timeStep() * m_dragOutputInterval)));
21967 eKinOutput.push_back(make_pair("-d(EkT)dt", -(meanState(1) - m_oldMeanState[stat][1]) * epsRef
21968 / (timeStep() * m_dragOutputInterval)));
21969 eKinOutput.push_back(make_pair("divergence", eKinFlowDataMean[4] / m_UInfinity));
21970 eKinOutput.push_back(make_pair("divergenceRMS", sqrt(eKinFlowDataMean[15]) / m_UInfinity));
21971 eKinOutput.push_back(make_pair("enstrophy", eKinFlowDataMean[5]));
21972 eKinOutput.push_back(make_pair("eps", eKinFlowDataMean[6] * epsRef));
21973 eKinOutput.push_back(make_pair("eps2", eKinFlowDataMean[7] * epsRef));
21974 eKinOutput.push_back(make_pair("eps3", eKinFlowDataMean[8] * epsRef));
21975 eKinOutput.push_back(make_pair("eps4", eps4 * epsRef));
21976 eKinOutput.push_back(make_pair("skewness", -skewness));
21977 eKinOutput.push_back(make_pair("volF", volF / POW3(DX)));
21978 eKinOutput.push_back(make_pair("volP", volP / POW3(DX)));
21979 eKinOutput.push_back(make_pair("volDiff", (POW3(DX) - volF - volP) / POW3(DX)));
21980 eKinOutput.push_back(make_pair("Kolmogorov-scale", eta / DX));
21981 eKinOutput.push_back(make_pair("Taylor-scale", lambda / DX));
21982 eKinOutput.push_back(make_pair("ReLambda", reLambda));
21983 eKinOutput.push_back(make_pair("Interphase-Momentum-Exchange", coupling * epsRef));
21984 eKinOutput.push_back(make_pair("uPMean", eKinPartDataMean[2] / m_Ma));
21985 eKinOutput.push_back(make_pair("vPMean", eKinPartDataMean[3] / m_Ma));
21986 eKinOutput.push_back(make_pair("wPMean", eKinPartDataMean[4] / m_Ma));
21987 eKinOutput.push_back(make_pair("uPRMS", sqrt(eKinPartDataMean[5]) / m_Ma));
21988 eKinOutput.push_back(make_pair("vPRMS", sqrt(eKinPartDataMean[6]) / m_Ma));
21989 eKinOutput.push_back(make_pair("wPRMS", sqrt(eKinPartDataMean[7]) / m_Ma));
21990 eKinOutput.push_back(make_pair("OmegaxPMean", eKinPartDataMean[8]));
21991 eKinOutput.push_back(make_pair("OmegayPMean", eKinPartDataMean[9]));
21992 eKinOutput.push_back(make_pair("OmegazPMean", eKinPartDataMean[10]));
21993 eKinOutput.push_back(make_pair("OmegaxPRMS", sqrt(eKinPartDataMean[11])));
21994 eKinOutput.push_back(make_pair("OmegayPRMS", sqrt(eKinPartDataMean[12])));
21995 eKinOutput.push_back(make_pair("OmegazPRMS", sqrt(eKinPartDataMean[13])));
21996 eKinOutput.push_back(make_pair("thetaMean", eKinPartDataMean[14]));
21997 eKinOutput.push_back(make_pair("RepMean", eKinPartDataMean[15]));
21998 eKinOutput.push_back(make_pair("RepRMS", sqrt(eKinPartDataMean[16])));
21999 eKinOutput.push_back(make_pair("Stokes", taup * sqrt(F5 * dudx)));
22000 eKinOutput.push_back(make_pair("Froude", taup * POW2(termVel[2]) / mue));
22001 eKinOutput.push_back(make_pair("mueMean", mue / (sysEqn().m_muInfinity / sysEqn().m_Re0)));
22002 eKinOutput.push_back(make_pair("rhoMean", eKinFlowDataMean[12] / m_rhoInfinity));
22003 eKinOutput.push_back(make_pair("rhoRMS", sqrt(eKinFlowDataMean[16]) / m_rhoInfinity));
22004 eKinOutput.push_back(make_pair("TFluid", eKinFlowDataMean[13] / m_TInfinity));
22005 eKinOutput.push_back(make_pair("TPart", eKinPartDataMean[24] / m_TInfinity));
22006 eKinOutput.push_back(make_pair("part_lin_diss", partLinDiss * epsRef));
22007 eKinOutput.push_back(make_pair("part_rot_diss", partRotDiss * epsRef));
22008 // output as ASCII-file
22009 ofstream ofl;
22010 MString suffix = (stat > 0) ? "_D" + to_string(m_distThresholdStat[stat]) : "";
22011 suffix.erase(suffix.find_last_not_of('0') + 1, std::string::npos);
22012 suffix.erase(suffix.find_last_not_of('.') + 1, std::string::npos);
22013 // if first file access, make a backup of existing files and print the header
22014 if(globalTimeStep == 0 && m_firstStats) {
22015 rename(("kineticEnergy" + suffix + "_BAK1").c_str(), ("kineticEnergy" + suffix + "_BAK2").c_str());
22016 rename(("kineticEnergy" + suffix + "_BAK0").c_str(), ("kineticEnergy" + suffix + "_BAK1").c_str());
22017 rename(("kineticEnergy" + suffix + "_BAK").c_str(), ("kineticEnergy" + suffix + "_BAK0").c_str());
22018 rename(("kineticEnergy" + suffix).c_str(), ("kineticEnergy" + suffix + "_BAK").c_str());
22019 ofl.open(("kineticEnergy" + suffix).c_str(), ios_base::out | ios_base::trunc);
22020 ofl << "# "; // outcommented for gnuplot
22021 for(MUint i = 0; i < eKinOutput.size(); i++) {
22022 ofl << i + 1 << ":" << get<0>(eKinOutput[i]) << " ";
22023 }
22024 ofl << endl;
22025 } else {
22026 ofl.open(("kineticEnergy" + suffix).c_str(), ios_base::out | ios_base::app);
22027 }
22028 if(ofl.is_open() && ofl.good()) {
22029 for(MUint i = 0; i < eKinOutput.size(); i++) {
22030 ofl << get<1>(eKinOutput[i]) << " ";
22031 }
22032 ofl << endl;
22033 ofl.close();
22034 }
22035 }
22036 m_oldMeanState[stat][0] = meanState(0);
22037 m_oldMeanState[stat][1] = meanState(1);
22038 m_oldMeanState[stat][2] = meanState(2);
22039 m_oldMeanState[stat][3] = meanState(3);
22040 }
22041 RECORD_TIMER_STOP(t_states);
22042
22043 // probability density function and orientation distribution function
22044 if(computePdf) {
22045 IF_CONSTEXPR(nDim == 2) mTerm(1, AT_, "computePdf not implemented for 2D!");
22046 RECORD_TIMER_START(t_odf);
22047 const MInt noSamples = 1; // no temporal averaging
22048 const MInt thetaSize = 100; // noBins for odf and pdf
22049 const MFloat deltaRadius = F2 / ((MFloat)thetaSize);
22050 const MInt noDat = 64; // mutiples of 4!
22051 // two containers for angles in radians and in degrees
22052 MFloatScratchSpace angles(noDat, AT_, "angles");
22053 MFloatScratchSpace angles2(noDat, AT_, "angles2");
22054 MFloatScratchSpace thetaDensity(thetaSize, noDat, AT_, "thetaDensity");
22055 MFloatScratchSpace thetaDensity2(thetaSize, noDat, AT_, "thetaDensity2");
22056 MFloatScratchSpace thetaPoints(thetaSize, AT_, "thetaPoints");
22057 MFloatScratchSpace thetaPoints2(thetaSize, AT_, "thetaPoints2");
22058 MFloatScratchSpace thetaBounds(thetaSize + 1, AT_, "thetaBounds");
22059 MFloatScratchSpace thetaBounds2(thetaSize + 1, AT_, "thetaBounds2");
22060 angles.fill(F0);
22061 angles2.fill(F0);
22062 thetaDensity.fill(F0);
22063 thetaDensity2.fill(F0);
22064 thetaBounds(0) = F0;
22065 thetaBounds2(0) = -F1;
22066 for(MInt i = 0; i < thetaSize; i++) {
22067 MFloat theta0 = thetaBounds(i);
22068 MFloat theta1 = acos(F1 - ((MFloat)(i + 1)) * deltaRadius); // equal-area bins for angle output
22069 MFloat theta02 = thetaBounds2(i);
22070 MFloat theta12 = thetaBounds2(0) + ((MFloat)(i + 1)) * deltaRadius; // uniform for directional cosines
22071 thetaPoints(i) = F1B2 * (theta0 + theta1);
22072 thetaPoints2(i) = F1B2 * (theta02 + theta12);
22073 thetaBounds(i + 1) = theta1;
22074 thetaBounds2(i + 1) = theta12;
22075 }
22076 thetaBounds(thetaSize) = PI;
22077 thetaBounds2(thetaSize) = F1;
22078 for(MInt p = 0; p < noParticles; p++) {
22079 if(skipParticle(p)) continue;
22080 vector<MFloat> values;
22081 MFloat fdir[3] = {F0, F0, F0};
22082 MFloat wdir[3] = {F0, F0, F0};
22083 MFloat pdir[3] = {F0, F0, F0};
22084 MFloat rdir[3] = {F0, F0, F0};
22085 MFloat reldir[3] = {F0, F0, F0};
22086 for(MInt i = 0; i < nDim; i++) {
22087 fdir[i] = vel[nDim * p + i];
22088 wdir[i] = pOmegaHat[nDim * p + i];
22089 pdir[i] = pvel[nDim * p + i];
22090 rdir[i] = protVelHat[nDim * p + i];
22091 reldir[i] = vel[nDim * p + i] - pvel[nDim * p + i];
22092 }
22093 const MFloat ffabs = sqrt(POW2(fdir[0]) + POW2(fdir[1]) + POW2(fdir[2]));
22094 const MFloat wabs = sqrt(POW2(wdir[0]) + POW2(wdir[1]) + POW2(wdir[2]));
22095 const MFloat pabs = sqrt(POW2(pdir[0]) + POW2(pdir[1]) + POW2(pdir[2]));
22096 const MFloat rabs = sqrt(POW2(rdir[0]) + POW2(rdir[1]) + POW2(rdir[2]));
22097 const MFloat relabs = sqrt(POW2(reldir[0]) + POW2(reldir[1]) + POW2(reldir[2]));
22098 MFloatScratchSpace R(3, 3, AT_, "R");
22099 computeRotationMatrix(R, &(quats[4 * p]));
22100 MFloat q[3];
22101 // fv_mb_cleanup
22102 MFloat tmp[3] = {F1, F0, F0};
22103 matrixVectorProductTranspose(q, R, tmp); // orientation of z-principal axis in world space
22104 const MFloat qabs = sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
22105 for(MInt i = 0; i < nDim; i++) {
22106 fdir[i] /= mMax(1e-12, ffabs);
22107 wdir[i] /= mMax(1e-12, wabs);
22108 pdir[i] /= mMax(1e-12, pabs);
22109 rdir[i] /= mMax(1e-12, rabs);
22110 reldir[i] /= mMax(1e-12, relabs);
22111 q[i] /= mMax(1e-12, qabs);
22112 }
22113 matrixVectorProduct(tmp, R, fdir);
22114 values.push_back(q[0]); // angle between major axis and x-axis
22115 values.push_back(q[1]); // angle between major axis and y-axis
22116 values.push_back(q[2]); // angle between major axis and z-axis
22117 values.push_back(tmp[2]); // angle between major axis and flow direction
22118 values.push_back(wdir[2]); // angle between major axis and vorticity direction
22119 MFloat omegaVel = F0; // angle between particle and fluid velocity
22120 MFloat omegaVort = F0; // angle between particle and fluid velocity
22121 for(MInt i = 0; i < nDim; i++) {
22122 omegaVel += pdir[i] * fdir[i];
22123 omegaVort += rdir[i] * wdir[i];
22124 }
22125 values.push_back(omegaVel);
22126 values.push_back(omegaVort);
22127 values.push_back(pdir[0] * q[0] + pdir[1] * q[1] + pdir[2] * q[2]);
22128 values.push_back(reldir[0] * q[0] + reldir[1] * q[1] + reldir[2] * q[2]);
22129 if(m_noEmbeddedBodies > 0)
22130 values.push_back(q[0] * rdir[0] + q[1] * rdir[1] + q[2] * rdir[2]);
22131 else
22132 values.push_back(rdir[2]);
22133
22134 MInt cnt = 0;
22135 for(MUint i = 0; i < values.size(); i++) {
22136 for(MInt j = 0; j < 4; j++) {
22137 angles[cnt] = acos(values[i]);
22138 angles2[cnt++] = values[i];
22139 }
22140 }
22141
22142 const MFloat kernelWidth = 0.05;
22143 const MFloat kernelWidth2 = 0.02;
22144 const MFloat fac = F1 / (kernelWidth);
22145 const MFloat fac2 = F1 / (kernelWidth2);
22146 for(MInt j = 0; j < noDat; j++) {
22147 for(MInt i = 0; i < thetaSize; i++) {
22148 MInt ii = i;
22149 MInt ii2 = i;
22150 if(j % 4 > 1 && i >= thetaSize / 2) ii = thetaSize - i - 1; // symmetry in theta
22151 if(j % 4 > 1 && i < thetaSize / 2) ii2 = thetaSize - i - 1; // symmetry in theta
22152 if(j % 2 == 0) {
22153 if(angles[j] > thetaBounds(i) && angles[j] < thetaBounds(i + 1)) thetaDensity(ii, j) += F1; // bin counting
22154 if(angles2[j] > thetaBounds2(i) && angles2[j] < thetaBounds2(i + 1))
22155 thetaDensity2(ii2, j) += F1; // bin counting
22156 } else {
22157 MFloat DA = thetaBounds(thetaSize) - thetaBounds(0);
22158 MFloat DA2 = thetaBounds2(thetaSize) - thetaBounds2(0);
22159 MFloat t = fabs(angles[j] - thetaPoints(i)) / kernelWidth;
22160 t = mMin(t, fabs(angles[j] + DA - thetaPoints(i)) / kernelWidth); // symmetry in theta
22161 t = mMin(t, fabs(angles[j] - DA - thetaPoints(i)) / kernelWidth); // symmetry in theta
22162 MFloat t2 = fabs(angles2[j] - thetaPoints2(i)) / kernelWidth2;
22163 t2 = mMin(t2, fabs(angles2[j] + DA2 - thetaPoints2(i)) / kernelWidth2); // symmetry in theta
22164 t2 = mMin(t2, fabs(angles2[j] - DA2 - thetaPoints2(i)) / kernelWidth2); // symmetry in theta
22165 // Smoothing using Gaussian kernel
22166 thetaDensity(ii, j) += fac * (thetaBounds(i + 1) - thetaBounds(i)) * exp(-F1B2 * POW2(t)) / sqrt(F2 * PI);
22167 thetaDensity2(ii2, j) +=
22168 fac2 * (thetaBounds2(i + 1) - thetaBounds2(i)) * exp(-F1B2 * POW2(t2)) / sqrt(F2 * PI);
22169 }
22170 }
22171 }
22172 }
22173 if(m_noPointParticles > 0) {
22174 MPI_Allreduce(MPI_IN_PLACE, &thetaDensity[0], noDat * thetaSize, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
22175 "MPI_IN_PLACE", "thetaDensity[0]");
22176 MPI_Allreduce(MPI_IN_PLACE, &thetaDensity2[0], noDat * thetaSize, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
22177 "MPI_IN_PLACE", "thetaDensity2[0]");
22178 }
22179 MFloatScratchSpace sum(noDat, AT_, "sum");
22180 MFloatScratchSpace sum2(noDat, AT_, "sum2");
22181 sum.fill(F0);
22182 sum2.fill(F0);
22183 for(MInt i = 0; i < thetaSize; i++) {
22184 MFloat ang = thetaPoints(i);
22185 MFloat fac = sin(ang);
22186 MFloat fac2 = F1;
22187 for(MInt j = 0; j < noDat; j++) {
22188 sum[j] += fac * (thetaBounds(i + 1) - thetaBounds(i)) * thetaDensity(i, j);
22189 sum2[j] += fac2 * (thetaBounds2(i + 1) - thetaBounds2(i)) * thetaDensity2(i, j);
22190 }
22191 }
22192 for(MInt i = 0; i < thetaSize; i++) {
22193 for(MInt j = 0; j < noDat; j++) {
22194 thetaDensity(i, j) /= sum[j];
22195 thetaDensity2(i, j) /= sum2[j];
22196 }
22197 }
22198
22199 if(domainId() == 0) {
22200 ofstream ofl;
22201 ofstream ofl2;
22202 ofl.open("angleDensity_00" + to_string(globalTimeStep), ios_base::out | ios_base::trunc);
22203 ofl2.open("angleDensityCos_00" + to_string(globalTimeStep), ios_base::out | ios_base::trunc);
22204 if(ofl.is_open() && ofl.good()) {
22205 ofl << "# average orientation distribution functions, sampled from time steps " << globalTimeStep - noSamples
22206 << " to " << globalTimeStep << " (time level " << m_time - (((MFloat)noSamples) * timeStep()) << " to "
22207 << m_time << ")" << endl;
22208 ofl2 << "# average orientation distribution functions (cosines), sampled from time steps "
22209 << globalTimeStep - noSamples << " to " << globalTimeStep << " (time level "
22210 << m_time - (((MFloat)noSamples) * timeStep()) << " to " << m_time << ")" << endl;
22211 ofl << "# 1: angle" << endl;
22212 ofl << "# 2: bin size" << endl;
22213 ofl << "# 3: no samples in bin" << endl;
22214 ofl << "# 4-7: alignment of particle symmetry axis with x-axis" << endl;
22215 ofl << "# 8-11: alignment of particle symmetry axis with y-axis" << endl;
22216 ofl << "# 12-15: alignment of particle symmetry axis with z-axis" << endl;
22217 ofl << "# 16-19: alignment of particle symmetry axis with flow direction" << endl;
22218 ofl << "# 20-23: alignment of particle symmetry axis with vorticity direction" << endl;
22219 ofl << "# 24-27: alignment of particle velocity with flow velocity" << endl;
22220 ofl << "# 28-31: alignment of particle angular velocity with fluid vorticity" << endl;
22221 ofl << "# 32-35: alignment of particle velocity vector with symmetry axis" << endl;
22222 ofl << "# 36-39: alignment of particle rotation vector with symmetry axis" << endl;
22223 ofl << "# 40-43: alignment of relative velocity vector with symmetry axis" << endl;
22224 for(MInt i = 0; i < thetaSize; i++) {
22225 ofl << thetaPoints(i) << " " << thetaBounds(i + 1) - thetaBounds(i) << " " << F0;
22226 ofl2 << thetaPoints2(i) << " " << thetaBounds2(i + 1) - thetaBounds2(i) << " " << F0;
22227 for(MInt j = 0; j < noDat; j++) {
22228 if(j % 4 > 1 && i >= thetaSize / 2)
22229 ofl << " nan"; // symmetry in theta
22230 else
22231 ofl << " " << thetaDensity(i, j);
22232 if(j % 4 > 1 && i < thetaSize / 2)
22233 ofl2 << " nan"; // symmetry in theta
22234 else
22235 ofl2 << " " << thetaDensity2(i, j);
22236 }
22237 ofl << endl;
22238 ofl2 << endl;
22239 }
22240 ofl.close();
22241 ofl2.close();
22242 }
22243 }
22244
22245 RECORD_TIMER_STOP(t_odf);
22246 RECORD_TIMER_START(t_pdf);
22247
22248 const MInt noPdfPoints = 100;
22249 // const MInt kernelSteps = 0; //no kernel smoothing
22250 const MInt kernelSteps = 5; // kernel smoothing
22251 // PF: Particle & Fluid
22252 // P: Particle
22253 const MInt noPdfsPF = 7;
22254 const MInt noPdfsP = 17;
22255 MFloatScratchSpace dataPointsPF(noPdfsPF, AT_, "dataPointsPF");
22256 MFloatScratchSpace pdfPointsPF(noPdfsPF, noPdfPoints, AT_, "pdfPointsPF");
22257 MFloatScratchSpace pdfBoundsPF(noPdfsPF, noPdfPoints + 1, AT_, "pdfBoundsPF");
22258 MFloatScratchSpace pdfValuesPFfluid(noPdfsPF, noPdfPoints, AT_, "pdfValuesPFfluid");
22259 MFloatScratchSpace pdfValuesPFparticle(noPdfsPF, noPdfPoints, AT_, "pdfValuesPFparticle");
22260 MFloatScratchSpace dataPointsP(noPdfsP, AT_, "dataPointsP");
22261 MFloatScratchSpace pdfPointsP(noPdfsP, noPdfPoints, AT_, "pdfPointsP");
22262 MFloatScratchSpace pdfBoundsP(noPdfsP, noPdfPoints + 1, AT_, "pdfBoundsP");
22263 MFloatScratchSpace pdfValuesP(noPdfsP, noPdfPoints, AT_, "pdfValuesP");
22264 MFloatScratchSpace meanValsPF(2, noPdfsPF, AT_, "meanValsPF");
22265 MFloatScratchSpace rmsValsPF(2, noPdfsPF, AT_, "rmsValsPF");
22266 MFloatScratchSpace sumValsPF(2, AT_, "sumValsPF");
22267 MFloatScratchSpace meanValsP(noPdfsP, AT_, "meanValsP");
22268 MFloatScratchSpace rmsValsP(noPdfsP, AT_, "rmsValsP");
22269 vector<MString> pdfTitle;
22270 dataPointsPF.fill(F0);
22271 pdfPointsPF.fill(F0);
22272 pdfBoundsPF.fill(F0);
22273 pdfValuesPFfluid.fill(F0);
22274 pdfValuesPFparticle.fill(F0);
22275 dataPointsP.fill(F0);
22276 pdfPointsP.fill(F0);
22277 pdfBoundsP.fill(F0);
22278 pdfValuesP.fill(F0);
22279 meanValsPF.fill(F0);
22280 rmsValsPF.fill(F0);
22281 meanValsP.fill(F0);
22282 rmsValsP.fill(F0);
22283 sumValsPF.fill(F0);
22284 MFloat sumValsP = F0;
22285
22286 //------- Fluid values in the flow field and near the particle
22287 pdfBoundsPF(0, 0) = 0.0;
22288 pdfBoundsPF(0, noPdfPoints) = 200.0;
22289 pdfTitle.push_back("angular-velocity(particle-fluid)");
22290 pdfBoundsPF(1, 0) = 0.0;
22291 pdfBoundsPF(1, noPdfPoints) = 200.0;
22292 pdfTitle.push_back("strain-rate(particle-fluid)");
22293 pdfBoundsPF(2, 0) = 0.98;
22294 pdfBoundsPF(2, noPdfPoints) = 1.03;
22295 pdfTitle.push_back("pressure(particle-fluid)");
22296 pdfBoundsPF(3, 0) = 0.0;
22297 pdfBoundsPF(3, noPdfPoints) = 3.0;
22298 pdfTitle.push_back("velocity(particle-fluid)");
22299
22300 pdfBoundsPF(4, 0) = -1.5;
22301 pdfBoundsPF(4, noPdfPoints) = 1.5;
22302 pdfTitle.push_back("velX(particle-fluid)");
22303 pdfBoundsPF(5, 0) = -1.5;
22304 pdfBoundsPF(5, noPdfPoints) = 1.5;
22305 pdfTitle.push_back("velY(particle-fluid)");
22306 pdfBoundsPF(6, 0) = -1.5;
22307 pdfBoundsPF(6, noPdfPoints) = 1.5;
22308 pdfTitle.push_back("velZ(particle-fluid)");
22309 //------- Particle-related values
22310 pdfBoundsP(0, 0) = 0.0;
22311 pdfBoundsP(0, noPdfPoints) = 3.0;
22312 pdfTitle.push_back("velocity(particle)");
22313 pdfBoundsP(1, 0) = 0.0;
22314 pdfBoundsP(1, noPdfPoints) = 150.0;
22315 pdfTitle.push_back("angular-velocity(particle)");
22316 pdfBoundsP(2, 0) = 0.0;
22317 pdfBoundsP(2, noPdfPoints) = 50.0;
22318 pdfTitle.push_back("particle-Reynolds-number");
22319 pdfBoundsP(3, 0) = -10.0;
22320 pdfBoundsP(3, noPdfPoints) = 100.0;
22321 pdfTitle.push_back("F_p");
22322 pdfBoundsP(4, 0) = -2.0;
22323 pdfBoundsP(4, noPdfPoints) = 30.0;
22324 pdfTitle.push_back("F*(U_p-v_p)");
22325 pdfBoundsP(5, 0) = -8.0;
22326 pdfBoundsP(5, noPdfPoints) = 20.0;
22327 pdfTitle.push_back("F*U_p");
22328 pdfBoundsP(6, 0) = -25.0;
22329 pdfBoundsP(6, noPdfPoints) = 2.0;
22330 pdfTitle.push_back("F*v_p");
22331 pdfBoundsP(7, 0) = -2.0;
22332 pdfBoundsP(7, noPdfPoints) = 10.0;
22333 pdfTitle.push_back("T_p");
22334 pdfBoundsP(8, 0) = -0.3;
22335 pdfBoundsP(8, noPdfPoints) = 0.3;
22336 pdfTitle.push_back("T_p*(O_p-w_p)");
22337 pdfBoundsP(9, 0) = -0.2;
22338 pdfBoundsP(9, noPdfPoints) = 0.2;
22339 pdfTitle.push_back("T_p*O_p");
22340 pdfBoundsP(10, 0) = -0.3;
22341 pdfBoundsP(10, noPdfPoints) = 0.3;
22342 pdfTitle.push_back("T_p*w_p");
22343 pdfBoundsP(11, 0) = -100.0;
22344 pdfBoundsP(11, noPdfPoints) = 100.0;
22345 pdfTitle.push_back("wHat_px");
22346 pdfBoundsP(12, 0) = -100.0;
22347 pdfBoundsP(12, noPdfPoints) = 100.0;
22348 pdfTitle.push_back("wHat_py");
22349 pdfBoundsP(13, 0) = -100.0;
22350 pdfBoundsP(13, noPdfPoints) = 100.0;
22351 pdfTitle.push_back("wHat_pz");
22352 pdfBoundsP(14, 0) = -100.0;
22353 pdfBoundsP(14, noPdfPoints) = 100.0;
22354 pdfTitle.push_back("OHat_px");
22355 pdfBoundsP(15, 0) = -100.0;
22356 pdfBoundsP(15, noPdfPoints) = 100.0;
22357 pdfTitle.push_back("OHat_py");
22358 pdfBoundsP(16, 0) = -100.0;
22359 pdfBoundsP(16, noPdfPoints) = 100.0;
22360 pdfTitle.push_back("OHat_pz");
22361
22362 for(MInt i = 0; i < noPdfsPF; i++) {
22363 const MFloat DV = (pdfBoundsPF(i, noPdfPoints) - pdfBoundsPF(i, 0)) / ((MFloat)noPdfPoints);
22364 for(MInt j = 0; j < noPdfPoints; j++) {
22365 pdfBoundsPF(i, j + 1) = pdfBoundsPF(i, j) + DV;
22366 pdfPointsPF(i, j) = F1B2 * (pdfBoundsPF(i, j + 1) + pdfBoundsPF(i, j));
22367 }
22368 }
22369 for(MInt i = 0; i < noPdfsP; i++) {
22370 const MFloat DV = (pdfBoundsP(i, noPdfPoints) - pdfBoundsP(i, 0)) / ((MFloat)noPdfPoints);
22371 for(MInt j = 0; j < noPdfPoints; j++) {
22372 pdfBoundsP(i, j + 1) = pdfBoundsP(i, j) + DV;
22373 pdfPointsP(i, j) = F1B2 * (pdfBoundsP(i, j + 1) + pdfBoundsP(i, j));
22374 }
22375 }
22376
22377 for(MInt c = 0; c < noLeafCells; c++) {
22378 MInt cellId = leafCells(c);
22379 MFloat volume = a_cellVolume(cellId) / grid().gridCellVolume(maxUniformRefinementLevel());
22380 MFloat vort = F0;
22381 MFloat strain = F0;
22382 MFloat velm = F0;
22383 for(MInt i = 0; i < nDim; i++) {
22384 MInt id0 = (i + 1) % 3;
22385 MInt id1 = (id0 + 1) % 3;
22386 vort += POW2(F1B2 * (a_slope(cellId, PV->VV[id1], id0) - a_slope(cellId, PV->VV[id0], id1)));
22387 for(MInt j = 0; j < nDim; j++) {
22388 strain += POW2(F1B2 * (a_slope(cellId, PV->VV[i], j) + a_slope(cellId, PV->VV[j], i)));
22389 }
22390 velm += POW2(a_pvariable(cellId, PV->VV[i]));
22391 }
22392 vort = sqrt(vort);
22393 strain = sqrt(strain);
22394 velm = sqrt(velm);
22395 MFloat pressure = a_pvariable(cellId, PV->P) / m_PInfinity;
22396 dataPointsPF(0) = vort * DX / m_UInfinity;
22397 dataPointsPF(1) = strain * DX / m_UInfinity;
22398 dataPointsPF(2) = pressure;
22399 dataPointsPF(3) = velm / m_UInfinity;
22400 dataPointsPF(4) = a_pvariable(cellId, PV->VV[0]) / m_UInfinity;
22401 dataPointsPF(5) = a_pvariable(cellId, PV->VV[1]) / m_UInfinity;
22402 dataPointsPF(6) = a_pvariable(cellId, PV->VV[2]) / m_UInfinity;
22403 const MFloat weight = volume;
22404 for(MInt i = 0; i < noPdfsPF; i++) {
22405 meanValsPF(0, i) += weight * dataPointsPF(i);
22406 rmsValsPF(0, i) += weight * POW2(dataPointsPF(i));
22407 }
22408 sumValsPF(0) += weight;
22409
22410 for(MInt i = 0; i < noPdfsPF; i++) {
22411 const MFloat DV = (pdfBoundsPF(i, noPdfPoints) - pdfBoundsPF(i, 0)) / ((MFloat)noPdfPoints);
22412 MInt bin = (MInt)floor((dataPointsPF(i) - pdfBoundsPF(i, 0)) / DV);
22413 const MFloat kernelWidth = DV * ((MFloat)kernelSteps);
22414 const MFloat fac = F1 / (kernelWidth);
22415 if(kernelSteps == 0) {
22416 if(bin > -1 && bin < noPdfPoints) pdfValuesPFfluid(i, bin) += weight;
22417 } else {
22418 for(MInt j = bin - 5 * kernelSteps; j < bin + 5 * kernelSteps; j++) {
22419 if(j < 0 || j >= noPdfPoints) continue;
22420 MFloat t = fabs(dataPointsPF(i) - pdfPointsPF(i, j)) / DV;
22421 pdfValuesPFfluid(i, j) += fac * weight * exp(-F1B2 * POW2(t)) / sqrt(F2 * PI); // Gaussian kernel
22422 }
22423 }
22424 }
22425 }
22426
22427 for(MInt p = 0; p < noParticles; p++) {
22428 if(skipParticle(p)) continue;
22429 // --- particle-fluid
22430 MFloat velRot = F0;
22431 MFloat shear = F0;
22432 MFloat velm = F0;
22433 for(MInt i = 0; i < nDim; i++) {
22434 velRot += POW2(pOmegaHat[p * nDim + i]);
22435 for(MInt j = 0; j < nDim; j++) {
22436 shear += POW2(velShearHat[p * nDim + i]);
22437 }
22438 velm += POW2(vel[3 * p + i]);
22439 }
22440 dataPointsPF(0) = sqrt(velRot) * DX / m_UInfinity;
22441 dataPointsPF(1) = sqrt(shear) * DX / m_UInfinity;
22442 dataPointsPF(2) = particleFluidPressure[p] / m_PInfinity;
22443 dataPointsPF(3) = sqrt(velm) / m_UInfinity;
22444 dataPointsPF(4) = vel[3 * p + 0] / m_UInfinity;
22445 dataPointsPF(5) = vel[3 * p + 1] / m_UInfinity;
22446 dataPointsPF(6) = vel[3 * p + 2] / m_UInfinity;
22447 for(MInt i = 0; i < noPdfsPF; i++) {
22448 const MFloat DV = (pdfBoundsPF(i, noPdfPoints) - pdfBoundsPF(i, 0)) / ((MFloat)noPdfPoints);
22449 MInt bin = (MInt)floor((dataPointsPF(i) - pdfBoundsPF(i, 0)) / DV);
22450 const MFloat kernelWidth = DV * ((MFloat)kernelSteps);
22451 const MFloat fac = F1 / (kernelWidth);
22452 if(kernelSteps == 0) {
22453 if(bin > -1 && bin < noPdfPoints) pdfValuesPFparticle(i, bin) += F1;
22454 } else {
22455 for(MInt j = bin - 5 * kernelSteps; j < bin + 5 * kernelSteps; j++) {
22456 if(j < 0 || j >= noPdfPoints) continue;
22457 MFloat t = fabs(dataPointsPF(i) - pdfPointsPF(i, j)) / DV;
22458 pdfValuesPFparticle(i, j) += fac * exp(-F1B2 * POW2(t)) / sqrt(F2 * PI); // Gaussian kernel
22459 }
22460 }
22461 }
22462 for(MInt i = 0; i < noPdfsPF; i++) {
22463 meanValsPF(1, i) += dataPointsPF(i);
22464 rmsValsPF(1, i) += POW2(dataPointsPF(i));
22465 }
22466 sumValsPF(1) += F1;
22467 // --- particle
22468 MFloat prot = F0;
22469 MFloat partvel = F0;
22470 for(MInt i = 0; i < nDim; i++) {
22471 partvel += POW2(pvel[3 * p + i]);
22472 prot += POW2(protVelHat[3 * p + i]);
22473 }
22474 dataPointsP(0) = sqrt(partvel) / m_UInfinity;
22475 dataPointsP(1) = sqrt(prot) * DX / m_UInfinity;
22476 MFloat Rep = F0;
22477 MFloat diameter = F2 * pow(pRadii[3 * p] * pRadii[3 * p + 1] * pRadii[3 * p + 2], F1B3);
22478 for(MInt i = 0; i < nDim; i++) {
22479 Rep += POW2(vel[nDim * p + i] - pvel[nDim * p + i]);
22480 }
22481 dataPointsP(2) = sqrt(Rep) * diameter * m_rhoInfinity * sysEqn().m_Re0 / sysEqn().m_muInfinity;
22482 MFloat pF = F0;
22483 MFloat pFUv = F0;
22484 MFloat pFU = F0;
22485 MFloat pFv = F0;
22486 MFloat pT = F0;
22487 MFloat pTOw = F0;
22488 MFloat pTO = F0;
22489 MFloat pTw = F0;
22490 vector<MFloat> pForce(3, F0);
22491 vector<MFloat> pTorqueHat(3, F0);
22492 MFloat q[3];
22493 MFloatScratchSpace R(3, 3, AT_, "R");
22494 computeRotationMatrix(R, &(quats[4 * p]));
22495 if(m_noEmbeddedBodies > 0) {
22496 matrixVectorProduct(q, R, &m_bodyTorque[nDim * p]);
22497 for(MInt i = 0; i < nDim; i++) {
22498 pForce[i] = m_hydroForce[nDim * p + i];
22499 pTorqueHat[i] = q[i];
22500 }
22501 } else { // point-particles
22502 const MFloat pmass = F4B3 * PI * m_particleRadii[3 * p] * m_particleRadii[3 * p + 1]
22503 * m_particleRadii[3 * p + 2] * m_densityRatio * m_rhoInfinity;
22504 const MFloat Ix = F1B5 * (POW2(m_particleRadii[3 * p + 1]) + POW2(m_particleRadii[3 * p + 2])) * pmass;
22505 const MFloat Iy = F1B5 * (POW2(m_particleRadii[3 * p + 0]) + POW2(m_particleRadii[3 * p + 2])) * pmass;
22506 const MFloat Iz = F1B5 * (POW2(m_particleRadii[3 * p + 0]) + POW2(m_particleRadii[3 * p + 1])) * pmass;
22507 const MFloat momI[3] = {Ix, Iy, Iz};
22508 for(MInt i = 0; i < nDim; i++) {
22509 pForce[i] = pmass * m_particleAcceleration[nDim * p + i];
22510 pTorqueHat[i] = momI[i] * m_particleAngularAcceleration[3 * p + i];
22511 protVelHat[i] = protVelHat[p * 3 + i];
22512 }
22513 }
22514 for(MInt i = 0; i < nDim; i++) {
22515 pF += POW2(pForce[i]);
22516 pFUv += pForce[i] * (vel[nDim * p + i] - pvel[nDim * p + i]);
22517 pFU += pForce[i] * vel[nDim * p + i];
22518 pFv += pForce[i] * pvel[nDim * p + i];
22519 pT += POW2(pTorqueHat[i]);
22520 pTOw += pTorqueHat[i] * (pOmegaHat[p * 3 + i] - protVelHat[p * 3 + i]);
22521 pTO += pTorqueHat[i] * pOmegaHat[p * 3 + i];
22522 pTw += pTorqueHat[i] * protVelHat[p * 3 + i];
22523 }
22524 dataPointsP(3) = sqrt(pF) / (POW3(m_UInfinity) * POW2(diameter));
22525 dataPointsP(4) = pFUv / (POW3(m_UInfinity) * POW2(diameter));
22526 dataPointsP(5) = pFU / (POW3(m_UInfinity) * POW2(diameter));
22527 dataPointsP(6) = pFv / (POW3(m_UInfinity) * POW2(diameter));
22528 dataPointsP(7) = sqrt(pT) / (POW3(m_UInfinity) * POW2(diameter));
22529 dataPointsP(8) = pTOw / (POW3(m_UInfinity) * POW2(diameter));
22530 dataPointsP(9) = pTO / (POW3(m_UInfinity) * POW2(diameter));
22531 dataPointsP(10) = pTw / (POW3(m_UInfinity) * POW2(diameter));
22532
22533 for(MInt i = 0; i < nDim; i++) {
22534 dataPointsP(11 + i) = protVelHat[p * nDim + i] * DX / m_UInfinity;
22535 dataPointsP(14 + i) = pOmegaHat[p * nDim + i] * DX / m_UInfinity;
22536 }
22537 for(MInt i = 0; i < noPdfsP; i++) {
22538 meanValsP(i) += dataPointsP(i);
22539 rmsValsP(i) += POW2(dataPointsP(i));
22540 }
22541 sumValsP += F1;
22542
22543 for(MInt i = 0; i < noPdfsP; i++) {
22544 const MFloat DV = (pdfBoundsP(i, noPdfPoints) - pdfBoundsP(i, 0)) / ((MFloat)noPdfPoints);
22545 MInt bin = (MInt)floor((dataPointsP(i) - pdfBoundsP(i, 0)) / DV);
22546 const MFloat kernelWidth = DV * ((MFloat)kernelSteps);
22547 const MFloat fac = F1 / (kernelWidth);
22548 if(kernelSteps == 0) {
22549 if(bin > -1 && bin < noPdfPoints) pdfValuesP(i, bin) += F1;
22550 } else {
22551 for(MInt j = bin - 5 * kernelSteps; j < bin + 5 * kernelSteps; j++) {
22552 if(j < 0 || j >= noPdfPoints) continue;
22553 MFloat t = fabs(dataPointsP(i) - pdfPointsP(i, j)) / DV;
22554 pdfValuesP(i, j) += fac * exp(-F1B2 * POW2(t)) / sqrt(F2 * PI); // Gaussian kernel
22555 }
22556 }
22557 }
22558 }
22559
22560 if(domainId() == 0) {
22561 MPI_Reduce(MPI_IN_PLACE, &meanValsPF[0], 2 * noPdfsPF, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE",
22562 "meanValsPF[0]");
22563 MPI_Reduce(MPI_IN_PLACE, &rmsValsPF[0], 2 * noPdfsPF, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE",
22564 "rmsValsPF[0]");
22565 MPI_Reduce(MPI_IN_PLACE, &sumValsPF[0], 2, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE",
22566 "sumValsPF[0]");
22567 } else {
22568 MPI_Reduce(&meanValsPF[0], &meanValsPF[0], 2 * noPdfsPF, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE",
22569 "meanValsPF[0]");
22570 MPI_Reduce(&meanValsPF[0], &rmsValsPF[0], 2 * noPdfsPF, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE",
22571 "rmsValsPF[0]");
22572 MPI_Reduce(&meanValsPF[0], &sumValsPF[0], 2, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE",
22573 "sumValsPF[0]");
22574 }
22575
22576 if(m_noPointParticles > 0) {
22577 MPI_Reduce(MPI_IN_PLACE, &pdfValuesPFfluid[0], noPdfsPF * noPdfPoints, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_,
22578 "MPI_IN_PLACE", "pdfValuesPFfluid[0]");
22579 MPI_Reduce(MPI_IN_PLACE, &pdfValuesPFparticle[0], noPdfsPF * noPdfPoints, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_,
22580 "MPI_IN_PLACE", "pdfValuesPFparticle[0]");
22581 MPI_Reduce(MPI_IN_PLACE, &meanValsP[0], noPdfsP, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE",
22582 "meanValsP[0]");
22583 MPI_Reduce(MPI_IN_PLACE, &rmsValsP[0], noPdfsP, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE",
22584 "rmsValsP[0]");
22585 MPI_Reduce(MPI_IN_PLACE, &sumValsP, 1, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_, "MPI_IN_PLACE", "sumValsP[0]");
22586 MPI_Reduce(MPI_IN_PLACE, &pdfValuesP[0], noPdfsP * noPdfPoints, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_,
22587 "MPI_IN_PLACE", "pdfValuesP[0]");
22588 }
22589
22590 if(domainId() == 0) {
22591 for(MInt i = 0; i < noPdfsPF; i++) {
22592 meanValsPF(0, i) /= sumValsPF(0);
22593 meanValsPF(1, i) /= sumValsPF(1);
22594 rmsValsPF(0, i) = sqrt(rmsValsPF(0, i) / sumValsPF(0));
22595 rmsValsPF(1, i) = sqrt(rmsValsPF(1, i) / sumValsPF(1));
22596 }
22597 for(MInt i = 0; i < noPdfsP; i++) {
22598 meanValsP(i) /= sumValsP;
22599 rmsValsP(i) = sqrt(rmsValsP(i) / sumValsP);
22600 }
22601
22602 MFloatScratchSpace nfacsPF(noPdfsPF, 2, AT_, "nfacsPF");
22603 MFloatScratchSpace nfacsP(noPdfsP, AT_, "nfacsP");
22604 for(MInt i = 0; i < noPdfsPF; i++) {
22605 MFloat sumv = F0;
22606 MFloat sumv2 = F0;
22607 for(MInt j = 0; j < noPdfPoints; j++) {
22608 sumv += (pdfBoundsPF(i, j + 1) - pdfBoundsPF(i, j)) * pdfValuesPFfluid(i, j);
22609 sumv2 += (pdfBoundsPF(i, j + 1) - pdfBoundsPF(i, j)) * pdfValuesPFparticle(i, j);
22610 }
22611 nfacsPF(i, 0) = sumv;
22612 nfacsPF(i, 1) = sumv2;
22613 for(MInt j = 0; j < noPdfPoints; j++) {
22614 pdfValuesPFfluid(i, j) /= sumv;
22615 pdfValuesPFparticle(i, j) /= sumv2;
22616 }
22617 }
22618 for(MInt i = 0; i < noPdfsP; i++) {
22619 MFloat sumv = F0;
22620 for(MInt j = 0; j < noPdfPoints; j++) {
22621 sumv += (pdfBoundsP(i, j + 1) - pdfBoundsP(i, j)) * pdfValuesP(i, j);
22622 }
22623 nfacsP(i) = sumv;
22624 for(MInt j = 0; j < noPdfPoints; j++) {
22625 pdfValuesP(i, j) /= sumv;
22626 }
22627 }
22628 ofstream ofl;
22629 ofl.open("pdf_00" + to_string(globalTimeStep), ios_base::out | ios_base::trunc);
22630 if(ofl.is_open() && ofl.good()) {
22631 // print header --------
22632 ofl << "# average pdfs, sampled at time step " << globalTimeStep << " (time level " << m_time << ")" << endl;
22633 ofl << "#particle-fluid meanVals: #fluid #particle-fluid: ";
22634 for(MInt i = 0; i < noPdfsPF; i++) {
22635 ofl << meanValsPF(0, i) << " " << meanValsPF(1, i) << " ";
22636 }
22637 ofl << endl;
22638 ofl << "#particle-fluid rmsVals: #fluid #particle-fluid: ";
22639 for(MInt i = 0; i < noPdfsPF; i++) {
22640 ofl << rmsValsPF(0, i) << " " << rmsValsPF(1, i) << " ";
22641 }
22642 ofl << endl;
22643 ofl << "#particle meanVals: ";
22644 for(MInt i = 0; i < noPdfsP; i++) {
22645 ofl << meanValsP(i) << " ";
22646 }
22647 ofl << endl;
22648 ofl << "#particle rmsVals: ";
22649 for(MInt i = 0; i < noPdfsP; i++) {
22650 ofl << rmsValsP(i) << " ";
22651 }
22652 ofl << endl;
22653 MInt cnt = 1;
22654 for(MUint i = 0; i < noPdfsPF; i++) {
22655 ofl << "#" << cnt++ << ":" << pdfTitle[i];
22656 ofl << ", " << cnt++ << ": pdf_fluid, ";
22657 ofl << cnt++ << ": pdf_particleFluid" << endl;
22658 }
22659 for(MUint i = noPdfsPF; i < pdfTitle.size(); i++) {
22660 ofl << "#" << cnt++ << ":" << pdfTitle[i];
22661 ofl << ", " << cnt++ << ": pdf_particle" << endl;
22662 }
22663 // print header -------- finished
22664 for(MInt j = 0; j < noPdfPoints; j++) {
22665 for(MInt i = 0; i < noPdfsPF; i++) {
22666 ofl << pdfPointsPF(i, j) << " " << pdfValuesPFfluid(i, j) << " " << pdfValuesPFparticle(i, j) << " ";
22667 }
22668 for(MInt i = 0; i < noPdfsP; i++) {
22669 ofl << pdfPointsP(i, j) << " " << pdfValuesP(i, j) << " ";
22670 }
22671 for(MInt i = 0; i < noPdfsPF; i++) {
22672 ofl << nfacsPF(i, 0) << " " << nfacsPF(i, 1) << " ";
22673 }
22674 for(MInt i = 0; i < noPdfsP; i++) {
22675 ofl << nfacsP(i) << " " << nfacsP(i) << " ";
22676 }
22677 ofl << endl;
22678 }
22679 ofl.close();
22680 }
22681 }
22682 RECORD_TIMER_STOP(t_pdf);
22683 }
22684
22685 // near-particle statistics
22686 if(computeNearBody && m_noEmbeddedBodies > 0) {
22687 IF_CONSTEXPR(nDim == 2) mTerm(1, AT_, "computeNearBody not implemented for 2D!");
22688 RECORD_TIMER_START(t_near);
22689
22690 // bodyDataScatter -> scatter plot
22691 constexpr MInt noDat2 = 26;
22692 const MInt noReClasses = (m_bodyTypeMb == 3 ? 6 : 1);
22693 MFloatScratchSpace ReClass(m_noEmbeddedBodies, AT_, "ReClass");
22694 MFloatScratchSpace ReClassBounds(noReClasses, AT_, "ReClassBounds");
22695 MFloatScratchSpace bodyDataScatter(m_noEmbeddedBodies, noDat2, AT_, "bodyDataScatter");
22696 MFloatScratchSpace bodyCnt(noReClasses, AT_, "bodyCnt");
22697 bodyDataScatter.fill(F0);
22698 bodyCnt.fill(F0);
22699
22700 if(m_bodyTypeMb == 3) {
22701 ReClassBounds(0) = 0;
22702 ReClassBounds(1) = 10;
22703 ReClassBounds(2) = 40;
22704 ReClassBounds(3) = 50;
22705 ReClassBounds(4) = 80;
22706 ReClassBounds(5) = 90;
22707 }
22708
22709 RECORD_TIMER_START(t_near_bodydat2);
22710 for(MInt p = 0; p < m_noEmbeddedBodies; p++) {
22711 MFloat diameter = F2 * pow(m_bodyRadii[3 * p] * m_bodyRadii[3 * p + 1] * m_bodyRadii[3 * p + 2], F1B3);
22712 MFloat vrel[3] = {F0, F0, F0};
22713 MFloat vdir[3] = {F0, F0, F0};
22714 MFloat vpdir[3] = {F0, F0, F0};
22715 MFloat vfdir[3] = {F0, F0, F0};
22716 MFloat omegaRel[3] = {F0, F0, F0};
22717 MFloat vrel_mag = F0;
22718 MFloat vp_mag = F0;
22719 MFloat vf_mag = F0;
22720 for(MInt i = 0; i < nDim; i++) {
22721 vrel[i] = vel[nDim * p + i] - pvel[nDim * p + i];
22722 vpdir[i] = pvel[nDim * p + i];
22723 vfdir[i] = vel[nDim * p + i];
22724 vrel_mag += POW2(vrel[i]);
22725 vp_mag += POW2(vpdir[i]);
22726 vf_mag += POW2(vfdir[i]);
22727 }
22728 vrel_mag = sqrt(vrel_mag);
22729 vp_mag = sqrt(vp_mag);
22730 vf_mag = sqrt(vf_mag);
22731 for(MInt i = 0; i < nDim; i++) {
22732 vdir[i] = vrel[i] / mMax(1e-12, vrel_mag);
22733 vpdir[i] /= mMax(1e-12, vp_mag);
22734 vfdir[i] /= mMax(1e-12, vf_mag);
22735 }
22736 MFloat q[3];
22737 // fv_mb_cleanup
22738 MFloat tmp[3] = {F1, F0, F0};
22739 MFloatScratchSpace R(3, 3, AT_, "R");
22740 computeRotationMatrix(R, &(quats[4 * p]));
22741 matrixVectorProductTranspose(q, R, tmp); // orientation of z-principal axis
22742 const MFloat qabs = sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2]);
22743 for(MInt i = 0; i < nDim; i++)
22744 q[i] /= mMax(1e-12, qabs);
22745 MFloat Rep = vrel_mag * diameter * m_rhoInfinity * sysEqn().m_Re0 / sysEqn().m_muInfinity;
22746 MInt classId = -1;
22747 if(m_bodyTypeMb == 3) {
22748 MFloat aof = F0;
22749 for(MInt i = 0; i < nDim; i++) {
22750 aof += vdir[i] * q[i];
22751 }
22752 aof = acos(fabs(aof)) * 360.0 / (2.0 * PI);
22753 for(MInt i = 1; i < noReClasses; i++) {
22754 if(aof >= ReClassBounds(i - 1) && aof < ReClassBounds(i)) {
22755 classId = i;
22756 break;
22757 }
22758 }
22759 ReClass(p) = classId;
22760 bodyCnt[0] += F1;
22761 bodyCnt[classId] += F1;
22762 } else {
22763 classId = 0;
22764 ReClass(p) = classId;
22765 bodyCnt[0] += F1;
22766 bodyCnt[classId] += F1;
22767 }
22768
22769 MFloat eps0 = F0;
22770 MFloat eps1 = F0;
22771 for(MInt i = 0; i < nDim; i++) {
22772 eps0 += 5.0 * (sysEqn().m_muInfinity / sysEqn().m_Re0) * POW2(velGradient[9 * p + 3 * i + i]);
22773 for(MInt j = 0; j < nDim; j++) {
22774 eps1 += (sysEqn().m_muInfinity / sysEqn().m_Re0)
22775 * (velGradient[9 * p + 3 * i + j] + velGradient[9 * p + 3 * j + i]) * velGradient[9 * p + 3 * i + j];
22776 }
22777 }
22778 const MFloat epsRef = diameter / (POW3(m_UInfinity));
22779 MFloat wdir[3]{};
22780 MFloat pOmega[3]{};
22781 for(MInt i = 0; i < nDim; i++) {
22782 MInt id0 = (i + 1) % 3;
22783 MInt id1 = (id0 + 1) % 3;
22784 wdir[i] = F1B2 * (velGradient[9 * p + 3 * id1 + id0] - velGradient[9 * p + 3 * id0 + id1]);
22785 pOmega[i] = wdir[i];
22786 }
22787 for(MInt i = 0; i < 3; i++) {
22788 omegaRel[i] = wdir[i] - m_bodyAngularVelocity[p * 3 + i];
22789 }
22790 const MFloat wabs = sqrt(POW2(wdir[0]) + POW2(wdir[1]) + POW2(wdir[2]));
22791 for(MInt i = 0; i < nDim; i++) {
22792 wdir[i] /= mMax(1e-12, wabs);
22793 }
22794
22795 MFloat tmp2[3]{};
22796 MFloat force_frs[3]{};
22797 for(MInt i = 0; i < nDim; i++) {
22798 tmp2[i] = m_hydroForce[nDim * p + i];
22799 }
22800 matrixVectorProduct(force_frs, R, tmp2);
22801 MFloat torque_frs[3];
22802 for(MInt i = 0; i < 3; i++) {
22803 tmp2[i] = m_bodyTorque[3 * p + i];
22804 }
22805 matrixVectorProduct(torque_frs, R, tmp2);
22806
22807 MInt cnt = 0;
22808 bodyDataScatter(p, cnt++) = Rep;
22809 bodyDataScatter(p, cnt++) = sqrt(POW2(vrel[0]) + POW2(vrel[1]) + POW2(vrel[2])) / m_UInfinity;
22810 bodyDataScatter(p, cnt++) =
22811 sqrt(POW2(pvel[nDim * p + 0]) + POW2(pvel[nDim * p + 1]) + POW2(pvel[nDim * p + 2])) / m_UInfinity;
22812 bodyDataScatter(p, cnt++) =
22813 (pvel[nDim * p + 0] * vdir[0] + pvel[nDim * p + 1] * vdir[1] + pvel[nDim * p + 2] * vdir[2]) / m_UInfinity;
22814 bodyDataScatter(p, cnt++) =
22815 sqrt(POW2(vel[nDim * p + 0]) + POW2(vel[nDim * p + 1]) + POW2(vel[nDim * p + 2])) / m_UInfinity;
22816 bodyDataScatter(p, cnt++) =
22817 (vel[nDim * p + 0] * vdir[0] + vel[nDim * p + 1] * vdir[1] + vel[nDim * p + 2] * vdir[2]) / m_UInfinity;
22818 bodyDataScatter(p, cnt++) = sqrt(POW2(pOmega[0]) + POW2(pOmega[1]) + POW2(pOmega[2])) * diameter / m_UInfinity;
22819 bodyDataScatter(p, cnt++) =
22820 (pOmega[0] * vdir[0] + pOmega[1] * vdir[1] + pOmega[2] * vdir[2]) * diameter / m_UInfinity;
22821 bodyDataScatter(p, cnt++) = (vfdir[0] * vpdir[0] + vfdir[1] * vpdir[1] + vfdir[2] * vpdir[2]);
22822 bodyDataScatter(p, cnt++) = (vdir[0] * vpdir[0] + vdir[1] * vpdir[1] + vdir[2] * vpdir[2]);
22823 bodyDataScatter(p, cnt++) = (particleFluidPressure[p] - m_PInfinity) / (F1B2 * m_rhoInfinity * POW2(m_UInfinity));
22824 bodyDataScatter(p, cnt++) = eps0 * epsRef;
22825 bodyDataScatter(p, cnt++) = eps1 * epsRef;
22826 bodyDataScatter(p, cnt++) = nearBodyState[noNearBodyState * p + 0] * epsRef;
22827 bodyDataScatter(p, cnt++) = nearBodyState[noNearBodyState * p + 1] * epsRef;
22828 bodyDataScatter(p, cnt++) = nearBodyState[noNearBodyState * p + 2] * epsRef;
22829 bodyDataScatter(p, cnt++) = nearBodyState[noNearBodyState * p + 3] * epsRef;
22830 bodyDataScatter(p, cnt++) = nearBodyState[noNearBodyState * p + 4] * epsRef;
22831 bodyDataScatter(p, cnt++) = (m_hydroForce[nDim * p + 0] * vrel[0] + m_hydroForce[nDim * p + 1] * vrel[1]
22832 + m_hydroForce[nDim * p + 2] * vrel[2])
22833 / (POW3(m_UInfinity) * POW2(diameter));
22834 bodyDataScatter(p, cnt++) = (m_bodyTorque[3 * p + 0] * omegaRel[0] + m_bodyTorque[nDim * p + 1] * omegaRel[1]
22835 + m_bodyTorque[nDim * p + 2] * omegaRel[2])
22836 / (POW3(m_UInfinity) * POW2(diameter));
22837 bodyDataScatter(p, cnt++) = force_frs[0];
22838 bodyDataScatter(p, cnt++) = force_frs[1];
22839 bodyDataScatter(p, cnt++) = force_frs[2];
22840 bodyDataScatter(p, cnt++) = torque_frs[0];
22841 bodyDataScatter(p, cnt++) = torque_frs[1];
22842 bodyDataScatter(p, cnt++) = torque_frs[2];
22843
22844 if(cnt != noDat2) mTerm(1, AT_, "data size mismatch.");
22845 }
22846 RECORD_TIMER_STOP(t_near_bodydat2);
22847
22848 RECORD_TIMER_START(t_near_bodydat);
22849 // nearBodydata -> near-body flow pattern
22850 // define a local uniform grid around the particle for visualization
22851 const MFloat refRadius = m_maxBodyRadius;
22852 constexpr MInt noDat = 13;
22853 const MFloat dxm = 4.0;
22854 // const MFloat deltaR = mMin(drm, mMax(m_outerBandWidth[maxUniformRefinementLevel() + 1] / refRadius, 4.0));
22855 const MFloat deltaX =
22856 mMin(dxm, mMax(m_outerBandWidth[mMin(maxUniformRefinementLevel(), maxRefinementLevel() - 1)] / refRadius, 4.0));
22857 const MFloat dx =
22858 mMax(c_cellLengthAtLevel(maxRefinementLevel()), mMin(m_minBodyRadius / 4.0, m_maxBodyRadius / 8.0)) / refRadius;
22859 const MInt noPointsX = (MInt)((deltaX + 0.001 * dx) / dx);
22860 const MFloat deltaY = deltaX;
22861 const MInt noPointsY = noPointsX;
22862 const MFloat dy = dx;
22863 MFloatScratchSpace nearBodyData(noPointsX, noPointsY, noDat * noReClasses, AT_, "nearBodyData");
22864 MFloatScratchSpace bodySum(noPointsX, noPointsY, noReClasses, AT_, "bodySum");
22865 MFloatScratchSpace xPoints(noPointsX, AT_, "xPoints");
22866 MFloatScratchSpace xBounds(noPointsX + 1, AT_, "xBounds");
22867 MFloatScratchSpace yPoints(noPointsY, AT_, "yPoints");
22868 MFloatScratchSpace yBounds(noPointsY + 1, AT_, "yBounds");
22869 MFloatScratchSpace dat(noDat, AT_, "dat");
22870 MFloatScratchSpace K(3, 3, AT_, "K");
22871 const MInt dataSize0 = noPointsX * noPointsY * noReClasses;
22872 const MInt dataSize = noDat * dataSize0;
22873 nearBodyData.fill(F0);
22874 bodySum.fill(F0);
22875
22876 xBounds(0) = (m_bodyTypeMb == 3) ? -F1B2 * deltaX : 0.0;
22877 for(MInt i = 0; i < noPointsX; i++) {
22878 xBounds(i + 1) = xBounds(i) + dx;
22879 xPoints(i) = F1B2 * (xBounds(i) + xBounds(i + 1));
22880 }
22881 yBounds(0) = (m_bodyTypeMb == 3) ? -F1B2 * deltaY : 0.0;
22882 for(MInt i = 0; i < noPointsY; i++) {
22883 yBounds(i + 1) = yBounds(i) + dy;
22884 yPoints(i) = F1B2 * (yBounds(i) + yBounds(i + 1));
22885 }
22886
22887 for(MInt c = 0; c < noLeafCells; c++) {
22888 MInt cellId = leafCells(c);
22889 MFloat volume = F1; // no volume - weighting for nearBodyData
22890 if(volume < 1e-14) continue;
22891 if(a_level(cellId) <= maxUniformRefinementLevel()) continue;
22892
22893 for(MInt set = m_startSet; set < m_noSets; set++) {
22894 if(a_associatedBodyIds(cellId, set) < 0) continue;
22895 // const MFloat dist0 = a_levelSetValuesMb(cellId, set);
22896 const MInt p = a_associatedBodyIds(cellId, set);
22897 const MInt q = m_internalBodyId[p];
22898 if(q < 0 || q >= m_noEmbeddedBodies) {
22899 cerr << "Warning: body id " << endl;
22900 continue;
22901 }
22902 if(skipParticle(q)) continue;
22903 const MInt classId = ReClass(q);
22904 if(classId < 0) continue;
22905 MFloat diameter = F2 * pow(m_bodyRadii[3 * q] * m_bodyRadii[3 * q + 1] * m_bodyRadii[3 * q + 2], F1B3);
22906 MFloat vrel[3] = {F0, F0, F0};
22907 MFloat vdir[3] = {F0, F0, F0};
22908 MFloat vrel_mag = F0;
22909 MFloat vmag = F0;
22910 MFloat r = F0;
22911 MFloat crossp[3] = {F0, F0, F0};
22912 MFloat crossp2[3] = {F0, F0, F0};
22913 MFloat symm[3];
22914 // fv_mb_cleanup
22915 MFloat tmp[3] = {F1, F0, F0};
22916 MFloat scnt = F0;
22917 MFloatScratchSpace R(3, 3, AT_, "R");
22918 computeRotationMatrix(R, &(quats[4 * q]));
22919 matrixVectorProductTranspose(symm, R, tmp); // orientation of z-principal axis
22920 for(MInt i = 0; i < nDim; i++) {
22921 vrel[i] = vel[nDim * q + i] - pvel[nDim * q + i];
22922 vrel_mag += POW2(vrel[i]);
22923 vmag += POW2(pvel[nDim * q + i]);
22924 scnt += POW2(symm[i]);
22925 }
22926 vmag = sqrt(vmag);
22927 vrel_mag = sqrt(vrel_mag);
22928 r = sqrt(r);
22929 scnt = sqrt(scnt);
22930 for(MInt i = 0; i < nDim; i++) {
22931 vdir[i] = vrel[i] / mMax(1e-14, vrel_mag);
22932 symm[i] = symm[i] / mMax(1e-14, scnt);
22933 }
22934 if(m_bodyTypeMb == 3) {
22935 MFloat minRad = mMin(mMin(m_bodyRadii[3 * p], m_bodyRadii[3 * p + 1]), m_bodyRadii[3 * p + 2]);
22936 r = (r - minRad) / minRad;
22937 } else {
22938 r = (r - m_bodyRadius[p]) / m_bodyRadius[p];
22939 }
22940
22941 MFloat csm = F0;
22942 MFloat trans = F0;
22943 crossProduct(crossp, vdir, symm);
22944 for(MInt i = 0; i < nDim; i++) {
22945 csm += POW2(crossp[i]);
22946 }
22947 csm = sqrt(csm);
22948 for(MInt i = 0; i < nDim; i++) {
22949 crossp[i] = crossp[i] / mMax(1e-14, csm);
22950 trans += crossp[i] * (a_coordinate(cellId, i) - m_bodyCenter[nDim * p + i]);
22951 }
22952 crossProduct(crossp2, vdir, crossp);
22953 MFloat csm2 = F0;
22954 for(MInt i = 0; i < nDim; i++) {
22955 csm2 += POW2(crossp2[i]);
22956 }
22957 csm2 = sqrt(csm2);
22958 for(MInt i = 0; i < nDim; i++) {
22959 crossp2[i] = crossp2[i] / mMax(1e-14, csm2);
22960 }
22961
22962 if(fabs(trans) > mMax(F2 * c_cellLengthAtLevel(maxRefinementLevel()), c_cellLengthAtCell(cellId))) {
22963 continue;
22964 }
22965
22966 MInt idx = -1;
22967 MInt idy = -1;
22968 // Cartesian interpolation
22969 MFloat aof0 = F0;
22970 for(MInt i = 0; i < nDim; i++) {
22971 aof0 += vdir[i] * symm[i];
22972 }
22973 MFloat distx = F0;
22974 MFloat disty = F0;
22975 for(MInt i = 0; i < nDim; i++) {
22976 distx += (a_coordinate(cellId, i) - m_bodyCenter[nDim * p + i]) * vdir[i] / refRadius;
22977 disty += (a_coordinate(cellId, i) - m_bodyCenter[nDim * p + i]) * crossp2[i] / refRadius;
22978 }
22979 if(aof0 < F0) disty *= -F1;
22980 idx = (MInt)(distx / dx) + noPointsX / 2;
22981 idy = (MInt)(disty / dy) + noPointsY / 2;
22982
22983 dat.fill(F0);
22984 if(idy < 0 || idx < 0 || idy >= noPointsY || idx >= noPointsX) {
22985 continue;
22986 }
22987
22988 MInt idCnt = 0;
22989 MFloat vabs = F0;
22990 MFloat vabs2 = F0;
22991 for(MInt i = 0; i < nDim; i++) {
22992 vabs += POW2(a_pvariable(cellId, PV->VV[i]) - pvel[nDim * q + i]);
22993 vabs2 += POW2(a_pvariable(cellId, PV->VV[i]) - vel[nDim * q + i]);
22994 }
22995 vabs = sqrt(vabs);
22996 vabs2 = sqrt(vabs2);
22997 dat(idCnt++) = vabs / m_UInfinity;
22998 dat(idCnt++) = vabs / vmag;
22999 dat(idCnt++) = vabs2 / m_UInfinity;
23000 dat(idCnt++) = vabs2 / vrel_mag;
23001 MFloat cp = (a_pvariable(cellId, PV->P) - particleFluidPressure[q]);
23002 dat(idCnt++) = cp / (F1B2 * m_rhoInfinity * POW2(m_UInfinity));
23003 dat(idCnt++) = cp / (F1B2 * m_rhoInfinity * POW2(vrel_mag));
23004
23005 MFloat vort[3]{};
23006 for(MInt i = 0; i < nDim; i++) {
23007 MInt id0 = (i + 1) % 3;
23008 MInt id1 = (id0 + 1) % 3;
23009 vort[i] = F1B2 * (a_slope(cellId, PV->VV[id1], id0) - a_slope(cellId, PV->VV[id0], id1));
23010 }
23011
23012 MFloat U2 = F0;
23013 MFloat eps = F0;
23014 MFloat eps0 = F0;
23015 for(MInt i = 0; i < nDim; i++) {
23016 U2 += POW2(a_variable(cellId, CV->RHO_VV[i]) / a_variable(cellId, CV->RHO));
23017 }
23018 MFloat mue = sysEqn().m_muInfinity / sysEqn().m_Re0;
23019 MFloat Ek = F1B2 * U2;
23020 for(MInt i = 0; i < nDim; i++) {
23021 eps0 += 5.0 * mue * POW2(a_slope(cellId, PV->VV[i], i));
23022 for(MInt j = 0; j < nDim; j++) {
23023 eps +=
23024 mue * (a_slope(cellId, PV->VV[i], j) + a_slope(cellId, PV->VV[j], i)) * a_slope(cellId, PV->VV[i], j);
23025 }
23026 }
23027 const MFloat epsRef = diameter / (POW3(m_UInfinity));
23028 dat(idCnt++) = Ek / POW2(m_UInfinity);
23029 dat(idCnt++) = (Ek - meanState(0)) / POW2(m_UInfinity);
23030 dat(idCnt++) = eps * epsRef;
23031 dat(idCnt++) = eps0 * epsRef;
23032 dat(idCnt++) = (eps - meanState(3)) * epsRef;
23033 dat(idCnt++) = (eps0 - meanState(2)) * epsRef;
23034 dat(idCnt++) = (POW2(vort[0]) + POW2(vort[1]) + POW2(vort[2])) * diameter / m_UInfinity;
23035 if(idCnt != noDat) mTerm(1, AT_, "id mismatch.");
23036
23037 for(MInt i = mMax(0, idx - 3); i < mMin(noPointsX, idx + 4); i++) {
23038 for(MInt j = mMax(0, idy - 3); j < mMin(noPointsY, idy + 4); j++) {
23039 const MFloat dist = sqrt(POW2((i - idx) * dx) + POW2((j - idy) * dy));
23040 const MFloat fac =
23041 exp(-F1B4 * POW2(dist)) * a_cellVolume(cellId) / grid().gridCellVolume(maxUniformRefinementLevel());
23042 for(MInt k = 0; k < noDat; k++) {
23043 nearBodyData(i, j, k) += fac * volume * dat(k);
23044 }
23045 bodySum(i, j, 0) += fac * volume;
23046 if(classId > 0) {
23047 for(MInt k = 0; k < noDat; k++) {
23048 nearBodyData(i, j, classId * noDat + k) += fac * volume * dat(k);
23049 }
23050 bodySum(i, j, classId) += fac * volume;
23051 }
23052 }
23053 }
23054 }
23055 }
23056 MPI_Allreduce(MPI_IN_PLACE, &nearBodyData[0], dataSize, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
23057 "nearBodyData[0]");
23058 MPI_Allreduce(MPI_IN_PLACE, &bodySum[0], dataSize0, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
23059 "bodySum[0]");
23060
23061 for(MInt i = 0; i < noPointsX; i++) {
23062 for(MInt j = 0; j < noPointsY; j++) {
23063 for(MInt k = 0; k < noDat; k++) {
23064 for(MInt l = 0; l < noReClasses; l++) {
23065 if(bodySum(i, j, l) > F0) {
23066 nearBodyData(i, j, l * noDat + k) /= bodySum(i, j, l);
23067 }
23068 }
23069 }
23070 }
23071 }
23072 RECORD_TIMER_STOP(t_near_bodydat);
23073 RECORD_TIMER_START(t_near_output);
23074 // This output should be evantually generated via Netcdf
23075 if(domainId() == 0) {
23076 for(MInt l = 0; l < noReClasses; l++) {
23077 ofstream ofl;
23078 string suffix = (l > 0) ? "_class" + to_string(l) : "";
23079 ofl.open(("nearBodyData" + suffix + "_00" + to_string(globalTimeStep)).c_str(),
23080 ios_base::out | ios_base::trunc);
23081 if(ofl.is_open() && ofl.good()) {
23082 ofl << "# mean near-body statistics at time step " << globalTimeStep << ", \n";
23083 ofl << "# average number of bodies in class: " << bodyCnt[l] << "\n";
23084 ofl << "# 1: lower bound x" << endl;
23085 ofl << "# 2: upper bound x" << endl;
23086 ofl << "# 3: x-Coordinate" << endl;
23087 ofl << "# 4: lower bound y" << endl;
23088 ofl << "# 5: upper bound y" << endl;
23089 ofl << "# 6: y-Coordinate" << endl;
23090 ofl << "# 7: sample weight" << endl;
23091 ofl << "# 8-9: relative velocity abs(u-v_p)" << endl;
23092 ofl << "# 12-13: relative velocity abs(u-U_p)" << endl;
23093 ofl << "# 14-15: cp" << endl;
23094 ofl << "# 16: Ek" << endl;
23095 ofl << "# 17: Ek - Ek_mean" << endl;
23096 ofl << "# 18: eps (isotropic)" << endl;
23097 ofl << "# 19: eps0" << endl;
23098 ofl << "# 20: eps - eps_mean (isotropic)" << endl;
23099 ofl << "# 21: eps0 - eps0_mean" << endl;
23100 ofl << "# 22: vorticity magnitude" << endl;
23101 ofl << endl;
23102 for(MInt i = 0; i < noPointsX; i++) {
23103 for(MInt j = 0; j < noPointsY; j++) {
23104 ofl << xBounds(i) << " " << xBounds(i + 1) << " " << xPoints(i) << " ";
23105 ofl << yBounds(j) << " " << yBounds(j + 1) << " " << yPoints(j) << " ";
23106 ofl << bodySum(i, j, l) << " ";
23107 if(bodySum(i, j, l) > F0) {
23108 for(MInt k = 0; k < noDat; k++) {
23109 ofl << nearBodyData(i, j, l * noDat + k) << " ";
23110 }
23111 } else {
23112 for(MInt k = 0; k < noDat; k++) {
23113 ofl << F0 << " " << F0 << " ";
23114 }
23115 }
23116 ofl << endl;
23117 }
23118 ofl << endl;
23119 }
23120 }
23121 ofl.close();
23122 }
23123 }
23124 // This output should be evantually generated via Netcdf
23125 if(domainId() == 0) {
23126 ofstream ofl;
23127 ofl.open("bodyData_00" + to_string(globalTimeStep), ios_base::out | ios_base::trunc);
23128 if(ofl.is_open() && ofl.good()) {
23129 ofl << "# body statistics at time step " << globalTimeStep << endl;
23130 ofl << "# 1: Re_p" << endl;
23131 ofl << "# 2: vel_rel abs" << endl;
23132 ofl << "# 3: vel_part abs" << endl;
23133 ofl << "# 4: vel_part inline" << endl;
23134 ofl << "# 5: vel_fluid abs" << endl;
23135 ofl << "# 6: vel_fluid inline" << endl;
23136 ofl << "# 7: vorticity abs" << endl;
23137 ofl << "# 8: cosine vorticity times vrel" << endl;
23138 ofl << "# 9: cosine vel fluid times vel part " << endl;
23139 ofl << "# 10: cosine rel vel times vel part " << endl;
23140 ofl << "# 11: c_p" << endl;
23141 ofl << "# 12: eps0" << endl;
23142 ofl << "# 13: eps1" << endl;
23143 ofl << "# 14: near-body eps 0.5 d_p" << endl;
23144 ofl << "# 15: near-body eps 1.0 d_p" << endl;
23145 ofl << "# 16: near-body eps 1.5 d_p" << endl;
23146 ofl << "# 17: near-body eps 2.0 d_p" << endl;
23147 ofl << "# 18: near-body eps 2.5 d_p" << endl;
23148 ofl << "# 19: F_p * (U_p - v_p)" << endl;
23149 ofl << "# 20: T_p * (O_p - o_p)" << endl;
23150 ofl << "# 21: FxHat" << endl;
23151 ofl << "# 22: FyHat" << endl;
23152 ofl << "# 23: FzHat" << endl;
23153 ofl << "# 24: TxHat" << endl;
23154 ofl << "# 25: TyHat" << endl;
23155 ofl << "# 26: TzHat" << endl;
23156
23157 for(MInt p = 0; p < m_noEmbeddedBodies; p++) {
23158 for(MInt i = 0; i < noDat2; i++) {
23159 ofl << bodyDataScatter[noDat2 * p + i] << " ";
23160 }
23161 ofl << endl;
23162 }
23163 ofl.clear();
23164 }
23165 ofl.close();
23166 }
23167 RECORD_TIMER_STOP(t_near_output);
23168 RECORD_TIMER_STOP(t_near);
23169 }
23170
23171 if(computeFFT) {
23172 RECORD_TIMER_START(t_fft);
23173 // fft-domain dimensions
23174 // this holds the size of the domain in number of cells on lowest level
23175 const MInt fftLevel = maxUniformRefinementLevel();
23176 if(fftLevel > maxUniformRefinementLevel()) mTerm(1, AT_, "Non-isotropic mesh is not implemented, yet");
23177 if(fftLevel < minLevel()) mTerm(1, AT_, "Parents missing for fftLevel < minLevel()");
23178
23179 const MFloat dx = c_cellLengthAtLevel(fftLevel);
23180 const MFloat dxeps = 0.1 * dx;
23181 MInt nx = (m_bbox[3] - m_bbox[0] + dxeps) / dx;
23182 MInt ny = (m_bbox[4] - m_bbox[1] + dxeps) / dx;
23183 MInt nz = (m_bbox[5] - m_bbox[2] + dxeps) / dx;
23184
23185 MFloatScratchSpace coupling(a_noCells(), nDim, AT_, "coupling");
23186 MFloatScratchSpace pVariables(a_noCells(), m_noPVars, AT_, "pVariables");
23187 MFloatScratchSpace cVariables(a_noCells(), m_noCVars, AT_, "cVariables");
23188 MFloatScratchSpace oldVariables(a_noCells(), m_noCVars, AT_, "oldVariables");
23189 MInt filterLvlLaplace = fftLevel;
23190 filterLvlLaplace = Context::getSolverProperty<MInt>("filterLvlLaplace", m_solverId, AT_, &filterLvlLaplace);
23191
23192 MFloat couplingCheck = determineCoupling(coupling);
23193 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23194 for(MInt i = 0; i < m_noPVars; i++) {
23195 pVariables(cellId, i) = a_pvariable(cellId, i);
23196 }
23197 for(MInt i = 0; i < m_noCVars; i++) {
23198 cVariables(cellId, i) = a_variable(cellId, i);
23199 oldVariables(cellId, i) = a_oldVariable(cellId, i);
23200 }
23201 }
23202 if(domainId() == 0)
23203 cerr << "coupling check " << couplingCheck << " " << m_couplingRate << " " << couplingCheck / (DX * DX * DX)
23204 << " " << m_couplingRate / (DX * DX * DX) << " " << DX * m_couplingRate / POW3(DX * m_UInfinity) << endl;
23205
23206 // Apply volumetric filter
23207 if(maxRefinementLevel() != fftLevel) {
23208 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23209 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
23210 if(a_isPeriodic(cellId)) continue;
23211 if(a_bndryId(cellId) < -1) continue;
23212 if(a_isHalo(cellId)) continue;
23213 if(a_level(cellId) != fftLevel) continue;
23214 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(cellId) > 0) {
23215 reduceData(cellId, &coupling(0), nDim, false);
23216 reduceData(cellId, &(pVariables(0, 0)), m_noPVars);
23217 reduceData(cellId, &(cVariables(0, 0)), m_noCVars);
23218 reduceData(cellId, &(oldVariables(0, 0)), m_noCVars);
23219 }
23220 }
23221 }
23222
23223 MInt noLocDat = 0;
23224 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23225 if(a_isHalo(cellId)) continue;
23226 if(a_isBndryGhostCell(cellId)) continue;
23227 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
23228 if(a_level(cellId) != fftLevel) continue;
23229 noLocDat++;
23230 }
23231 MFloatScratchSpace velDat(noLocDat, 3 * nDim, AT_, "velDat");
23232 MIntScratchSpace velPos(noLocDat, AT_, "velPos");
23233 noLocDat = 0;
23234 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23235 if(a_isHalo(cellId)) continue;
23236 if(a_isBndryGhostCell(cellId)) continue;
23237 if(a_level(cellId) != fftLevel) continue;
23238 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
23239 MFloat actualCellLength = c_cellLengthAtCell(cellId);
23240 MInt xPos = floor((F1B2 * nx + (a_coordinate(cellId, 0) - F1B2 * (actualCellLength)) / dx) + 0.1);
23241 MInt yPos = floor((F1B2 * ny + (a_coordinate(cellId, 1) - F1B2 * (actualCellLength)) / dx) + 0.1);
23242 MInt zPos = floor((F1B2 * nz + (a_coordinate(cellId, 2) - F1B2 * (actualCellLength)) / dx) + 0.1);
23243 if(xPos > nx - 1 || xPos < 0 || yPos > ny - 1 || yPos < 0 || zPos > nz - 1 || zPos < 0) {
23244 cerr << "ERROR: wrong array position!" << endl;
23245 cerr << "pos=" << xPos << ", " << yPos << ", " << zPos << endl;
23246 cerr << "coorda = (" << a_coordinate(cellId, 0) << ", " << a_coordinate(cellId, 1) << ", "
23247 << a_coordinate(cellId, 2) << ")" << endl;
23248 cerr << "actuallength=" << actualCellLength << endl;
23249 cerr << "minlevel=" << minLevel() << ", maxLevel=" << maxLevel() << endl;
23250 cerr << "lenght on level0=" << c_cellLengthAtLevel(0) << endl;
23251 mTerm(1, AT_, "Wrong array position");
23252 }
23253 MInt pos = zPos + nz * (yPos + ny * xPos);
23254 for(MInt i = 0; i < nDim; i++) {
23255 velDat(noLocDat, i) = pVariables(cellId, PV->VV[i]) / m_UInfinity;
23256 velDat(noLocDat, nDim + i) = coupling(cellId, i) * DX / (grid().gridCellVolume(fftLevel) * POW2(m_UInfinity));
23257 MFloat u1 = cVariables(cellId, CV->RHO_VV[i]) / cVariables(cellId, CV->RHO);
23258 MFloat u0 = oldVariables(cellId, CV->RHO_VV[i]) / oldVariables(cellId, CV->RHO);
23259 velDat(noLocDat, 2 * nDim + i) = ((u1 - u0) / timeStep()) * DX / POW2(m_UInfinity);
23260 }
23261 if(m_noPointParticles > 0 && m_pointParticleTwoWayCoupling > 0) {
23262 for(MInt i = 0; i < nDim; i++) {
23263 velDat(noLocDat, nDim + i) =
23264 m_coupling[cellId][i] * (DX / (grid().gridCellVolume(fftLevel) * POW2(m_UInfinity)));
23265 }
23266 }
23267 velPos(noLocDat) = pos;
23268 noLocDat++;
23269 }
23270
23271 maia::math::computeEnergySpectrum(velDat, velPos, 3 * nDim, noLocDat, nx, ny, nz,
23272 F1 / (sysEqn().m_Re0 * DX * m_UInfinity), mpiComm());
23273
23274 RECORD_TIMER_STOP(t_fft);
23275 }
23276
23277 m_firstStats = false;
23278
23279 RECORD_TIMER_STOP(t_timertotal);
23280 DISPLAY_TIMER(t_timertotal);
23281}
23282
23283
23284template <MInt nDim, class SysEqn>
23286 TRACE();
23287 if(m_noEmbeddedBodies > 0) {
23288 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23289 if(a_bndryId(cellId) < -1) continue;
23290 if(a_isHalo(cellId)) continue;
23291 if(a_isPeriodic(cellId)) continue;
23292 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(cellId) > 0) continue;
23293
23294 if(a_levelSetValuesMb(cellId, 0) < F0 || a_bndryId(cellId) >= m_noOuterBndryCells) {
23295 if(m_associatedBodyIds[IDX_LSSETMB(cellId, 0)] < 0
23296 || m_associatedBodyIds[IDX_LSSETMB(cellId, 0)] > m_noEmbeddedBodies + m_noPeriodicGhostBodies) {
23297 cerr << domainId() << ": negative body id B " << m_associatedBodyIds[IDX_LSSETMB(cellId, 0)] << " "
23298 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " "
23299 << a_hasProperty(cellId, SolverCell::IsSplitChild) << endl;
23300 continue;
23301 }
23302 MInt bodyId = m_internalBodyId[m_associatedBodyIds[IDX_LSSETMB(cellId, 0)]];
23303 MFloat svol = grid().gridCellVolume(a_level(cellId));
23304 if(a_bndryId(cellId) > -1) svol -= a_cellVolume(cellId);
23305 partVol(bodyId) += svol;
23306 if(a_bndryId(cellId) < 0 && a_hasProperty(cellId, SolverCell::IsInactive)) a_cellVolume(cellId) = F0;
23307 }
23308 }
23309 MPI_Allreduce(MPI_IN_PLACE, &partVol[0], m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
23310 "partVol[0]");
23311 return;
23312 } else {
23313 cerr0 << "computeBodyVolume skipped since there are no Bodies." << endl;
23314 return;
23315 }
23316}
23317
23318
23326template <MInt nDim, class SysEqn>
23328 const MIntScratchSpace& nearestBodies, const MFloatScratchSpace& nearestDist, MFloat* vel, MFloat* velGrad,
23329 MFloat* rotation, const vector<MFloat>& setup, MInt* skipBodies, MFloat* meanBodyState, MFloat* pressure,
23330 MFloat* velDt, MFloat* rotationDt, MFloat* nearestFac) {
23331 TRACE();
23332
23333 if(m_noEmbeddedBodies == 0) return;
23334
23335 const MFloat minDist = (setup.size() >= 1 ? setup[0] : 0.5) * m_bodyDiameter[0];
23336 const MFloat maxDist = (setup.size() >= 2 ? setup[1] : 4.0) * m_bodyDiameter[0];
23337 const MFloat maxAngleVel = (setup.size() >= 3 ? setup[2] : F0);
23338 const MFloat maxAngleRot = (setup.size() >= 4 ? setup[3] : F0);
23339 const MFloat sigma = (setup.size() >= 5 ? setup[2] : (maxDist - minDist) / 6.0);
23340 const MFloat D0 = (setup.size() >= 6 ? setup[3] : (maxDist + minDist) / F2); // distance for peak weight
23341
23342 if(minDist > maxDist || maxAngleVel < -F1 || maxAngleRot < -F1) {
23343 cerr << "computeNearBodyFluidVelocity: wrong setup " << endl;
23344 return;
23345 }
23346
23347 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
23348 for(MInt i = 0; i < nDim; i++) {
23349 vel[b * nDim + i] = F0;
23350 rotation[b * nDim + i] = F0;
23351 for(MInt j = 0; j < nDim; j++) {
23352 velGrad[b * nDim * nDim + i * nDim + j] = F0;
23353 }
23354 }
23355 }
23356
23357 if(nearestFac != NULL) {
23358 std::fill_n(nearestFac, m_maxNearestBodies * a_noCells(), F0);
23359 }
23360
23361 MFloatScratchSpace weights(m_noEmbeddedBodies, AT_, "weights");
23362 MFloatScratchSpace vel0((velDt || rotationDt || meanBodyState) ? m_noEmbeddedBodies : 1, nDim, AT_, "vel0");
23363 weights.fill(F0);
23364 vel0.fill(F0);
23365
23366 vector<vector<MInt>> velCells(m_noEmbeddedBodies);
23367 vector<vector<MInt>> rotCells(m_noEmbeddedBodies);
23368 MInt noLeafCells = 0;
23369 MIntScratchSpace leafCells(a_noCells(), AT_, "leafCells");
23370 MIntScratchSpace skipBody(m_noEmbeddedBodies, AT_, "skipBody");
23371
23372 {
23373 MInt cnt1 = 0;
23374 MInt cnt2 = 0;
23375 for(MInt bodyId = 0; bodyId < m_noEmbeddedBodies; bodyId++) {
23376 skipBody(bodyId) = 0;
23377 MFloat hydroForceAbs = F0;
23378 for(MInt i = 0; i < nDim; i++) {
23379 hydroForceAbs += POW2(m_hydroForce[bodyId * nDim + i]);
23380 }
23381 if(hydroForceAbs < 1e-12) {
23382 skipBody(bodyId) = 1;
23383 cnt1++;
23384 }
23385 if(m_bodyInCollision[bodyId] > 0) {
23386 skipBody(bodyId) = 1;
23387 cnt2++;
23388 }
23389 }
23390 m_log << "computeNearBodyFluidVelocities: noBodies skipped (small Body force): " << cnt1 << " collision: " << cnt2
23391 << " " << minDist / m_bodyDiameter[0] << " " << maxDist / m_bodyDiameter[0] << " " << maxAngleVel << endl;
23392 }
23393
23394 MLong smallGradPhi = 0;
23395 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23396 if(a_isBndryGhostCell(cellId)) continue;
23397 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(cellId) > 0) continue;
23398 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
23399 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
23400 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
23401 if(a_hasProperty(cellId, SolverCell::IsSplitChild) ? a_hasProperty(getAssociatedInternalCell(cellId), Cell::IsHalo)
23402 : a_hasProperty(cellId, Cell::IsHalo))
23403 continue;
23404 if(a_hasProperty(cellId, SolverCell::IsSplitChild) ? a_isPeriodic(getAssociatedInternalCell(cellId))
23405 : a_isPeriodic(cellId))
23406 continue;
23407 leafCells(noLeafCells++) = cellId;
23408 for(MInt nb = 0; nb < m_maxNearestBodies; nb++) {
23409 const MInt bodyId0 = nearestBodies[m_maxNearestBodies * cellId + nb];
23410 if(bodyId0 < 0) continue;
23411 const MInt bodyId = m_internalBodyId[bodyId0];
23412 if(skipBody(bodyId)) continue;
23413 const MFloat phi = nearestDist[m_maxNearestBodies * cellId + nb];
23414 if(phi > minDist && phi < maxDist) {
23415 MFloat gradPhi[3] = {F0, F0, F0};
23416 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
23417 cerr << "debug state splitChild in CNBFV 1"
23418 << " remove this message, if it was reached and everything went fine" << endl;
23419 MInt splitChildBndryId = a_bndryId(cellId);
23420 if(m_bndryCells->a[splitChildBndryId].m_noSrfcs > 1)
23421 cerr << "SplitChilds due to collision should not appear here." << endl;
23422 for(MInt i = 0; i < nDim; i++) {
23423 gradPhi[i] = m_fvBndryCnd->m_bndryCells->a[splitChildBndryId].m_srfcs[0]->m_normalVector[i];
23424 }
23425 } else {
23426 for(MInt i = 0; i < nDim; i++) {
23427 MInt n0 = (a_hasNeighbor(cellId, 2 * i, false) > 0) ? c_neighborId(cellId, 2 * i, false) : cellId;
23428 MInt n1 = (a_hasNeighbor(cellId, 2 * i + 1, false) > 0) ? c_neighborId(cellId, 2 * i + 1, false) : cellId;
23429 if(n0 > -1 && n1 > -1) {
23430 MInt nb0, nb1;
23431 for(nb0 = 0; nb0 < m_maxNearestBodies; nb0++) {
23432 if(nearestBodies[m_maxNearestBodies * n0 + nb0] == bodyId0) break;
23433 }
23434 for(nb1 = 0; nb1 < m_maxNearestBodies; nb1++) {
23435 if(nearestBodies[m_maxNearestBodies * n1 + nb1] == bodyId0) break;
23436 }
23437 if(nb0 < m_maxNearestBodies && nb1 < m_maxNearestBodies) {
23438 gradPhi[i] = (nearestDist[m_maxNearestBodies * n1 + nb1] - nearestDist[m_maxNearestBodies * n0 + nb0])
23439 / (a_coordinate(n1, i) - a_coordinate(n0, i));
23440 }
23441 }
23442 }
23443 }
23444 MFloat distDotVelGuess = F0;
23445 MFloat gradPhiAbs = F0;
23446 MFloat hydroForceAbs = F0;
23447 for(MInt i = 0; i < nDim; i++) {
23448 distDotVelGuess += gradPhi[i] * m_hydroForce[bodyId * nDim + i];
23449 gradPhiAbs += POW2(gradPhi[i]);
23450 hydroForceAbs += POW2(m_hydroForce[bodyId * nDim + i]);
23451 }
23452 if(gradPhiAbs < 1e-12) {
23453 smallGradPhi++;
23454 continue;
23455 }
23456 MFloat angle = distDotVelGuess / sqrt(gradPhiAbs * hydroForceAbs);
23457 if(angle < maxAngleVel) {
23458 MFloat velWeight = a_cellVolume(cellId);
23459 MFloat distanceBasedWeight = F1 / sqrt(F2 * PI * POW2(sigma)) * exp(-POW2(phi - D0) / (F2 * POW2(sigma)));
23460 velWeight *= distanceBasedWeight;
23461 weights(bodyId) += velWeight;
23462 for(MInt i = 0; i < nDim; i++) {
23463 vel[bodyId * nDim + i] += velWeight * a_pvariable(cellId, PV->VV[i]);
23464 }
23465 if(nearestFac != NULL) {
23466 nearestFac[m_maxNearestBodies * cellId + nb] += velWeight;
23467 }
23468 velCells[bodyId].push_back(cellId);
23469 if(velDt || rotationDt || meanBodyState) {
23470 for(MInt i = 0; i < nDim; i++) {
23471 vel0(bodyId, i) += velWeight * a_oldVariable(cellId, CV->RHO_VV[i]) / a_oldVariable(cellId, CV->RHO);
23472 }
23473 }
23474 }
23475 if(distDotVelGuess / sqrt(gradPhiAbs * hydroForceAbs) < maxAngleRot) {
23476 rotCells[bodyId].push_back(cellId);
23477 }
23478 }
23479 }
23480 }
23481
23482 MLong globalSmallGradPhi = 0;
23483 MPI_Reduce(&smallGradPhi, &globalSmallGradPhi, 1, MPI_LONG, MPI_SUM, 0, mpiComm(), AT_, "smallGradPhi",
23484 "globalSmallGradPhi");
23485 if(globalSmallGradPhi > 0) {
23486 m_log << "Skipping cells for nearBodyFluidVelocities (small gradPhi) " << globalSmallGradPhi << " "
23487 << minDist / m_bodyDiameter[0] << " " << maxDist / m_bodyDiameter[0] << " " << maxAngleVel << endl;
23488 }
23489
23490 MPI_Allreduce(MPI_IN_PLACE, &vel[0], nDim * m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
23491 "vel[0]");
23492 MPI_Allreduce(MPI_IN_PLACE, &weights[0], m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
23493 "weights[0]");
23494
23495 if(velDt || rotationDt || meanBodyState) {
23496 MPI_Allreduce(MPI_IN_PLACE, &vel0[0], nDim * m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
23497 "MPI_IN_PLACE", "vel0[0]");
23498 }
23499
23500 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
23501 if((weights(b) < 1e-10) && !skipBody(b)) {
23502 if(domainId() == 0)
23503 cerr << setprecision(12) << "Warning: near body velocity interpolation " << b << " " << weights(b) << " "
23504 << minDist / m_bodyDiameter[0] << " " << maxDist / m_bodyDiameter[0] << " " << maxAngleVel << endl;
23505 skipBody(b) = 1;
23506 }
23507 for(MInt i = 0; i < nDim; i++) {
23508 vel[b * nDim + i] /= mMax(1e-10, weights(b));
23509 if(velDt || rotationDt || meanBodyState) vel0(b, i) /= mMax(1e-10, weights(b));
23510 }
23511 }
23512 if(velDt) {
23513 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
23514 for(MInt i = 0; i < nDim; i++) {
23515 velDt[b * nDim + i] = vel0(b, i);
23516 }
23517 }
23518 }
23519
23520 if(nearestFac != NULL) {
23521 for(MInt c = 0; c < noLeafCells; c++) {
23522 MInt cellId = leafCells(c);
23523 for(MInt nb = 0; nb < m_maxNearestBodies; nb++) {
23524 const MInt bodyId0 = nearestBodies[m_maxNearestBodies * cellId + nb];
23525 if(bodyId0 < 0) continue;
23526 const MInt bodyId = m_internalBodyId[bodyId0];
23527 nearestFac[m_maxNearestBodies * cellId + nb] /= weights(bodyId);
23528 }
23529 }
23530 }
23531
23532 weights.fill(F0);
23533 for(MInt bodyId = 0; bodyId < m_noEmbeddedBodies; bodyId++) {
23534 for(auto const& cellId : rotCells[bodyId]) {
23535 MInt bodyId0 = -1;
23536 MFloat phi = F0;
23537 for(MInt nb = 0; nb < m_maxNearestBodies; nb++) {
23538 if(nearestBodies[m_maxNearestBodies * cellId + nb] > -1
23539 && m_internalBodyId[nearestBodies[m_maxNearestBodies * cellId + nb]] == bodyId) {
23540 bodyId0 = nearestBodies[m_maxNearestBodies * cellId + nb];
23541 phi = nearestDist[m_maxNearestBodies * cellId + nb];
23542 if(bodyId0 < 0)
23543 cerr << "bodyId not found " << bodyId0 << " bodyId " << bodyId << " domainId() " << domainId() << endl;
23544 MFloat gradPhi[3] = {F0, F0, F0};
23545 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
23546 cerr << "debug state splitChild in CNBFV 2"
23547 << " remove this message, if it was reached and everything went fine" << endl;
23548 MInt splitChildBndryId = a_bndryId(cellId);
23549 if(m_bndryCells->a[splitChildBndryId].m_noSrfcs > 1)
23550 cerr << "SplitChilds due to collision should not appear here." << endl;
23551 for(MInt i = 0; i < nDim; i++) {
23552 gradPhi[i] = m_fvBndryCnd->m_bndryCells->a[splitChildBndryId].m_srfcs[0]->m_normalVector[i];
23553 }
23554 } else {
23555 for(MInt i = 0; i < nDim; i++) {
23556 MInt n0 = (a_hasNeighbor(cellId, 2 * i, false) > 0) ? c_neighborId(cellId, 2 * i, false) : cellId;
23557 MInt n1 = (a_hasNeighbor(cellId, 2 * i + 1, false) > 0) ? c_neighborId(cellId, 2 * i + 1, false) : cellId;
23558 if(n0 == n1) cerr << "wrong neighbors" << endl;
23559 if(n0 > -1 && n1 > -1) {
23560 MInt nb0, nb1;
23561 for(nb0 = 0; nb0 < m_maxNearestBodies; nb0++) {
23562 if(nearestBodies[m_maxNearestBodies * n0 + nb0] == bodyId0) break;
23563 }
23564 for(nb1 = 0; nb1 < m_maxNearestBodies; nb1++) {
23565 if(nearestBodies[m_maxNearestBodies * n1 + nb1] == bodyId0) break;
23566 }
23567 if(nb0 < m_maxNearestBodies && nb1 < m_maxNearestBodies) {
23568 gradPhi[i] = (nearestDist[m_maxNearestBodies * n1 + nb1] - nearestDist[m_maxNearestBodies * n0 + nb0])
23569 / (a_coordinate(n1, i) - a_coordinate(n0, i));
23570 }
23571 }
23572 }
23573 }
23574
23575 MFloat gradPhiAbs = F0;
23576 for(MInt i = 0; i < nDim; i++) {
23577 gradPhiAbs += POW2(gradPhi[i]);
23578 }
23579 if(gradPhiAbs < 1e-12) {
23580 continue;
23581 }
23582 MFloat rot[3]{};
23583 MFloat rot0[3]{};
23584 MFloat rad[3]{};
23585 MFloat rad0[3]{};
23586 MFloat vpr[3]{};
23587 MFloat vpr0[3]{};
23588 MFloat r2 = F0;
23589 MFloat r20 = F0;
23590 MFloat rotWeight = a_cellVolume(cellId);
23591 MFloat distanceBasedWeight = F1 / sqrt(F2 * PI * POW2(sigma)) * exp(-POW2(phi - D0) / (F2 * POW2(sigma)));
23592 rotWeight *= distanceBasedWeight;
23593 for(MInt i = 0; i < nDim; i++) {
23594 rad[i] = a_coordinate(cellId, i) - m_bodyCenter[bodyId0 * nDim + i];
23595 vpr[i] = a_pvariable(cellId, PV->VV[i]) - vel[bodyId * nDim + i];
23596 r2 += POW2(rad[i]);
23597 for(MInt j = 0; j < nDim; j++) {
23598 velGrad[bodyId * nDim * nDim + i * nDim + j] += rotWeight * a_slope(cellId, PV->VV[i], j);
23599 }
23600 }
23601 crossProduct(rot, rad, vpr);
23602 for(MInt i = 0; i < nDim; i++) {
23603 rotation[bodyId * nDim + i] += rotWeight * rot[i] / r2;
23604 }
23605 if(velDt || rotationDt || meanBodyState) {
23606 for(MInt i = 0; i < nDim; i++) {
23607 rad0[i] = a_coordinate(cellId, i)
23608 - (m_bodyCenter[bodyId0 * nDim + i] + m_bodyCenterDt1[bodyId * nDim + i]
23609 - m_bodyCenter[bodyId * nDim + i]);
23610 vpr0[i] = a_oldVariable(cellId, CV->RHO_VV[i]) / a_oldVariable(cellId, CV->RHO) - vel0(bodyId, i);
23611 r20 += POW2(rad0[i]);
23612 }
23613 crossProduct(rot0, rad0, vpr0);
23614 }
23615 if(rotationDt) {
23616 for(MInt i = 0; i < nDim; i++) {
23617 rotationDt[bodyId * nDim + i] += rotWeight * (rot0[i] / r20);
23618 }
23619 }
23620 weights(bodyId) += rotWeight;
23621 }
23622 }
23623 }
23624 }
23625
23626 MPI_Allreduce(MPI_IN_PLACE, &weights[0], m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
23627 "weights[0]");
23628 MPI_Allreduce(MPI_IN_PLACE, &velGrad[0], nDim * nDim * m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
23629 "MPI_IN_PLACE", "velGrad[0]");
23630 MPI_Allreduce(MPI_IN_PLACE, &rotation[0], nDim * m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
23631 "MPI_IN_PLACE", "rotation[0]");
23632 if(rotationDt)
23633 MPI_Allreduce(MPI_IN_PLACE, &rotationDt[0], nDim * m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
23634 "MPI_IN_PLACE", "rotationDt[0]");
23635
23636 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
23637 if(domainId() == 0 && weights(b) < 1e-10 && !skipBody(b)) {
23638 cerr << setprecision(12) << "Warning: near body velocity gradient interpolation " << b << " " << weights(b) << " "
23639 << minDist / m_bodyDiameter[0] << " " << maxDist / m_bodyDiameter[0] << " " << maxAngleRot << endl;
23640 }
23641 for(MInt i = 0; i < nDim; i++) {
23642 rotation[b * nDim + i] /= mMax(1e-10, weights(b));
23643 for(MInt j = 0; j < nDim; j++) {
23644 velGrad[b * nDim * nDim + i * nDim + j] /= mMax(1e-10, weights(b));
23645 }
23646 }
23647 }
23648
23649 if(rotationDt) {
23650 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
23651 for(MInt i = 0; i < nDim; i++) {
23652 rotationDt[b * nDim + i] /= mMax(1e-10, weights(b));
23653 }
23654 }
23655 }
23656
23657 if(meanBodyState && pressure) {
23658 const MInt noNearBodyState = 5;
23659 weights.fill(F0);
23660 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
23661 pressure[b] = F0;
23662 for(MInt i = 0; i < noNearBodyState; i++) {
23663 meanBodyState[noNearBodyState * b + i] = F0;
23664 }
23665 }
23666
23667 for(MInt c = 0; c < noLeafCells; c++) {
23668 MInt cellId = leafCells(c);
23669 for(MInt nb = 0; nb < m_maxNearestBodies; nb++) {
23670 const MInt bodyId0 = nearestBodies[m_maxNearestBodies * cellId + nb];
23671 if(bodyId0 < 0) continue;
23672 const MInt bodyId = m_internalBodyId[bodyId0];
23673 // if(skipBody(bodyId)) continue;
23674 const MFloat phi = nearestDist[m_maxNearestBodies * cellId + nb];
23675 MFloat weight = a_cellVolume(cellId);
23676 MFloat distanceBasedWeight = F1 / sqrt(F2 * PI * POW2(sigma)) * exp(-POW2(phi - D0) / (F2 * POW2(sigma)));
23677 weight *= distanceBasedWeight;
23678 pressure[bodyId] += weight * a_pvariable(cellId, PV->P);
23679 weights(bodyId) += weight;
23680 MFloat eps1 = F0;
23681 for(MInt i = 0; i < nDim; i++) {
23682 for(MInt j = 0; j < nDim; j++) {
23683 eps1 += F1B2 * (sysEqn().m_muInfinity / sysEqn().m_Re0)
23684 * POW2(a_slope(cellId, PV->VV[i], j) + a_slope(cellId, PV->VV[j], i));
23685 }
23686 }
23687
23688 if(phi < 0.5 * m_bodyDiameter[bodyId]) meanBodyState[noNearBodyState * bodyId] += a_cellVolume(cellId) * eps1;
23689 if(phi < 1.0 * m_bodyDiameter[bodyId])
23690 meanBodyState[noNearBodyState * bodyId + 1] += a_cellVolume(cellId) * eps1;
23691 if(phi < 1.5 * m_bodyDiameter[bodyId])
23692 meanBodyState[noNearBodyState * bodyId + 2] += a_cellVolume(cellId) * eps1;
23693 if(phi < 2.0 * m_bodyDiameter[bodyId])
23694 meanBodyState[noNearBodyState * bodyId + 3] += a_cellVolume(cellId) * eps1;
23695 if(phi < 2.5 * m_bodyDiameter[bodyId])
23696 meanBodyState[noNearBodyState * bodyId + 4] += a_cellVolume(cellId) * eps1;
23697 }
23698 }
23699
23700 MPI_Allreduce(MPI_IN_PLACE, &weights[0], m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
23701 "weights[0]");
23702 MPI_Allreduce(MPI_IN_PLACE, &pressure[0], m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
23703 "pressure[0]");
23704 MPI_Allreduce(MPI_IN_PLACE, &meanBodyState[0], noNearBodyState * m_noEmbeddedBodies, MPI_DOUBLE, MPI_SUM, mpiComm(),
23705 AT_, "MPI_IN_PLACE", "meanBodyState[0]");
23706
23707 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
23708 if(domainId() == 0 && weights(b) < 1e-10 && !skipBody(b)) {
23709 cerr << "Warning: near body pressure interpolation " << b << " " << weights(b) / m_bodyVolume[b] << " "
23710 << minDist / m_bodyDiameter[0] << " " << maxDist / m_bodyDiameter[0] << " " << maxAngleVel << endl;
23711 }
23712 pressure[b] /= mMax(1e-10, weights(b));
23713 }
23714 }
23715
23716 if(skipBodies) {
23717 MInt cnt = 0;
23718 for(MInt b = 0; b < m_noEmbeddedBodies; b++) {
23719 skipBodies[b] = skipBody(b);
23720 if(skipBody(b)) cnt++;
23721 }
23722 if(domainId() == 0 && cnt > 0 && globalTimeStep % m_dragOutputInterval == 0)
23723 m_log << "computeNearBodyFluidVelocities: noBodies skipped " << cnt << " (" << globalTimeStep << ")" << endl;
23724 }
23725}
23726
23727
23732template <MInt nDim, class SysEqn>
23734 writeVtkXmlFiles("Q_ERR", "G_ERR", 0, 0);
23735}
23736
23737
23742template <MInt nDim, class SysEqn>
23744 MBool regularOutput, MBool diverged) {
23745 TRACE();
23746
23748
23749 const MBool correctCoords = m_fvBndryCnd->m_cellCoordinatesCorrected;
23750 if(correctCoords) m_fvBndryCnd->recorrectCellCoordinates();
23751
23752 if(diverged) {
23753 m_haloCellOutput = true;
23754 m_vtuGeometryOutputExtended = true;
23755 m_vtuGlobalIdOutput = true;
23756 m_vtuDomainIdOutput = true;
23757 m_vtuLevelSetOutput = false;
23758 m_vtuVelocityGradientOutput = true;
23759 }
23760 restoreNeighbourLinks();
23761 IF_CONSTEXPR(nDim == 3) {
23762 if(true || regularOutput || noDomains() > 24) {
23763 extractPointIdsFromGrid(m_extractedCells, m_gridPoints, false, m_splitChildToSplitCell, m_vtuLevelThreshold,
23764 m_vtuCoordinatesThreshold);
23765 if(m_vtuLevelThreshold < maxRefinementLevel()) reduceVariables();
23766 deleteNeighbourLinks();
23767 MInt noSolverSpecificVars = (m_vtuLevelSetOutput > 0 ? 1 : 0);
23768 MFloatScratchSpace levelSetOutput((noSolverSpecificVars > 0 ? a_noCells() : 1), AT_, "levelSetOutput");
23769 if(m_vtuLevelSetOutput) {
23770 noSolverSpecificVars = 1;
23771 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23772 levelSetOutput(cellId) = a_levelSetValuesMb(cellId, 0);
23773 }
23774 }
23775 MString fName;
23776 MString gName;
23777 if(!m_multipleFvSolver) {
23778 fName = m_solutionOutput + fileName + "_00" + to_string(globalTimeStep) + ".vtu";
23779 gName = m_solutionOutput + GFileName + "_00" + to_string(globalTimeStep) + ".vtp";
23780 } else {
23781 fName = m_solutionOutput + fileName + "_s" + to_string(solverId()) + "_00" + to_string(globalTimeStep) + ".vtu";
23782 gName =
23783 m_solutionOutput + GFileName + "_s" + to_string(solverId()) + "_00" + to_string(globalTimeStep) + ".vtp";
23784 }
23785 if(m_solutionDiverged && !m_multipleFvSolver) {
23786 fName = m_solutionOutput + fileName + "_diverged_00" + to_string(globalTimeStep) + ".vtu";
23787 gName = m_solutionOutput + GFileName + "_diverged_00" + to_string(globalTimeStep) + ".vtp";
23788 } else if(m_solutionDiverged) {
23789 fName = m_solutionOutput + fileName + "_s" + to_string(solverId()) + "_diverged_00" + to_string(globalTimeStep)
23790 + ".vtu";
23791 gName = m_solutionOutput + GFileName + "_s" + to_string(solverId()) + "_diverged_00" + to_string(globalTimeStep)
23792 + ".vtp";
23793 }
23794 if(domainId() == 0) {
23795 cerr << "Writing " << fName << " at time step " << globalTimeStep << "... ";
23796 }
23797
23798 VtkIo.writeVtuOutputParallel(fName.c_str(), gName.c_str(), noSolverSpecificVars, levelSetOutput);
23799
23800 cerr0 << "finished." << endl;
23801 } else {
23802 extractPointIdsFromGrid(m_extractedCells, m_gridPoints, true, m_splitChildToSplitCell);
23803 MString fName = m_solutionOutput + fileName + "_B" + to_string(domainId());
23804 MString gName = m_solutionOutput + GFileName + "_B" + to_string(domainId());
23805 if(diverged) fName += "_diverged";
23806 if(diverged) gName += "_diverged";
23807 fName += ".vtu";
23808 gName += ".vtp";
23809 cerr << endl << "Saving '" << fName << "' at time " << setprecision(6) << m_physicalTime << "...";
23810 writeVtkXmlOutput(fName.c_str(), (diverged || !regularOutput));
23811 writeGeometryToVtkXmlFile(gName.c_str());
23812 cerr << " finished." << endl;
23813 }
23814 }
23815 else {
23816 extractPointIdsFromGrid(m_extractedCells, m_gridPoints, m_haloCellOutput, m_splitChildToSplitCell);
23817 deleteNeighbourLinks();
23818
23819 stringstream QName;
23820 QName << m_solutionOutput << "solver_data/" << fileName << "_B" << domainId();
23821 if(regularOutput) QName << "_00" << globalTimeStep;
23822 if(diverged) QName << "_diverged";
23823 QName << ".vtu";
23824
23825 DEBUG_LOG("Rank " << domainId() << " saving '" << QName.str() << "' at time " << setprecision(6) << m_physicalTime
23826 << "...");
23827 if(domainId() == 0)
23828 cerr << endl << "Saving '" << QName.str() << "' at time " << setprecision(6) << m_physicalTime << "...";
23829
23830 writeVtkXmlOutput((QName.str()).c_str(), (diverged || !regularOutput));
23831
23832 DEBUG_LOG(" finished (" << domainId() << ").");
23833 cerr0 << " finished." << endl;
23834
23835
23836 MInt noPolygons = 0;
23837 ScratchSpace<MInt> noPolys2(noDomains(), AT_, "noPolys2");
23838 MInt* noPolysGlobal = noPolys2.getPointer();
23839 IF_CONSTEXPR(nDim == 3 && m_vtuWriteGeometryFile) {
23840 stringstream GName;
23841 GName << m_solutionOutput << "solver_data/" << GFileName << "_B" << domainId();
23842 if(regularOutput) GName << "_00" << globalTimeStep;
23843 if(diverged) GName << "_diverged";
23844 GName << ".vtp";
23845
23846 DEBUG_LOG("Rank " << domainId() << " saving '" << GName.str() << "' at time " << setprecision(6) << m_physicalTime
23847 << "...");
23848
23849 noPolygons = writeGeometryToVtkXmlFile(GName.str());
23850
23851 DEBUG_LOG(" .. finished (" << domainId() << ").");
23852 }
23853 if(regularOutput) {
23854 ScratchSpace<MInt> noPolys(noDomains(), AT_, "noPolys");
23855 MInt* noPolysLocal = noPolys.getPointer();
23856 for(MInt c = 0; c < noDomains(); c++) {
23857 noPolysLocal[c] = 0;
23858 }
23859 noPolysLocal[domainId()] = noPolygons;
23860 MPI_Reduce(noPolysLocal, noPolysGlobal, noDomains(), MPI_INT, MPI_SUM, 0, mpiComm(), AT_, "noPolysLocal",
23861 "noPolysGlobal");
23862 } else {
23863 noPolysGlobal[0] = noPolygons;
23864 }
23865
23866
23867 ScratchSpace<MInt> noLsMbCells(noDomains(), AT_, "noLsMbCells");
23868 if(noDomains() > 1)
23869 MPI_Gather(&m_noLsMbBndryCells, 1, MPI_INT, &(noLsMbCells[0]), 1, MPI_INT, 0, mpiComm(), AT_,
23870 "m_noLsMbBndryCells", "(noLsMbCells[0])");
23871
23872
23873 if(domainId() == 0 && regularOutput) {
23874 //------ QOUT.pvd -------
23875
23876 if(true) {
23877 DEBUG_LOG("Writing QOUT.pvd file...");
23878
23879 MBool& firstCall = m_static_writeVtkXmlFiles_firstCall;
23880 if(firstCall) {
23881 if(fileExists("out/QOUT.pvd")) {
23882 rename("out/QOUT.pvd", "out/QOUT_BU.pvd");
23883 }
23884 if(fileExists("out/QOUT.pvd.tmp")) {
23885 remove("out/QOUT.pvd.tmp");
23886 }
23887 ofstream ofile("out/QOUT.pvd.tmp", ios_base::out | ios_base::trunc);
23888 if(ofile.is_open() && ofile.good()) {
23889 ofile << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
23890 ofile << "<Collection>" << endl;
23891 if(m_restart) {
23892 if(m_solutionTimeSteps.empty()) {
23893 for(MInt t = m_solutionOffset; t <= globalTimeStep; t += m_solutionInterval) {
23894 for(MInt p = 0; p < noDomains(); p++) {
23895 stringstream tmp;
23896 tmp << "out/solver_data/" << fileName << "_B" << p << "_00" << t << ".vtu";
23897 if(fileExists((tmp.str()).c_str())) {
23898 ofile << "<DataSet part=\"" << p << "\" timestep=\"" << t << "\" file=\""
23899 << "./solver_data/" << fileName << "_B" << p << "_00" << t << ".vtu\"/>" << endl;
23900 }
23901 }
23902 }
23903 } else {
23904 for(std::set<MInt>::iterator it = m_solutionTimeSteps.begin(); it != m_solutionTimeSteps.end(); it++) {
23905 MInt t = *it;
23906 for(MInt p = 0; p < noDomains(); p++) {
23907 stringstream tmp;
23908 tmp << "out/solver_data/" << fileName << "_B" << p << "_00" << t << ".vtu";
23909 if(fileExists((tmp.str()).c_str())) {
23910 ofile << "<DataSet part=\"" << p << "\" timestep=\"" << t << "\" file=\""
23911 << "./solver_data/" << fileName << "_B" << p << "_00" << t << ".vtu\"/>" << endl;
23912 }
23913 }
23914 }
23915 }
23916 }
23917 ofile.close();
23918 ofile.clear();
23919 } else {
23920 cerr << "Error opening file out/QOUT.pvd.tmp" << endl;
23921 }
23922 }
23923 if(firstCall) {
23924 ofstream ofile("out/QOUT_all.pvd", ios_base::out | ios_base::trunc);
23925 if(ofile.is_open() && ofile.good()) {
23926 ofile << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
23927 ofile << "<Collection>" << endl;
23928 if(m_solutionTimeSteps.empty()) {
23929 MInt t = m_solutionOffset;
23930 MBool found = true;
23931 while(found) {
23932 for(MInt p = 0; p < noDomains(); p++) {
23933 stringstream tmp;
23934 tmp << "out/solver_data/" << fileName << "_B" << p << "_00" << t << ".vtu";
23935 if(fileExists((tmp.str()).c_str())) {
23936 ofile << "<DataSet part=\"" << p << "\" timestep=\"" << t << "\" file=\""
23937 << "./solver_data/" << fileName << "_B" << p << "_00" << t << ".vtu\"/>" << endl;
23938 } else {
23939 found = false;
23940 }
23941 }
23942 t += m_solutionInterval;
23943 }
23944 } else {
23945 std::set<MInt>::iterator it = m_solutionTimeSteps.begin();
23946 MInt t = *it;
23947 MBool found = true;
23948 while(found) {
23949 for(MInt p = 0; p < noDomains(); p++) {
23950 stringstream tmp;
23951 tmp << "out/solver_data/" << fileName << "_B" << p << "_00" << t << ".vtu";
23952 if(fileExists((tmp.str()).c_str())) {
23953 ofile << "<DataSet part=\"" << p << "\" timestep=\"" << t << "\" file=\""
23954 << "./solver_data/" << fileName << "_B" << p << "_00" << t << ".vtu\"/>" << endl;
23955 } else {
23956 found = false;
23957 }
23958 }
23959 it++;
23960 }
23961 }
23962 ofile << "</Collection>" << endl;
23963 ofile << "</VTKFile>" << endl;
23964 ofile.close();
23965 ofile.clear();
23966 } else {
23967 cerr << "Error opening file out/QOUT_all.pvd" << endl;
23968 }
23969 }
23970 ofstream ofile("out/QOUT.pvd.tmp", ios_base::out | ios_base::app);
23971 if(ofile.is_open() && ofile.good()) {
23972 for(MInt p = 0; p < noDomains(); p++) {
23973 ofile << "<DataSet part=\"" << p << "\" timestep=\"" << globalTimeStep << "\" file=\""
23974 << "./solver_data/" << fileName << "_B" << p << "_00" << globalTimeStep << ".vtu\"/>" << endl;
23975 }
23976 ofile.close();
23977 ofile.clear();
23978 } else {
23979 cerr << "Error opening file out/QOUT.pvd.tmp" << endl;
23980 }
23981
23982 if(fileExists("out/QOUT.pvd")) {
23983 remove("out/QOUT.pvd");
23984 }
23985 copyFile("out/QOUT.pvd.tmp", "out/QOUT.pvd");
23986 ofstream ofile2("out/QOUT.pvd", ios_base::out | ios_base::app);
23987 if(ofile2.is_open() && ofile2.good()) {
23988 ofile2 << "</Collection>" << endl;
23989 ofile2 << "</VTKFile>" << endl;
23990 ofile2.close();
23991 } else {
23992 cerr << "Error opening file out/QOUT.pvd" << endl;
23993 }
23994 firstCall = false;
23995
23996 DEBUG_LOG("finished.");
23997 }
23998
23999
24000 //------ GEOM.pvd -------
24001
24002 IF_CONSTEXPR(nDim == 3 && m_vtuWriteGeometryFile) {
24003 DEBUG_LOG("Writing GEOM.pvd file...");
24004
24005 MBool& firstCall2 = m_static_writeVtkXmlFiles_firstCall2;
24006 if(firstCall2) {
24007 if(fileExists("out/GEOM.pvd")) {
24008 rename("out/GEOM.pvd", "out/GEOM_BU.pvd");
24009 }
24010 if(fileExists("out/GEOM.pvd.tmp")) {
24011 remove("out/GEOM.pvd.tmp");
24012 }
24013 ofstream ofile("out/GEOM.pvd.tmp", ios_base::out | ios_base::trunc);
24014 if(ofile.is_open() && ofile.good()) {
24015 ofile << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
24016 ofile << "<Collection>" << endl;
24017 if(m_restart) {
24018 if(m_solutionTimeSteps.empty()) {
24019 for(MInt t = m_solutionOffset; t <= globalTimeStep; t += m_solutionInterval) {
24020 MInt cnt = 0;
24021 for(MInt p = 0; p < noDomains(); p++) {
24022 stringstream fn;
24023 fn << "out/solver_data/" << GFileName << "_B" << p << "_00" << t;
24024 if(fileExists((fn.str()).c_str())) {
24025 ofile << "<DataSet part=\"" << cnt << "\" group=\"\" timestep=\"" << t << "\" file=\""
24026 << "./solver_data/" << GFileName << "_B" << p << "_00" << t << ".vtp\"/>" << endl;
24027 cnt++;
24028 }
24029 }
24030 }
24031 } else {
24032 for(std::set<MInt>::iterator it = m_solutionTimeSteps.begin(); it != m_solutionTimeSteps.end(); it++) {
24033 MInt t = *it;
24034 MInt cnt = 0;
24035 for(MInt p = 0; p < noDomains(); p++) {
24036 stringstream fn;
24037 fn << "out/solver_data/" << GFileName << "_B" << p << "_00" << t;
24038 if(fileExists((fn.str()).c_str())) {
24039 ofile << "<DataSet part=\"" << cnt << "\" group=\"\" timestep=\"" << t << "\" file=\""
24040 << "./solver_data/" << GFileName << "_B" << p << "_00" << t << ".vtp\"/>" << endl;
24041 cnt++;
24042 }
24043 }
24044 }
24045 }
24046 }
24047 ofile.close();
24048 ofile.clear();
24049 } else {
24050 cerr << "Error opening file out/GEOM.pvd.tmp" << endl;
24051 }
24052 }
24053 if(firstCall2) {
24054 ofstream ofile("out/GEOM_all.pvd", ios_base::out | ios_base::trunc);
24055 if(ofile.is_open() && ofile.good()) {
24056 ofile << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
24057 ofile << "<Collection>" << endl;
24058 if(m_solutionTimeSteps.empty()) {
24059 MInt t = m_solutionOffset;
24060 MBool found = true;
24061 while(found) {
24062 MInt cnt = 0;
24063 for(MInt p = 0; p < noDomains(); p++) {
24064 stringstream fn;
24065 fn << "out/solver_data/" << GFileName << "_B" << p << "_00" << t << ".vtp";
24066 if(fileExists((fn.str()).c_str())) {
24067 ofile << "<DataSet part=\"" << cnt << "\" group=\"\" timestep=\"" << t << "\" file=\""
24068 << "./solver_data/" << GFileName << "_B" << p << "_00" << t << ".vtp\"/>" << endl;
24069 cnt++;
24070 }
24071 }
24072 if(cnt == 0) {
24073 found = false;
24074 }
24075 t += m_solutionInterval;
24076 }
24077 } else {
24078 std::set<MInt>::iterator it = m_solutionTimeSteps.begin();
24079 MInt t = *it;
24080 MBool found = true;
24081 while(found) {
24082 MInt cnt = 0;
24083 for(MInt p = 0; p < noDomains(); p++) {
24084 stringstream fn;
24085 fn << "out/solver_data/" << GFileName << "_B" << p << "_00" << t << ".vtp";
24086 if(fileExists((fn.str()).c_str())) {
24087 ofile << "<DataSet part=\"" << cnt << "\" group=\"\" timestep=\"" << t << "\" file=\""
24088 << "./solver_data/" << GFileName << "_B" << p << "_00" << t << ".vtp\"/>" << endl;
24089 cnt++;
24090 }
24091 }
24092 if(cnt == 0) {
24093 found = false;
24094 }
24095 it++;
24096 }
24097 }
24098 ofile << "</Collection>" << endl;
24099 ofile << "</VTKFile>" << endl;
24100 ofile.close();
24101 ofile.clear();
24102 } else {
24103 cerr << "Error opening file out/GEOM_all.pvd" << endl;
24104 }
24105 }
24106 ofstream ofile("out/GEOM.pvd.tmp", ios_base::out | ios_base::app);
24107 if(ofile.is_open() && ofile.good()) {
24108 MInt cnt = 0;
24109 for(MInt p = 0; p < noDomains(); p++) {
24110 if(noPolysGlobal[p] > 0) {
24111 ofile << "<DataSet part=\"" << cnt << "\" group=\"\" timestep=\"" << globalTimeStep << "\" file=\""
24112 << "./solver_data/" << GFileName << "_B" << p << "_00" << globalTimeStep << ".vtp\"/>" << endl;
24113 cnt++;
24114 }
24115 }
24116 ofile.close();
24117 ofile.clear();
24118 } else {
24119 cerr << "Error opening file out/GEOM.pvd.tmp" << endl;
24120 }
24121
24122 if(fileExists("out/GEOM.pvd")) {
24123 remove("out/GEOM.pvd");
24124 }
24125 copyFile("out/GEOM.pvd.tmp", "out/GEOM.pvd");
24126 ofstream ofile2("out/GEOM.pvd", ios_base::out | ios_base::app);
24127 if(ofile2.is_open() && ofile2.good()) {
24128 ofile2 << "</Collection>" << endl;
24129 ofile2 << "</VTKFile>" << endl;
24130 ofile2.close();
24131 } else {
24132 cerr << "Error opening file out/GEOM.pvd" << endl;
24133 }
24134 firstCall2 = false;
24135
24136 DEBUG_LOG("finished.");
24137 }
24138 }
24139
24140
24141 if(domainId() == 0 && diverged) {
24142 // QOUT_diverged.pvd
24143 if(fileExists("out/QOUT_diverged.pvd")) {
24144 remove("out/QOUT_diverged.pvd");
24145 }
24146 ofstream ofile("out/QOUT_diverged.pvd", ios_base::out | ios_base::trunc);
24147 if(ofile.is_open() && ofile.good()) {
24148 ofile << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
24149 ofile << "<Collection>" << endl;
24150 for(MInt p = 0; p < noDomains(); p++) {
24151 stringstream tmp;
24152 tmp << "out/solver_data/" << fileName << "_B" << p << "_diverged.vtu";
24153 if(fileExists((tmp.str()).c_str())) {
24154 ofile << "<DataSet part=\"" << p << "\" timestep=\"" << globalTimeStep << "\" file=\""
24155 << "./solver_data/" << fileName << "_B" << p << "_diverged.vtu\"/>" << endl;
24156 }
24157 }
24158 ofile << "</Collection>" << endl;
24159 ofile << "</VTKFile>" << endl;
24160 ofile.close();
24161 ofile.clear();
24162 } else {
24163 cerr << "Error opening file out/QOUT_diverged.pvd" << endl;
24164 }
24165
24166
24167 // GEOM_diverged.pvd
24168 if(fileExists("out/GEOM_diverged.pvd")) {
24169 remove("out/GEOM_diverged.pvd");
24170 }
24171 ofstream ofile2("out/GEOM_diverged.pvd", ios_base::out | ios_base::trunc);
24172 if(ofile2.is_open() && ofile2.good()) {
24173 ofile2 << "<VTKFile type=\"Collection\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
24174 ofile2 << "<Collection>" << endl;
24175 for(MInt p = 0; p < noDomains(); p++) {
24176 if(noLsMbCells(p) > 0) {
24177 ofile2 << "<DataSet part=\"" << p << "\" timestep=\"" << globalTimeStep << "\" file=\""
24178 << "./solver_data/" << GFileName << "_B" << p << "_diverged.vtp\"/>" << endl;
24179 }
24180 }
24181 ofile2 << "</Collection>" << endl;
24182 ofile2 << "</VTKFile>" << endl;
24183 ofile2.close();
24184 ofile2.clear();
24185 } else {
24186 cerr << "Error opening file out/GEOM_diverged.pvd" << endl;
24187 }
24188 }
24189 }
24190
24191 if(correctCoords) m_fvBndryCnd->rerecorrectCellCoordinates();
24192
24193
24194 if(m_extractedCells) {
24195 delete m_extractedCells;
24196 m_extractedCells = nullptr;
24197 }
24198 if(m_gridPoints) {
24199 delete m_gridPoints;
24200 m_gridPoints = nullptr;
24201 }
24202
24203 if(diverged) {
24204 const MInt noBytes = maxNoGridCells() * m_noCVars * sizeof(MFloat);
24205 MFloat* RESTRICT cVars = (MFloat*)(&(a_variable(0, 0)));
24206 MFloat* RESTRICT oCVars = (MFloat*)(&(a_oldVariable(0, 0)));
24207 memcpy(cVars, oCVars, noBytes);
24208 computePrimitiveVariables();
24209 cerr0 << "deactivate m_useNonSpecifiedRestartFile" << endl;
24210 m_useNonSpecifiedRestartFile = false;
24211 if((globalTimeStep % m_restartInterval) != 0 && globalTimeStep != m_restartTimeStep) {
24212 saveRestartFile(false);
24213 }
24214 }
24215
24216
24217 // point particle output
24218 if(m_noPointParticles > 0 && m_noPointParticles < 1000000) {
24219 MFloatScratchSpace partCoord(m_noPointParticles, nDim, AT_, "partCoord");
24220 MFloatScratchSpace partVel(m_noPointParticles, nDim, AT_, "partVel");
24221 MFloatScratchSpace partVelFluid(m_noPointParticles, nDim, AT_, "partVelFluid");
24222 MFloatScratchSpace partRadii(m_noPointParticles, nDim, AT_, "partVevRadii");
24223 MIntScratchSpace noPartData(noDomains(), AT_, "noPartData");
24224 MIntScratchSpace partDataOffsets(noDomains(), AT_, "partDataOffsets");
24225 noPartData(domainId()) = nDim * m_noPointParticlesLocal;
24226 MPI_Allreduce(MPI_IN_PLACE, &noPartData[0], noDomains(), MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
24227 "noPartData[0]");
24228 partDataOffsets[0] = 0;
24229 for(MInt i = 1; i < noDomains(); i++)
24230 partDataOffsets[i] = partDataOffsets[i - 1] + noPartData[i - 1];
24231 MPI_Gatherv(&m_particleCoords[0], noPartData(domainId()), MPI_DOUBLE, &partCoord[0], &noPartData[0],
24232 &partDataOffsets[0], MPI_DOUBLE, 0, mpiComm(), AT_, "m_particleCoords[0]", "partCoord[0]");
24233 MPI_Gatherv(&m_particleVelocity[0], noPartData(domainId()), MPI_DOUBLE, &partVel[0], &noPartData[0],
24234 &partDataOffsets[0], MPI_DOUBLE, 0, mpiComm(), AT_, "m_particleVelocity[0]", "partVel[0]");
24235 MPI_Gatherv(&m_particleVelocityFluid[0], noPartData(domainId()), MPI_DOUBLE, &partVelFluid[0], &noPartData[0],
24236 &partDataOffsets[0], MPI_DOUBLE, 0, mpiComm(), AT_, "m_particleVelocityFluid[0]", "partVelFluid[0]");
24237 MPI_Gatherv(&m_particleRadii[0], noPartData(domainId()), MPI_DOUBLE, &partRadii[0], &noPartData[0],
24238 &partDataOffsets[0], MPI_DOUBLE, 0, mpiComm(), AT_, "m_particleRadii[0]", "partRadii[0]");
24239
24240 if(domainId() == 0) {
24241 typedef uint32_t uint_t;
24242 const char* const uIDataType = (std::is_same<uint_t, uint64_t>::value) ? "UInt64" : "UInt32";
24243 const char* const dataType = "Float32";
24244 ofstream ofl;
24245 const MString partFileName = m_solutionOutput + "PPOUT_00" + to_string(globalTimeStep) + ".vtp";
24246 ofl.open(partFileName.c_str(), ios_base::out | ios_base::trunc);
24247 if(ofl.is_open() && ofl.good()) {
24248 // VTKFile
24249 ofl << "<?xml version=\"1.0\"?>" << endl;
24250 ofl << "<VTKFile type=\"PolyData\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">" << endl;
24251 ofl << "<PolyData>" << endl;
24252
24253 // FieldData
24254 ofl << "<FieldData>" << endl;
24255 ofl << "<DataArray type=\"" << uIDataType
24256 << "\" Name=\"globalTimeStep\" format=\"ascii\" NumberOfTuples=\"1\" > " << globalTimeStep
24257 << " </DataArray>" << endl;
24258 ofl << "<DataArray type=\"" << dataType << "\" Name=\"time\" format=\"ascii\" NumberOfTuples=\"1\" > " << m_time
24259 << " </DataArray>" << endl;
24260 ofl << "<DataArray type=\"" << dataType << "\" Name=\"physicalTime\" format=\"ascii\" NumberOfTuples=\"1\" > "
24261 << m_physicalTime << " </DataArray>" << endl;
24262 ofl << "</FieldData>" << endl;
24263
24264 // Dimensions
24265 ofl << "<Piece NumberOfPoints=\"" << m_noPointParticles << "\" NumberOfVerts=\"" << m_noPointParticles << "\">"
24266 << endl;
24267
24268 // Points
24269 ofl << "<Points>" << endl;
24270 ofl << setprecision(12);
24271 ofl << "<DataArray type=\"" << dataType << "\" NumberOfComponents=\"3\" format=\"ascii\">" << endl;
24272 for(MInt k = 0; k < m_noPointParticles; k++) {
24273 for(MInt i = 0; i < nDim; i++) {
24274 ofl << partCoord(k, i) << " ";
24275 }
24276 ofl << endl;
24277 }
24278 ofl << "</DataArray>" << endl;
24279 ofl << "</Points>" << endl;
24280
24281 // Verts
24282 ofl << "<Verts>" << endl;
24283 ofl << "<DataArray type=\"" << uIDataType << "\" Name=\"connectivity\" format=\"ascii\">" << endl;
24284 for(MInt k = 0; k < m_noPointParticles; k++) {
24285 ofl << k << " ";
24286 }
24287 ofl << endl;
24288 ofl << "</DataArray>" << endl;
24289 ofl << "<DataArray type=\"" << uIDataType << "\" Name=\"offsets\" format=\"ascii\">" << endl;
24290 for(MInt k = 0; k < m_noPointParticles; k++) {
24291 ofl << k + 1 << " ";
24292 }
24293 ofl << endl;
24294 ofl << "</DataArray>" << endl;
24295 ofl << "</Verts>" << endl;
24296
24297 // PointData
24298 ofl << "<PointData Scalars=\"scalars\">" << endl;
24299 ofl << "<DataArray type=\"" << dataType << "\" Name=\"velocity\" NumberOfComponents=\"3\" format=\"ascii\">"
24300 << endl;
24301 for(MInt k = 0; k < m_noPointParticles; k++) {
24302 for(MInt i = 0; i < nDim; i++) {
24303 ofl << partVel(k, i) << " ";
24304 }
24305 ofl << endl;
24306 }
24307 ofl << "</DataArray>" << endl;
24308 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Re_p\" NumberOfComponents=\"1\" format=\"ascii\">"
24309 << endl;
24310 for(MInt k = 0; k < m_noPointParticles; k++) {
24311 MFloat diameter = F2 * pow(partRadii[3 * k] * partRadii[3 * k + 1] * partRadii[3 * k + 2], F1B3);
24312 MFloat Rep = F0;
24313 for(MInt i = 0; i < nDim; i++) {
24314 Rep += POW2(partVelFluid(k, i) - partVel(k, i));
24315 }
24316 Rep = sqrt(Rep) * diameter * m_rhoInfinity * sysEqn().m_Re0 / sysEqn().m_muInfinity;
24317 ofl << Rep << " ";
24318 }
24319 ofl << endl;
24320 ofl << "</DataArray>" << endl;
24321 ofl << "</PointData>" << endl;
24322
24323 ofl << "</Piece>" << endl;
24324 ofl << "</PolyData>" << endl;
24325 ofl << "</VTKFile>" << endl;
24326 ofl.close();
24327 ofl.clear();
24328 } else {
24329 cerr << "ERROR! COULD NOT OPEN FILE " << partFileName << " for writing! (1)" << endl;
24330 }
24331 }
24332 }
24333}
24334
24335
24340template <MInt nDim, class SysEqn>
24342 TRACE();
24343
24344 string line;
24345 ifstream ifile;
24346 MBool isBinary = false;
24347 MFloat a[3];
24348 MFloat b[3];
24349 MFloat c[3];
24350 MInt noPoints;
24351 char cstr[100];
24352 string token;
24353 m_noSurfacePointSamples = 0;
24354 noPoints = 0;
24355
24356 if(!fileExists(fileName)) {
24357 stringstream errorMessage;
24358 errorMessage << "Error: Unable to find file " << fileName << ". Quit." << endl;
24359 mTerm(1, AT_, errorMessage.str());
24360 } else if(isBinary) {
24361 cerr << "lacking binary stl code" << endl;
24362 } else {
24363 ifile.open(fileName);
24364 if(ifile.is_open()) {
24365 cerr << "Reading " << fileName << "... ";
24366
24367 getline(ifile, line);
24368 strcpy(cstr, line.c_str());
24369 token = strtok(cstr, " ");
24370 if(token.compare(0, 5, "solid", 0, 5) != 0) {
24371 stringstream errorMessage;
24372 errorMessage << "Error 1 reading " << fileName << ". Quit." << endl;
24373 mTerm(1, AT_, errorMessage.str());
24374 }
24375 while(ifile.good()) {
24376 getline(ifile, line);
24377 if(line == "") continue;
24378 strcpy(cstr, line.c_str());
24379 token = strtok(cstr, " ");
24380 if(token.compare(0, 5, "facet", 0, 5) == 0) {
24381 if(noPoints >= m_maxNoSurfacePointSamples) {
24382 mTerm(1, AT_, "Increase m_maxNoSurfacePointSamples. Quit.");
24383 }
24384
24385 // 1. obtain normals
24386 token = strtok(nullptr, " ");
24387 if(token.compare(0, 5, "normal", 0, 5) != 0) {
24388 stringstream errorMessage;
24389 errorMessage << "Error 2 reading " << fileName << ". Quit." << endl;
24390 mTerm(1, AT_, errorMessage.str());
24391 }
24392 if(readNormals) {
24393 token = strtok(nullptr, " ");
24394 m_sampleNormals[3 * noPoints] = atof(token.c_str());
24395 token = strtok(nullptr, " ");
24396 m_sampleNormals[3 * noPoints + 1] = atof(token.c_str());
24397 token = strtok(nullptr, " ");
24398 m_sampleNormals[3 * noPoints + 2] = atof(token.c_str());
24399 }
24400
24401 // skip "outer loop"
24402 getline(ifile, line);
24403
24404 // 2a. obtain point a
24405 getline(ifile, line);
24406 strcpy(cstr, line.c_str());
24407 token = strtok(cstr, " ");
24408 if(token.compare(0, 6, "vertex", 0, 6) != 0) {
24409 stringstream errorMessage;
24410 errorMessage << "Error 3 reading " << fileName << ". Quit." << endl;
24411 mTerm(1, AT_, errorMessage.str());
24412 }
24413 token = strtok(nullptr, " ");
24414 a[0] = atof(token.c_str());
24415 token = strtok(nullptr, " ");
24416 a[1] = atof(token.c_str());
24417 token = strtok(nullptr, " ");
24418 a[2] = atof(token.c_str());
24419
24420 // 2b. obtain point b
24421 getline(ifile, line);
24422 strcpy(cstr, line.c_str());
24423 token = strtok(cstr, " ");
24424 if(token.compare(0, 6, "vertex", 0, 6) != 0) {
24425 stringstream errorMessage;
24426 errorMessage << "Error 4 reading " << fileName << ". Quit." << endl;
24427 mTerm(1, AT_, errorMessage.str());
24428 }
24429 token = strtok(nullptr, " ");
24430 b[0] = atof(token.c_str());
24431 token = strtok(nullptr, " ");
24432 b[1] = atof(token.c_str());
24433 token = strtok(nullptr, " ");
24434 b[2] = atof(token.c_str());
24435
24436 // 2c. obtain point c
24437 getline(ifile, line);
24438 strcpy(cstr, line.c_str());
24439 token = strtok(cstr, " ");
24440 if(token.compare(0, 6, "vertex", 0, 6) != 0) {
24441 stringstream errorMessage;
24442 errorMessage << "Error 5 reading " << fileName << ". Quit." << endl;
24443 mTerm(1, AT_, errorMessage.str());
24444 }
24445 token = strtok(nullptr, " ");
24446 c[0] = atof(token.c_str());
24447 token = strtok(nullptr, " ");
24448 c[1] = atof(token.c_str());
24449 token = strtok(nullptr, " ");
24450 c[2] = atof(token.c_str());
24451
24452 m_sampleCoordinates[3 * noPoints] = F1B3 * (a[0] + b[0] + c[0]);
24453 m_sampleCoordinates[3 * noPoints + 1] = F1B3 * (a[1] + b[1] + c[1]);
24454 m_sampleCoordinates[3 * noPoints + 2] = F1B3 * (a[2] + b[2] + c[2]);
24455
24456 if(!readNormals) {
24457 for(MInt i = 0; i < 3; i++) {
24458 b[i] = b[i] - a[i];
24459 a[i] = c[i] - a[i];
24460 }
24461 crossProduct(c, b, a);
24462 MFloat tmp = F1 / sqrt(POW2(c[0]) + POW2(c[1]) + POW2(c[2]));
24463
24464 m_sampleNormals[3 * noPoints] = c[0] * tmp;
24465 m_sampleNormals[3 * noPoints + 1] = c[1] * tmp;
24466 m_sampleNormals[3 * noPoints + 2] = c[2] * tmp;
24467 }
24468
24469 // skip "endloop"
24470 getline(ifile, line);
24471
24472 // skip "endfacet"
24473 getline(ifile, line);
24474
24475 noPoints++;
24476 } else if(token.compare(0, 8, "endsolid", 0, 8) == 0) {
24477 cerr << "finished ";
24478 break;
24479 } else {
24480 stringstream errorMessage;
24481 errorMessage << "Error 6 reading " << fileName << ". Quit." << endl;
24482 mTerm(1, AT_, errorMessage.str());
24483 }
24484 }
24485
24486 ifile.close();
24487 }
24488 }
24489 m_noSurfacePointSamples = noPoints;
24490
24491 cerr << "(read " << m_noSurfacePointSamples << " samples)." << endl;
24492 cerr << "establishing sample neighborhood...";
24493
24494 const MInt noNghbrs = m_maxNoSampleNghbrs;
24495 MFloat dist[10];
24496 MInt nghbrs[10];
24497 ASSERT(noNghbrs <= 10, "");
24498 MInt offset = 0;
24499 for(MInt p = 0; p < noPoints; p++) {
24500 for(MInt i = 0; i < noNghbrs; i++) {
24501 dist[i] = POW2(c_cellLengthAtLevel(0));
24502 nghbrs[i] = -1;
24503 }
24504 for(MInt q = 0; q < noPoints; q++) {
24505 if(p == q) continue;
24506 MFloat tmpDist = POW2(m_sampleCoordinates[3 * p] - m_sampleCoordinates[3 * q])
24507 + POW2(m_sampleCoordinates[3 * p + 1] - m_sampleCoordinates[3 * q + 1])
24508 + POW2(m_sampleCoordinates[3 * p + 2] - m_sampleCoordinates[3 * q + 2]);
24509 for(MInt i = 0; i < noNghbrs; i++) {
24510 if(tmpDist < dist[i]) {
24511 for(MInt j = noNghbrs - 1; j > i; j--) {
24512 if(nghbrs[j - 1] > -1) {
24513 nghbrs[j] = nghbrs[j - 1];
24514 dist[j] = dist[j - 1];
24515 }
24516 }
24517 dist[i] = tmpDist;
24518 nghbrs[i] = q;
24519 break;
24520 }
24521 }
24522 }
24523 for(MInt i = 0; i < noNghbrs; i++) {
24524 m_sampleNghbrs[offset + i] = nghbrs[i];
24525 }
24526 offset += noNghbrs;
24527 m_sampleNghbrOffsets[p] = offset;
24528 }
24529
24530 cerr << "finished." << endl;
24531}
24532
24533
24539template <MInt nDim, class SysEqn>
24541 TRACE();
24542
24543 writeGridRestart = false;
24544
24545 if(((globalTimeStep % m_restartInterval) == 0 && globalTimeStep > m_restartTimeStep) || writeRestart) {
24546 writeRestart = true;
24547
24548 if(isActive() && m_deleteNeighbour) {
24549 restoreNeighbourLinks();
24550 }
24551
24552 if(m_onlineRestartInterval > 0) {
24553 if(globalTimeStep == 0 && m_onlineRestartInterval < g_timeSteps) m_adaptationSinceLastRestart = true;
24554 if(globalTimeStep == 1 && m_onlineRestartInterval < g_timeSteps) m_adaptationSinceLastRestart = true;
24555 if(globalTimeStep % m_onlineRestartInterval == 0) m_adaptationSinceLastRestart = true;
24556 }
24557
24558 if(m_forceRestartGrid) {
24559 m_adaptationSinceLastRestart = true;
24560 if(isActive() && m_recalcIds == nullptr) mAlloc(m_recalcIds, maxNoGridCells(), "m_recalcIds", -1, AT_);
24561 }
24562
24563 if(m_adaptationSinceLastRestartBackup || m_adaptationSinceLastRestart) {
24564 writeGridRestart = true;
24565 }
24566 }
24567
24568 if(grid().newMinLevel() > 0) {
24569 writeGridRestart = true;
24570 }
24571
24572 // This needs to happen before the grid and variable-output. Thats why it had to be moved here
24573 // from saveRestartFile()!
24574 if(isActive() && m_useNonSpecifiedRestartFile && writeRestart) {
24575 if(domainId() == 0) {
24576 if(m_adaptationSinceLastRestart) {
24577 MString fileName = outputDir() + "restartGrid";
24578 fileName += ".Netcdf";
24579 MString fileNameBak = fileName + ".BAK";
24580#ifdef _MB_DEBUG_
24581 cerr << "rename " << fileName << " " << fileNameBak << endl;
24582#endif
24583 rename(fileName.c_str(), fileNameBak.c_str());
24584 }
24585 {
24586 MString fileName = outputDir() + "restartVariables";
24587 fileName += ".Netcdf";
24588 MString fileNameBak = fileName + ".BAK";
24589#ifdef _MB_DEBUG_
24590 cerr << "rename " << fileName << " " << fileNameBak << endl;
24591#endif
24592 rename(fileName.c_str(), fileNameBak.c_str());
24593 }
24594 {
24595 MString fileName = outputDir() + "restartBodyData";
24596 fileName += ".Netcdf";
24597 MString fileNameBak = fileName + ".BAK";
24598#ifdef _MB_DEBUG_
24599 cerr << "rename " << fileName << " " << fileNameBak << endl;
24600#endif
24601 rename(fileName.c_str(), fileNameBak.c_str());
24602 }
24603 }
24604 MPI_Barrier(mpiComm(), AT_);
24605 }
24606
24607 if(isActive() && m_levelSetMb && writeRestart) {
24608 if(maxLevel() > minLevel()) {
24609 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
24610 if(a_isBndryGhostCell(cellId)) continue;
24611 if(a_isHalo(cellId)) continue;
24612 if(a_level(cellId) != minLevel()) continue;
24613 reduceData(cellId, &a_pvariable(0, 0), PV->noVariables);
24614 if(grid().azimuthalPeriodicity()) {
24615 // Should this be done also for non-periodic cases?
24616 // Else, after restart CV are computed based on PV variables
24617 // In the running simulation PV, however, are simply overwritten to old value in computePV()
24618 reduceData(cellId, &a_variable(0, 0), CV->noVariables);
24619 }
24620 }
24621 }
24622 }
24623
24624#if defined _MB_DEBUG_ || !defined NDEBUG
24625 if(isActive() && writeRestart) {
24626 if(domainId() == 0) {
24627 cerr << "Checking cells before writing restart-file... ";
24628 }
24629 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
24630 for(MInt v = 0; v < CV->noVariables; v++) {
24631 if(std::isnan(a_variable(cellId, v)) && a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
24632 cerr << "Nan in variable when writing restart-File: " << cellId << " "
24633 << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
24634 }
24635 }
24636 }
24637 cerr0 << "finished. " << endl;
24638 }
24639#endif
24640
24641 return writeRestart;
24642}
24643
24644
24650template <MInt nDim, class SysEqn>
24652 TRACE();
24653
24654 if(doneRestart) {
24655 m_adaptationSinceLastRestart = false;
24656 m_adaptationSinceLastRestartBackup = false;
24657 if(isActive()) {
24658 deleteNeighbourLinks();
24659 }
24660 }
24661}
24662
24663
24669template <MInt nDim, class SysEqn>
24671 TRACE();
24672
24673 const MInt noCellsGrid = grid().raw().treeb().size();
24674 const MInt offset = noCellsGrid * solverId();
24675
24676 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
24677 if(a_isBndryGhostCell(cellId)) continue;
24678 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
24679 if(a_hasProperty(cellId, SolverCell::IsSplitClone)) continue;
24680 assertValidGridCellId(cellId);
24681 const MInt gridCellId = grid().tree().solver2grid(cellId);
24682 const MInt id = gridCellId + offset;
24683 if(a_isHalo(cellId)) continue;
24684 if(c_noChildren(cellId) > 0) {
24685 solverCellWeight[id] = m_weightBaseCell * m_weightMulitSolverFactor;
24686 continue;
24687 }
24688 if(a_hasProperty(cellId, SolverCell::IsInactive)) {
24689 solverCellWeight[id] = m_weightLeafCell * m_weightMulitSolverFactor;
24690 } else {
24691 solverCellWeight[id] = m_weightActiveCell * m_weightMulitSolverFactor;
24692 }
24693
24694 MFloat dist = fabs(a_levelSetValuesMb(cellId, 0));
24695 if(dist < 2 * grid().cellLengthAtLevel(maxRefinementLevel())) {
24696 solverCellWeight[id] += m_weightNearBndryCell * m_weightMulitSolverFactor;
24697 }
24698 if(a_bndryId(cellId) > -1 && c_isLeafCell(cellId)) {
24699 solverCellWeight[id] += m_weightBndryCell * m_weightMulitSolverFactor;
24700 }
24701 }
24702}
24703
24704
24710template <MInt nDim, class SysEqn>
24712 TRACE();
24713
24715
24716 if(m_noEmbeddedBodies > 0) {
24717 saveBodyRestartFile(writeBackup);
24718 }
24719}
24720
24721
24728template <MInt nDim, class SysEqn>
24730 TRACE();
24731
24733 m_physicalTimeDt1 = m_physicalTime;
24734
24735 updateInfinityVariables();
24736
24737 m_log << "ok" << endl;
24738 m_log << "computing conservative variables... ";
24739 computeConservativeVariables();
24740 m_log << "ok" << endl;
24741 m_log << "restart at time step: " << globalTimeStep << " - solution time: " << m_time << endl;
24742 m_log << m_noSamples << " samples read" << endl;
24743 cerr0 << "finished restart at time step " << globalTimeStep << endl;
24744}
24745
24746
24752template <MInt nDim, class SysEqn>
24754 TRACE();
24755
24756 if(globalTimeStep <= 0 || (m_restart && globalTimeStep <= m_restartTimeStep)) {
24757 cerr0 << "Not saving body-restart-data, as the cell volume might not have been created yet!" << endl;
24758 return;
24759 }
24760
24761 // force calculation before writing the restartFile!
24762 if(!m_trackBodySurfaceData) computeBodySurfaceData();
24763
24764 cerr0 << "writing body-restart-data for the fv-mb-solver... ";
24765
24766 int64_t noMbCells = 0;
24767 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
24768 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
24769 if(a_isHalo(cellId)) continue;
24770 if(a_isPeriodic(cellId)) continue;
24771 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
24772 noMbCells++;
24773 }
24774
24775 int64_t noMbCellsGlobal = noMbCells;
24776 ScratchSpace<MPI_Offset> volOffsets(noDomains() + 1, AT_, "volOffsets");
24777 volOffsets(0) = 0;
24778
24779 if(noDomains() > 1) {
24780 volOffsets(domainId() + 1) = (MPI_Offset)noMbCells;
24781 MPI_Allgather(&noMbCells, 1, MPI_INT64_T, &volOffsets[1], 1, MPI_INT64_T, mpiComm(), AT_, "noMbCells",
24782 "volOffsets[1]");
24783 for(MInt d = 0; d < noDomains(); d++) {
24784 volOffsets(d + 1) += volOffsets(d);
24785 }
24786 noMbCellsGlobal = noMbCells;
24787 MPI_Allreduce(MPI_IN_PLACE, &noMbCellsGlobal, 1, MPI_INT64_T, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
24788 "noMbCellsGlobal");
24789 if(noMbCellsGlobal != volOffsets(noDomains())) mTerm(1, AT_, "Dimension mismatch.");
24790 }
24791 volOffsets(noDomains()) = (MPI_Offset)noMbCellsGlobal;
24792
24793 // Azimuthal periodicity. Boundary cell volume of halo cells musst be saved!
24794 int64_t noAzimuthalMbCells = 0;
24795 int64_t noAzimuthalMbCellsGlobal = 0;
24796 ScratchSpace<MPI_Offset> volOffsetsAzimuthal(grid().azimuthalPeriodicity() ? (noDomains() + 1) : 1, AT_,
24797 "volOffsetsAzimuthal");
24798 if(grid().azimuthalPeriodicity()) {
24799 storeAzimuthalPeriodicData();
24800 noAzimuthalMbCells = m_azimuthalNearBoundaryBackup.size();
24801 noAzimuthalMbCellsGlobal = noAzimuthalMbCells;
24802 volOffsetsAzimuthal(0) = 0;
24803 if(noDomains() > 1) {
24804 volOffsetsAzimuthal(domainId() + 1) = (MPI_Offset)noAzimuthalMbCells;
24805 MPI_Allgather(&noAzimuthalMbCells, 1, MPI_INT64_T, &volOffsetsAzimuthal[1], 1, MPI_INT64_T, mpiComm(), AT_,
24806 "noAzimuthalMbCells", "volOffsetsAzimuthal[1]");
24807 for(MInt d = 0; d < noDomains(); d++) {
24808 volOffsetsAzimuthal(d + 1) += volOffsetsAzimuthal(d);
24809 }
24810 noAzimuthalMbCellsGlobal = noAzimuthalMbCells;
24811 MPI_Allreduce(MPI_IN_PLACE, &noAzimuthalMbCellsGlobal, 1, MPI_INT64_T, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
24812 "noAzimuthalMbCellsGlobal");
24813 if(noAzimuthalMbCellsGlobal != volOffsetsAzimuthal(noDomains())) mTerm(1, AT_, "Dimension mismatch.");
24814 }
24815 volOffsetsAzimuthal(noDomains()) = (MPI_Offset)noAzimuthalMbCellsGlobal;
24816 }
24817
24818 const MLong DOF = m_noEmbeddedBodies;
24819 const MLong DOF_TRANS = nDim * m_noEmbeddedBodies;
24820 const MLong DOF_ROT = 3 * m_noEmbeddedBodies;
24821 const MLong DOF_QUAT = 4 * m_noEmbeddedBodies;
24822 const MLong DOF_VOL = (MLong)noMbCellsGlobal;
24823 const MLong DOF_VOL_AZIMUTHAL = (MLong)noAzimuthalMbCellsGlobal;
24824
24825 stringstream fn;
24826 fn.clear();
24827 if(backup) {
24828 fn << outputDir() << "restartBodyDataBackup_" << getIdentifier(m_multipleFvSolver) << globalTimeStep;
24829 } else {
24830 if(m_useNonSpecifiedRestartFile) {
24831 fn << outputDir() << "restartBodyData" << getIdentifier(m_multipleFvSolver, "_", "");
24832 } else {
24833 fn << outputDir() << "restartBodyData_" << getIdentifier(m_multipleFvSolver) << globalTimeStep;
24834 }
24835 }
24836 fn << ParallelIo::fileExt();
24837
24838 MString fileName = fn.str();
24839
24840 MLongScratchSpace bndryCellVolumesIds(noMbCells, AT_, "bndryCellVolumesIds");
24841 MFloatScratchSpace bndryCellVolumes(noMbCells, AT_, "bndryCellVolumes");
24842 MInt cnt = 0;
24843 if(grid().newMinLevel() < 0) {
24844 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
24845 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
24846 if(a_isHalo(cellId)) continue;
24847 if(a_isPeriodic(cellId)) continue;
24848 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
24849 ASSERT(c_globalId(cellId) >= domainOffset(domainId())
24850 && c_globalId(cellId) < domainOffset(domainId()) + noInternalCells(),
24851 "");
24852 bndryCellVolumesIds[cnt] = c_globalId(cellId);
24853 bndryCellVolumes[cnt] = a_cellVolume(cellId);
24854 if(bndryCellVolumesIds[cnt] >= domainOffset(noDomains())) {
24855 cerr << domainId() << ": index out of range " << bndryCellVolumes[cnt] << " " << domainOffset(noDomains())
24856 << " " << grid().noCellsGlobal() << " " << grid().bitOffset() << endl;
24857 }
24858 cnt++;
24859 }
24860 } else {
24861 vector<MInt> reOrderedCells;
24862 vector<MLong> newGlobalIds;
24863 cerr0 << "Updating globalIds for bodyRestartFile!" << endl;
24864 this->reOrderCellIds(reOrderedCells);
24865 // recompute the globalIds
24866 this->recomputeGlobalIds(reOrderedCells, newGlobalIds);
24867
24868 // store bndryCellVolume and new globalId
24869 for(MUint id = 0; id < reOrderedCells.size(); id++) {
24870 const MInt cellId = reOrderedCells[id];
24871 if(a_isHalo(cellId)) continue;
24872 if(a_isPeriodic(cellId)) continue;
24873 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
24874 const MInt bndryId = a_bndryId(cellId);
24875 if(bndryId < m_noOuterBndryCells) continue;
24876 bndryCellVolumesIds[cnt] = newGlobalIds[id];
24877 bndryCellVolumes[cnt] = a_cellVolume(cellId);
24878 cnt++;
24879 }
24880 ASSERT(cnt == noMbCells, "");
24881 }
24882
24883 MLongScratchSpace azimuthalBndryCellVolumesIds(mMax(noAzimuthalMbCells, (int64_t)1), AT_,
24884 "azimuthalndryCellVolumesIds");
24885 MFloatScratchSpace azimuthalBndryCellVolumes(mMax(noAzimuthalMbCells, (int64_t)1), AT_, "azimuthalndryCellVolumes");
24886 MFloatScratchSpace azimuthalBndryCellCoordinates(mMax(noAzimuthalMbCells * nDim, (int64_t)1), AT_,
24887 "azimuthalndryCellCoordinates");
24888 if(grid().azimuthalPeriodicity()) {
24889 cnt = 0;
24890 for(auto it = m_azimuthalNearBoundaryBackup.begin(); it != m_azimuthalNearBoundaryBackup.end(); ++it) {
24891 MInt cellId = it->first;
24892 azimuthalBndryCellVolumesIds[cnt] = c_globalId(cellId);
24893 azimuthalBndryCellVolumes[cnt] = (it->second).first[nDim]; // cellVolume
24894 for(MInt d = 0; d < nDim; d++) {
24895 azimuthalBndryCellCoordinates[cnt * nDim + d] = (it->second).first[d];
24896 }
24897 cnt++;
24898 }
24899 }
24900
24901 MFloatScratchSpace bodyRotation(m_noEmbeddedBodies, 3, AT_, "bodyRotation");
24902 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
24903 getBodyRotation(k, &bodyRotation[3 * k]);
24904 }
24905
24906 {
24907 map<MLong, MFloat> tmpVol;
24908 for(MInt i = 0; i < noMbCells; i++) {
24909 tmpVol.insert(make_pair(bndryCellVolumesIds[i], bndryCellVolumes[i]));
24910 }
24911 cnt = 0;
24912 for(map<MLong, MFloat>::iterator it = tmpVol.begin(); it != tmpVol.end(); it++) {
24913 bndryCellVolumesIds[cnt] = it->first;
24914 bndryCellVolumes[cnt] = it->second;
24915 cnt++;
24916 }
24917
24918 if(grid().azimuthalPeriodicity()) {
24919 multimap<MLong, vector<MFloat>> tmpVolAzimuthal;
24920 for(MInt i = 0; i < noAzimuthalMbCells; i++) {
24921 vector<MFloat> tmpFloats(nDim + 1);
24922 for(MInt d = 0; d < nDim; d++) {
24923 tmpFloats[d] = azimuthalBndryCellCoordinates[i * nDim + d];
24924 }
24925 tmpFloats[nDim] = azimuthalBndryCellVolumes[i];
24926 tmpVolAzimuthal.insert(make_pair(azimuthalBndryCellVolumesIds[i], tmpFloats));
24927 }
24928 cnt = 0;
24929 for(multimap<MLong, vector<MFloat>>::iterator it = tmpVolAzimuthal.begin(); it != tmpVolAzimuthal.end(); it++) {
24930 azimuthalBndryCellVolumesIds[cnt] = it->first;
24931 for(MInt d = 0; d < nDim; d++) {
24932 azimuthalBndryCellCoordinates[cnt * nDim + d] = (it->second)[d];
24933 }
24934 azimuthalBndryCellVolumes[cnt] = (it->second)[nDim];
24935 cnt++;
24936 }
24937 }
24938
24939 ParallelIo::size_type start = 0;
24940 ParallelIo::size_type count = 0;
24941
24942 using namespace maia::parallel_io;
24943 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
24944
24945 // Creating file header.
24946 parallelIo.defineScalar(PIO_INT, "DOF");
24947
24948 count = DOF;
24949 parallelIo.defineArray(PIO_FLOAT, "bodyTemperature", count);
24950
24951 count = DOF_TRANS;
24952 parallelIo.defineArray(PIO_FLOAT, "bodyCenter", count);
24953 parallelIo.defineArray(PIO_FLOAT, "bodyVelocity", count);
24954 parallelIo.defineArray(PIO_FLOAT, "bodyAcceleration", count);
24955 parallelIo.defineArray(PIO_FLOAT, "bodyForce", count);
24956
24957 count = DOF_ROT;
24958 parallelIo.defineArray(PIO_FLOAT, "bodyRotation", count);
24959 parallelIo.defineArray(PIO_FLOAT, "bodyAngularVelocity", count);
24960 parallelIo.defineArray(PIO_FLOAT, "bodyAngularAcceleration", count);
24961 parallelIo.defineArray(PIO_FLOAT, "bodyTorque", count);
24962
24963 count = DOF_QUAT;
24964 parallelIo.defineArray(PIO_FLOAT, "bodyQuaternion", count);
24965
24966 count = DOF_VOL;
24967 parallelIo.defineArray(PIO_LONG, "bndryCellVolumesIds", count);
24968 parallelIo.defineArray(PIO_FLOAT, "bndryCellVolumes", count);
24969
24970 if(grid().azimuthalPeriodicity()) {
24971 count = DOF_VOL_AZIMUTHAL;
24972 parallelIo.defineArray(PIO_LONG, "azimuthalBndryCellVolumesIds", count);
24973 parallelIo.defineArray(PIO_FLOAT, "azimuthalBndryCellVolumes", count);
24974 count *= nDim;
24975 parallelIo.defineArray(PIO_FLOAT, "azimuthalBndryCellCoordinates", count);
24976 }
24977
24978 parallelIo.writeScalar(DOF, "DOF");
24979
24980
24981 start = 0;
24982 count = DOF;
24983 parallelIo.setOffset(count, start);
24984 parallelIo.writeArray(m_bodyTemperature, "bodyTemperature");
24985
24986 count = DOF_TRANS;
24987 parallelIo.setOffset(count, start);
24988 parallelIo.writeArray(m_bodyCenter, "bodyCenter");
24989 parallelIo.writeArray(m_bodyVelocity, "bodyVelocity");
24990 parallelIo.writeArray(m_bodyAcceleration, "bodyAcceleration");
24991 parallelIo.writeArray(m_bodyForce, "bodyForce");
24992
24993 count = DOF_ROT;
24994 parallelIo.setOffset(count, start);
24995 parallelIo.writeArray(&bodyRotation[0], "bodyRotation");
24996
24997 if(m_LsRotate && !m_constructGField) {
24998 // This can occur for multisolver where the lsSolver is inactive on some ranks
24999 MIntScratchSpace invalid(noDomains(), AT_, "invalid");
25000 invalid.fill(-1);
25001 MInt validRoot = -1;
25002 if(std::isnan(m_bodyAngularVelocity[0])) invalid[domainId()] = 1;
25003 MPI_Allreduce(MPI_IN_PLACE, invalid.getPointer(), noDomains(), MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
25004 "invalid");
25005 for(MInt d = 0; d < noDomains(); d++) {
25006 if(invalid[d] < 0) validRoot = d;
25007 }
25008 MPI_Bcast(&m_bodyAngularVelocity[0], m_noEmbeddedBodies * nDim, MPI_DOUBLE, validRoot, mpiComm(), AT_,
25009 "m_bodyAngularVelocity");
25010 MPI_Bcast(&m_bodyAngularAcceleration[0], m_noEmbeddedBodies * nDim, MPI_DOUBLE, validRoot, mpiComm(), AT_,
25011 "m_bodyAngularAcceleration");
25012 }
25013
25014 parallelIo.writeArray(m_bodyAngularVelocity, "bodyAngularVelocity");
25015 parallelIo.writeArray(m_bodyAngularAcceleration, "bodyAngularAcceleration");
25016 parallelIo.writeArray(m_bodyTorque, "bodyTorque");
25017
25018 count = DOF_QUAT;
25019 parallelIo.setOffset(count, start);
25020 parallelIo.writeArray(m_bodyQuaternion, "bodyQuaternion");
25021
25022 start = volOffsets(domainId());
25023 count = noMbCells;
25024 parallelIo.setOffset(count, start);
25025 parallelIo.writeArray(bndryCellVolumesIds.begin(), "bndryCellVolumesIds");
25026 parallelIo.writeArray(bndryCellVolumes.begin(), "bndryCellVolumes");
25027
25028 if(grid().azimuthalPeriodicity()) {
25029 start = volOffsetsAzimuthal(domainId());
25030 count = noAzimuthalMbCells;
25031 parallelIo.setOffset(count, start);
25032 parallelIo.writeArray(azimuthalBndryCellVolumesIds.begin(), "azimuthalBndryCellVolumesIds");
25033 parallelIo.writeArray(azimuthalBndryCellVolumes.begin(), "azimuthalBndryCellVolumes");
25034 start = volOffsetsAzimuthal(domainId()) * nDim;
25035 count = noAzimuthalMbCells * nDim;
25036 parallelIo.setOffset(count, start);
25037 parallelIo.writeArray(azimuthalBndryCellCoordinates.begin(), "azimuthalBndryCellCoordinates");
25038 }
25039 }
25040
25041 if(domainId() == 0) cerr << "ok" << endl;
25042}
25043
25044
25055template <MInt nDim, class SysEqn>
25057 TRACE();
25058
25059 if(m_noEmbeddedBodies == 0) return;
25060
25061 stringstream fn;
25062 fn.clear();
25063 if(m_useNonSpecifiedRestartFile) {
25064 if(!m_multipleFvSolver) {
25065 fn << restartDir() << "restartBodyData";
25066 } else {
25067 fn << restartDir() << "restartBodyData_" << solverId();
25068 }
25069 } else {
25070 if(!m_multipleFvSolver) {
25071 fn << restartDir() << "restartBodyData_" << m_restartTimeStep;
25072 } else {
25073 fn << restartDir() << "restartBodyData_" << solverId() << "_" << m_restartTimeStep;
25074 }
25075 }
25076 fn << ParallelIo::fileExt();
25077
25078 MString fileName = fn.str();
25079
25080#ifdef _MB_DEBUG_
25081 MInt cnt = 0;
25082#endif
25083
25084 const MLong DOF = m_noEmbeddedBodies;
25085 const MLong DOF_TRANS = nDim * m_noEmbeddedBodies;
25086 const MLong DOF_ROT = 3 * m_noEmbeddedBodies;
25087 const MLong DOF_QUAT = 4 * m_noEmbeddedBodies;
25088
25089 if(domainId() == 0) {
25090 cerr << "loading body restart file " << fn.str() << " at " << globalTimeStep << "...";
25091 }
25092
25093 int64_t noMbCells = 0;
25094 int64_t domainOffset0 = (int64_t)domainOffset(domainId() + 1);
25095 int64_t domainOffset1 = (int64_t)domainOffset(domainId());
25096
25097 // check that the number of bndry-Cells in the file matches
25098 // the number of already created bndryCells
25099 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
25100 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25101 if(a_isHalo(cellId)) continue;
25102 if(a_isPeriodic(cellId)) continue;
25103 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
25104 domainOffset0 = mMin(domainOffset0, (int64_t)c_globalId(cellId));
25105 domainOffset1 = mMax(domainOffset1, (int64_t)c_globalId(cellId));
25106 noMbCells++;
25107 }
25108 domainOffset1++;
25109 domainOffset0 = mMax(domainOffset0, (int64_t)domainOffset(domainId()));
25110 domainOffset1 = mMin(domainOffset1, (int64_t)domainOffset(domainId() + 1));
25111
25112 if(noMbCells == 0) {
25113 domainOffset0 = (int64_t)domainOffset(domainId());
25114 // NOTE: check the below, this makes hardly any sense!
25115 domainOffset1 = domainOffset0 + 1;
25116 if(readMode == 2) { // working version
25117 domainOffset1 = (int64_t)domainOffset(domainId() + 1);
25118 }
25119 }
25120 if(domainOffset0 > domainOffset1 || m_bodyTypeMb == 3) {
25121 domainOffset0 = (int64_t)domainOffset(domainId());
25122 domainOffset1 = (int64_t)domainOffset(domainId() + 1);
25123 }
25124 int64_t noMbCellsGlobal = noMbCells;
25125
25126 if(noDomains() > 1) {
25127 noMbCellsGlobal = noMbCells;
25128 MPI_Allreduce(MPI_IN_PLACE, &noMbCellsGlobal, 1, MPI_INT64_T, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
25129 "noMbCellsGlobal");
25130 }
25131
25132 using namespace maia::parallel_io;
25133 ParallelIo parallelIo(fileName, PIO_READ, mpiComm());
25134
25135 ParallelIo::size_type size = 0;
25136 ParallelIo::size_type start = 0;
25137 ParallelIo::size_type count = 0;
25138
25139 if(parallelIo.hasDataset("DOF")) {
25140 parallelIo.readScalar(&size, "DOF");
25141 } else {
25142 size = parallelIo.getArraySize("bodyTemperature");
25143 }
25144
25145 if(size != DOF) {
25146 mTerm(1, AT_,
25147 "No embedded bodies mismatch in loadBodyRestartFile(): " + to_string(m_noEmbeddedBodies)
25148 + " != " + to_string(size) + ".");
25149 }
25150
25151 size = parallelIo.getArraySize("bndryCellVolumesIds");
25152
25153 if(noMbCellsGlobal > 0 && size != (MPI_Offset)noMbCellsGlobal && m_geometryChange == nullptr) {
25154 if(domainId() == 0) {
25155 cerr << "Warning: No boundary cells mismatch in loadBodyRestartFile(): " + to_string(noMbCellsGlobal)
25156 + " != " + to_string(size) + ". Might be due to non-converged to fluid-structure iterations."
25157 << endl;
25158 }
25159 }
25160 const MLong DOF_VOL = size;
25161
25162 // read body properties:
25163 count = DOF;
25164 parallelIo.setOffset(count, start);
25165 parallelIo.readArray(m_bodyTemperature, "bodyTemperature");
25166
25167 count = DOF_TRANS;
25168 parallelIo.setOffset(count, start);
25169 parallelIo.readArray(m_bodyCenter, "bodyCenter");
25170 parallelIo.readArray(m_bodyVelocity, "bodyVelocity");
25171 parallelIo.readArray(m_bodyAcceleration, "bodyAcceleration");
25172 parallelIo.readArray(m_bodyForce, "bodyForce");
25173
25174 count = DOF_ROT;
25175 parallelIo.setOffset(count, start);
25176 parallelIo.readArray(m_bodyAngularVelocity, "bodyAngularVelocity");
25177 parallelIo.readArray(m_bodyAngularAcceleration, "bodyAngularAcceleration");
25178 parallelIo.readArray(m_bodyTorque, "bodyTorque");
25179
25180 count = DOF_QUAT;
25181 parallelIo.setOffset(count, start);
25182 parallelIo.readArray(m_bodyQuaternion, "bodyQuaternion");
25183
25184 if(readMode == 2) {
25185 ASSERT(m_geometryChange != nullptr, "");
25186 if(domainId() == 0) {
25187 cerr << "Storing old bndryCell volume for geometryChange!" << endl;
25188 }
25189 m_oldGeomBndryCells.clear();
25190 }
25191
25192 MInt mismatchCnt = 0;
25193 if(readMode > 0 && DOF_VOL > 0 && DOF_VOL < domainOffset(noDomains())) {
25194 MBool readVolStrided = false;
25195 if((readVolStrided || DOF_VOL <= noDomains()) && readMode != 2) {
25196 start = 0;
25197 count = DOF_VOL;
25198 if(readVolStrided) {
25199 MPI_Offset noSamples = (MPI_Offset)max(2, min((MInt)DOF_VOL, noDomains() / 2));
25200 MPI_Offset sampleWidth = ((MPI_Offset)(DOF_VOL - 1)) / (noSamples - 1);
25201 MLongScratchSpace sampledIds(noSamples, AT_, "sampledIds");
25202 start = 0;
25203 count = noSamples;
25204 parallelIo.setOffset(count, start);
25205 parallelIo.readArray(&sampledIds[0], "bndryCellVolumesIds", -1, sampleWidth);
25206 start = 0;
25207 count = 0;
25208 MPI_Offset end = DOF_VOL;
25209 for(MPI_Offset i = 0; i < noSamples; i++) {
25210 if(domainOffset0 >= sampledIds[i])
25211 start = i * sampleWidth;
25212 else
25213 break;
25214 }
25215 for(MPI_Offset i = noSamples - 1; i >= 0; i--) {
25216 if(domainOffset1 < sampledIds[i])
25217 end = i * sampleWidth;
25218 else
25219 break;
25220 }
25221 MInt diff = end - start;
25222 count = (diff > 0) ? (MPI_Offset)diff : 0;
25223 }
25224 MLongScratchSpace bndryCellVolumesIds(count + 1, AT_, "bndryCellVolumesIds");
25225 MFloatScratchSpace bndryCellVolumes(count + 1, AT_, "bndryCellVolumes");
25226
25227 parallelIo.setOffset(count, start);
25228 parallelIo.readArray(&bndryCellVolumesIds[0], "bndryCellVolumesIds");
25229 parallelIo.readArray(&bndryCellVolumes[0], "bndryCellVolumes");
25230
25231 MIntScratchSpace bndCells(domainOffset1 - domainOffset0 + 1, AT_, "bndCells");
25232 bndCells.fill(-1);
25233 for(MInt i = 0; i < count; i++) {
25234 if(bndryCellVolumesIds[i] < domainOffset0 || bndryCellVolumesIds[i] >= domainOffset1) {
25235 continue;
25236 }
25237 bndCells[bndryCellVolumesIds[i] - domainOffset0] = i;
25238 }
25239#ifdef _MB_DEBUG_
25240 cerr << domainId() << ": read " << bndCells.size() << " of " << DOF_VOL
25241 << " volume entries within domain offsets " << domainOffset0 << "-" << domainOffset1 << endl;
25242#endif
25243
25244 mismatchCnt = 0;
25245
25246 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
25247 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25248 if(a_isHalo(cellId)) continue;
25249
25250 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
25251 if(c_globalId(cellId) < domainOffset0 || c_globalId(cellId) >= domainOffset1) continue;
25252 if(bndCells[c_globalId(cellId) - domainOffset0] > -1) {
25253 // const MInt i = it->second;
25254 MInt i = bndCells[c_globalId(cellId) - domainOffset0];
25255 a_cellVolume(cellId) = bndryCellVolumes[i];
25256 m_cellVolumesDt1[cellId] = bndryCellVolumes[i];
25257 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = bndryCellVolumes[i];
25258 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
25259 m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume = bndryCellVolumes[i];
25260
25261#ifdef _MB_DEBUG_
25262 if(a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) < F0
25263 || a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) > F1) {
25264 cerr << domainId() << ": warning volume fraction in loadBodyRestartFile() "
25265 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << " for cell " << cellId << endl;
25266 }
25267#endif
25268 } else {
25269 mismatchCnt++;
25270 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
25271 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
25272 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = a_cellVolume(cellId);
25273 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
25274#ifdef _MB_DEBUG_
25275 if(cnt < 20) {
25276 cerr << domainId() << ": Corresponding boundary id not found. "
25277 << "Might be due to non-converged to fluid-structure iterations: /g " << c_globalId(cellId) << " /c "
25278 << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, 2)
25279 << " /ls " << a_levelSetValuesMb(cellId, 0) / c_cellLengthAtCell(cellId) << " /v "
25280 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume / grid().gridCellVolume(a_level(cellId)) << " "
25281 << domainOffset0 << " " << domainOffset1 << endl;
25282 cnt++;
25283 if(cnt == 20) {
25284 cerr << domainId() << ": Exceeding 20, not reporting any more." << endl;
25285 }
25286 }
25287#endif
25288 }
25289 }
25290 MPI_Allreduce(MPI_IN_PLACE, &mismatchCnt, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "mismatchCnt");
25291 if(domainId() == 0) {
25292 cerr << "mismatch cnt: " << mismatchCnt << " out of " << DOF_VOL << endl;
25293 }
25294
25295 } else {
25296 start = (DOF_VOL / noDomains()) * domainId();
25297 count = (domainId() == noDomains() - 1) ? DOF_VOL - start : (DOF_VOL / noDomains());
25298
25299 MLongScratchSpace bndryCellVolumesIdsTmp(count, AT_, "bndryCellVolumesIdsTmp");
25300 MFloatScratchSpace bndryCellVolumesTmp(count, AT_, "bndryCellVolumesTmp");
25301
25302 parallelIo.setOffset(count, start);
25303 parallelIo.readArray(&bndryCellVolumesIdsTmp[0], "bndryCellVolumesIds");
25304 parallelIo.readArray(&bndryCellVolumesTmp[0], "bndryCellVolumes");
25305
25306 MIntScratchSpace sendCnt(noDomains(), AT_, "sendCnt");
25307 MIntScratchSpace recvCnt(noDomains(), AT_, "recvCnt");
25308 MIntScratchSpace recvOffsets(noDomains() + 1, AT_, "recvOffsets");
25309 MIntScratchSpace sendOffsets(noDomains(), AT_, "sendOffsets");
25310 sendCnt.fill(0);
25311 recvCnt.fill(0);
25312 recvOffsets.fill(0);
25313 sendOffsets.fill(-1);
25314 MInt nbDom = noDomains() / 2;
25315 MLong minId = std::numeric_limits<MLong>::max();
25316 MLong bitOffsetBuf = 0;
25317 for(MInt i = 0; i < count; i++) {
25318 minId = mMin(minId, bndryCellVolumesIdsTmp[i]);
25319 }
25320 if(minId < grid().bitOffset()) {
25321 bitOffsetBuf = grid().bitOffset();
25322 } else {
25323 bitOffsetBuf = 0;
25324 }
25325
25326 for(MInt i = 0; i < count; i++) {
25327 bndryCellVolumesIdsTmp[i] += bitOffsetBuf;
25328 }
25329 for(MInt i = 0; i < count; i++) {
25330 if(bndryCellVolumesIdsTmp(i) >= domainOffset(noDomains())) {
25331 cerr << domainId() << ": index out of range " << bndryCellVolumesIdsTmp(i) << " " << domainOffset(noDomains())
25332 << " " << grid().noCellsGlobal() << " " << grid().bitOffset() << " " << bitOffsetBuf << endl;
25333 continue;
25334 }
25335 while(bndryCellVolumesIdsTmp(i) < domainOffset(nbDom) || bndryCellVolumesIdsTmp(i) >= domainOffset(nbDom + 1)) {
25336 if(bndryCellVolumesIdsTmp(i) < domainOffset(nbDom)) nbDom--;
25337 if(bndryCellVolumesIdsTmp(i) >= domainOffset(nbDom + 1)) nbDom++;
25338 }
25339 if(sendCnt(nbDom) == 0) sendOffsets[nbDom] = i;
25340 sendCnt(nbDom)++;
25341 }
25342 for(MInt i = 0; i < noDomains(); i++) {
25343 if(sendCnt(i) > 0 && sendOffsets[i] < 0) {
25344 cerr << domainId() << ": Warning send offset not set: " << i << endl;
25345 }
25346 }
25347 MPI_Alltoall(&sendCnt[0], 1, MPI_INT, &recvCnt[0], 1, MPI_INT, mpiComm(), AT_, "sendCnt[0]", "recvCnt[0]");
25348 MInt totalNoRecv = 0;
25349 recvOffsets[0] = 0;
25350 for(MInt i = 0; i < noDomains(); i++) {
25351 totalNoRecv += recvCnt(i);
25352 recvOffsets[i + 1] = recvOffsets[i] + recvCnt(i);
25353 }
25354 MLongScratchSpace bndryCellVolumesIds(mMax(1, totalNoRecv), AT_, "bndryCellVolumesIds");
25355 MFloatScratchSpace bndryCellVolumes(mMax(1, totalNoRecv), AT_, "bndryCellVolumes");
25356 ScratchSpace<MPI_Request> sendReq(noDomains(), AT_, "sendReq");
25357 sendReq.fill(MPI_REQUEST_NULL);
25358 MInt scnt = 0;
25359 for(MInt i = 0; i < noDomains(); i++) {
25360 if(sendCnt[i] == 0) continue;
25361 MPI_Issend(&(bndryCellVolumesIdsTmp[sendOffsets[i]]), sendCnt[i], MPI_LONG, i, 432, mpiComm(), &sendReq[scnt],
25362 AT_, "(bndryCellVolumesIdsTmp[sendOffsets[i]])");
25363 scnt++;
25364 }
25365 for(MInt i = 0; i < noDomains(); i++) {
25366 if(recvCnt[i] == 0) continue;
25367 MPI_Recv(&(bndryCellVolumesIds[recvOffsets[i]]), recvCnt[i], MPI_LONG, i, 432, mpiComm(), MPI_STATUS_IGNORE,
25368 AT_, "(bndryCellVolumesIds[recvOffsets[i]])");
25369 }
25370 if(scnt > 0) MPI_Waitall(scnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
25371 sendReq.fill(MPI_REQUEST_NULL);
25372 scnt = 0;
25373 for(MInt i = 0; i < noDomains(); i++) {
25374 if(sendCnt[i] == 0) continue;
25375 MPI_Issend(&(bndryCellVolumesTmp[sendOffsets[i]]), sendCnt[i], MPI_DOUBLE, i, 433, mpiComm(), &sendReq[scnt],
25376 AT_, "(bndryCellVolumesTmp[sendOffsets[i]])");
25377 scnt++;
25378 }
25379 for(MInt i = 0; i < noDomains(); i++) {
25380 if(recvCnt[i] == 0) continue;
25381 MPI_Recv(&(bndryCellVolumes[recvOffsets[i]]), recvCnt[i], MPI_DOUBLE, i, 433, mpiComm(), MPI_STATUS_IGNORE, AT_,
25382 "(bndryCellVolumes[recvOffsets[i]])");
25383 }
25384 if(scnt > 0) MPI_Waitall(scnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
25385
25386 MIntScratchSpace bndCells(domainOffset1 - domainOffset0 + 1, AT_, "bndCells");
25387 bndCells.fill(-1);
25388 for(MInt i = 0; i < totalNoRecv; i++) {
25389 if(bndryCellVolumesIds[i] < domainOffset0 || bndryCellVolumesIds[i] >= domainOffset1) {
25390 continue;
25391 }
25392 bndCells[bndryCellVolumesIds[i] - domainOffset0] = i;
25393 }
25394
25395 mismatchCnt = 0;
25396
25397 if(readMode == 1) {
25398 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
25399 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25400 if(a_isHalo(cellId)) continue;
25401 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
25402 if(c_globalId(cellId) < domainOffset0 || c_globalId(cellId) >= domainOffset1) continue;
25403 const MInt i = bndCells[c_globalId(cellId) - domainOffset0];
25404 if(i > -1) {
25405 a_cellVolume(cellId) = bndryCellVolumes[i];
25406 m_cellVolumesDt1[cellId] = bndryCellVolumes[i];
25407 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = bndryCellVolumes[i];
25408 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
25409 m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume = bndryCellVolumes[i];
25410#ifdef _MB_DEBUG_
25411 if(a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) < F0
25412 || a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) > F1) {
25413 cerr << domainId() << ": warning volume fraction in loadBodyRestartFile() "
25414 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << " for cell " << cellId << " "
25415 << c_globalId(cellId) << endl;
25416 }
25417#endif
25418 } else {
25419 mismatchCnt++;
25420 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
25421 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
25422 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = a_cellVolume(cellId);
25423 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
25424
25425#ifdef _MB_DEBUG_
25426 if(mismatchCnt < 20) {
25427 cerr << domainId()
25428 << ": Corresponding boundary id not found. Might be due to non-converged to fluid-structure "
25429 "iterations: /g "
25430 << c_globalId(cellId) << " /c " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " "
25431 << a_coordinate(cellId, 2) << " /v "
25432 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume / grid().gridCellVolume(a_level(cellId)) << " "
25433 << domainOffset0 << " " << domainOffset1 << endl;
25434 cnt++;
25435 if(cnt == 20) {
25436 cerr << domainId() << ": Exceeding 20, not reporting any more." << endl;
25437 }
25438 }
25439#endif
25440 }
25441 }
25442
25443 MPI_Allreduce(MPI_IN_PLACE, &mismatchCnt, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "mismatchCnt");
25444
25445 if(domainId() == 0) {
25446 cerr << "mismatch cnt: " << mismatchCnt << " out of " << DOF_VOL << endl;
25447 }
25448
25449 // for large missmatch count assume complete irregularity and treat all cells as missmatched!
25450 if(mismatchCnt > 0.5 * DOF_VOL) {
25451 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
25452 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25453 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
25454 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
25455 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = a_cellVolume(cellId);
25456 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
25457 }
25458 }
25459
25460 } else { // read mode 2!
25461
25462 // store volume from file in array,
25463 // which is then correctly keept during the forcedAdaptation
25464 // and set for the bndryCells which remain the same thoughout the geometryChange!
25465 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
25466 const MInt i = bndCells[cellId];
25467 if(i > -1) {
25468 const MFloat volume = bndryCellVolumes[i];
25469 m_oldGeomBndryCells.insert(make_pair(cellId, volume));
25470 }
25471 }
25472 }
25473 }
25474 }
25475
25476 // set volumes on halo cells
25477 exchangeData(&a_cellVolume(0), 1);
25478
25479 // Read cellVolume of azimuthal halo cells
25480 if(grid().azimuthalPeriodicity() && readMode == 1) {
25481 size = parallelIo.getArraySize("azimuthalBndryCellVolumesIds");
25482 const MLong DOF_VOL_AZIMUTHAL = size;
25483 start = (DOF_VOL_AZIMUTHAL / noDomains()) * domainId();
25484 count = (domainId() == noDomains() - 1) ? DOF_VOL_AZIMUTHAL - start : (DOF_VOL_AZIMUTHAL / noDomains());
25485
25486 MLongScratchSpace azimuthalBndryCellVolumesIdsTmp(count, AT_, "azimuthalBndryCellVolumesIdsTmp");
25487 MFloatScratchSpace azimuthalBndryCellVolumesTmp(count, AT_, "azimuthalBndryCellVolumesTmp");
25488 MFloatScratchSpace azimuthalBndryCellCoordinatesTmp(count * nDim, AT_, "azimuthalBndryCellCoordinatesTmp");
25489
25490 parallelIo.setOffset(count, start);
25491 parallelIo.readArray(&azimuthalBndryCellVolumesIdsTmp[0], "azimuthalBndryCellVolumesIds");
25492 parallelIo.readArray(&azimuthalBndryCellVolumesTmp[0], "azimuthalBndryCellVolumes");
25493 parallelIo.setOffset(count * nDim, start * nDim);
25494 parallelIo.readArray(&azimuthalBndryCellCoordinatesTmp[0], "azimuthalBndryCellCoordinates");
25495
25496 MIntScratchSpace sendCntAzimuthal(noDomains(), AT_, "sendCntAzimuthal");
25497 MIntScratchSpace recvCntAzimuthal(noDomains(), AT_, "recvCntAzimuthal");
25498 MIntScratchSpace recvOffsetsAzimuthal(noDomains() + 1, AT_, "recvOffsetsAzimuthal");
25499 MIntScratchSpace sendOffsetsAzimuthal(noDomains(), AT_, "sendOffsetsAzimuthal");
25500 sendCntAzimuthal.fill(0);
25501 recvCntAzimuthal.fill(0);
25502 recvOffsetsAzimuthal.fill(0);
25503 sendOffsetsAzimuthal.fill(-1);
25504 MInt nbDom = noDomains() / 2;
25505 MLong minId = std::numeric_limits<MLong>::max();
25506 MLong bitOffsetBuf = 0;
25507 for(MInt i = 0; i < count; i++) {
25508 minId = mMin(minId, azimuthalBndryCellVolumesIdsTmp[i]);
25509 }
25510 if(minId < grid().bitOffset()) {
25511 bitOffsetBuf = grid().bitOffset();
25512 } else {
25513 bitOffsetBuf = 0;
25514 }
25515
25516 for(MInt i = 0; i < count; i++) {
25517 azimuthalBndryCellVolumesIdsTmp[i] += bitOffsetBuf;
25518 }
25519 for(MInt i = 0; i < count; i++) {
25520 if(azimuthalBndryCellVolumesIdsTmp(i) >= domainOffset(noDomains())) {
25521 cerr << domainId() << ": index out of range " << azimuthalBndryCellVolumesIdsTmp(i) << " "
25522 << domainOffset(noDomains()) << " " << grid().noCellsGlobal() << " " << grid().bitOffset() << " "
25523 << bitOffsetBuf << endl;
25524 continue;
25525 }
25526 while(azimuthalBndryCellVolumesIdsTmp(i) < domainOffset(nbDom)
25527 || azimuthalBndryCellVolumesIdsTmp(i) >= domainOffset(nbDom + 1)) {
25528 if(azimuthalBndryCellVolumesIdsTmp(i) < domainOffset(nbDom)) nbDom--;
25529 if(azimuthalBndryCellVolumesIdsTmp(i) >= domainOffset(nbDom + 1)) nbDom++;
25530 }
25531 if(sendCntAzimuthal(nbDom) == 0) sendOffsetsAzimuthal[nbDom] = i;
25532 sendCntAzimuthal(nbDom)++;
25533 }
25534 for(MInt i = 0; i < noDomains(); i++) {
25535 if(sendCntAzimuthal(i) > 0 && sendOffsetsAzimuthal[i] < 0) {
25536 cerr << domainId() << ": Warning send offset not set: " << i << endl;
25537 }
25538 }
25539 MPI_Alltoall(&sendCntAzimuthal[0], 1, MPI_INT, &recvCntAzimuthal[0], 1, MPI_INT, mpiComm(), AT_,
25540 "sendCntAzimuthal[0]", "recvCntAzimuthal[0]");
25541 MInt totalNoRecv = 0;
25542 recvOffsetsAzimuthal[0] = 0;
25543 for(MInt i = 0; i < noDomains(); i++) {
25544 totalNoRecv += recvCntAzimuthal(i);
25545 recvOffsetsAzimuthal[i + 1] = recvOffsetsAzimuthal[i] + recvCntAzimuthal(i);
25546 }
25547 MLongScratchSpace azimuthalBndryCellVolumesIds(mMax(1, totalNoRecv), AT_, "azimuthalBndryCellVolumesIds");
25548 MFloatScratchSpace azimuthalBndryCellVolumes(mMax(1, totalNoRecv), AT_, "azimuthalBndryCellVolumes");
25549 MFloatScratchSpace azimuthalBndryCellCoordinates(mMax(1, nDim * totalNoRecv), AT_, "azimuthalBndryCellCoordinates");
25550 ScratchSpace<MPI_Request> sendReqAzimuthal(noDomains(), AT_, "sendReqAzimuthal");
25551 sendReqAzimuthal.fill(MPI_REQUEST_NULL);
25552 MInt scnt = 0;
25553 for(MInt i = 0; i < noDomains(); i++) {
25554 if(sendCntAzimuthal[i] == 0) continue;
25555 MPI_Issend(&(azimuthalBndryCellVolumesIdsTmp[sendOffsetsAzimuthal[i]]), sendCntAzimuthal[i], MPI_LONG, i, 432,
25556 mpiComm(), &sendReqAzimuthal[scnt], AT_, "(azimuthalBndryCellVolumesIdsTmp[sendOffsetsAzimuthal[i]])");
25557 scnt++;
25558 }
25559 for(MInt i = 0; i < noDomains(); i++) {
25560 if(recvCntAzimuthal[i] == 0) continue;
25561 MPI_Recv(&(azimuthalBndryCellVolumesIds[recvOffsetsAzimuthal[i]]), recvCntAzimuthal[i], MPI_LONG, i, 432,
25562 mpiComm(), MPI_STATUS_IGNORE, AT_, "(azimuthalBndryCellVolumesIds[recvOffsets[i]])");
25563 }
25564 if(scnt > 0) MPI_Waitall(scnt, &sendReqAzimuthal[0], MPI_STATUSES_IGNORE, AT_);
25565 sendReqAzimuthal.fill(MPI_REQUEST_NULL);
25566 scnt = 0;
25567 for(MInt i = 0; i < noDomains(); i++) {
25568 if(sendCntAzimuthal[i] == 0) continue;
25569 MPI_Issend(&(azimuthalBndryCellVolumesTmp[sendOffsetsAzimuthal[i]]), sendCntAzimuthal[i], MPI_DOUBLE, i, 433,
25570 mpiComm(), &sendReqAzimuthal[scnt], AT_, "(azimuthalBndryCellVolumesTmp[sendOffsetsAzimuthal[i]])");
25571 scnt++;
25572 }
25573 for(MInt i = 0; i < noDomains(); i++) {
25574 if(recvCntAzimuthal[i] == 0) continue;
25575 MPI_Recv(&(azimuthalBndryCellVolumes[recvOffsetsAzimuthal[i]]), recvCntAzimuthal[i], MPI_DOUBLE, i, 433,
25576 mpiComm(), MPI_STATUS_IGNORE, AT_, "(azimuthalBndryCellVolumes[recvOffsetsAzimuthal[i]])");
25577 }
25578 if(scnt > 0) MPI_Waitall(scnt, &sendReqAzimuthal[0], MPI_STATUSES_IGNORE, AT_);
25579 sendReqAzimuthal.fill(MPI_REQUEST_NULL);
25580 scnt = 0;
25581 for(MInt i = 0; i < noDomains(); i++) {
25582 if(sendCntAzimuthal[i] == 0) continue;
25583 MPI_Issend(&(azimuthalBndryCellCoordinatesTmp[nDim * sendOffsetsAzimuthal[i]]), nDim * sendCntAzimuthal[i],
25584 MPI_DOUBLE, i, 434, mpiComm(), &sendReqAzimuthal[scnt], AT_,
25585 "(azimuthalBndryCellCoordinatesTmp[nDim*sendOffsetsAzimuthal[i]])");
25586 scnt++;
25587 }
25588 for(MInt i = 0; i < noDomains(); i++) {
25589 if(recvCntAzimuthal[i] == 0) continue;
25590 MPI_Recv(&(azimuthalBndryCellCoordinates[nDim * recvOffsetsAzimuthal[i]]), nDim * recvCntAzimuthal[i], MPI_DOUBLE,
25591 i, 434, mpiComm(), MPI_STATUS_IGNORE, AT_,
25592 "(azimuthalBndryCellCoordinates[nDim*recvOffsetsAzimuthal[i]])");
25593 }
25594 if(scnt > 0) MPI_Waitall(scnt, &sendReqAzimuthal[0], MPI_STATUSES_IGNORE, AT_);
25595
25596 multimap<MLong, vector<MFloat>> tmpVolAzimuthal;
25597 for(MInt i = 0; i < totalNoRecv; i++) {
25598 MLong cellId = azimuthalBndryCellVolumesIds[i];
25599 if(cellId >= domainOffset(domainId()) && cellId < domainOffset(domainId() + 1)) {
25600 vector<MFloat> tmpFloats(nDim + 1);
25601 for(MInt d = 0; d < nDim; d++) {
25602 tmpFloats[d] = azimuthalBndryCellCoordinates[i * nDim + d];
25603 }
25604 tmpFloats[nDim] = azimuthalBndryCellVolumes[i];
25605 tmpVolAzimuthal.insert(make_pair(cellId, tmpFloats));
25606 } else {
25607 cerr << "ERROR:" << domainId() << " " << cellId << " " << domainOffset(noDomains()) << " "
25608 << domainOffset(noDomains() + 1) << endl;
25609 mTerm(1, AT_, ": azimuthal data is broken.");
25610 }
25611 }
25612 MInt cnt = 0;
25613 MInt noFloatData = 3;
25614 MInt noIntData = 2;
25615 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
25616 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
25617 MInt cellId = grid().azimuthalWindowCell(i, j);
25618 if(tmpVolAzimuthal.count(c_globalId(cellId)) != 0) {
25619 MFloat cellLength = c_cellLengthAtCell(cellId);
25620 auto range = tmpVolAzimuthal.equal_range(c_globalId(cellId));
25621 for(auto it = range.first; it != range.second; ++it) {
25622 MBool isEqual = true;
25623 for(MInt d = 0; d < nDim; d++) {
25624 if(!approx((it->second)[d], this->m_azimuthalCartRecCoord[cnt * nDim + d],
25625 m_azimuthalCornerEps * cellLength)) {
25626 isEqual = false;
25627 }
25628 }
25629 if(isEqual) {
25630 vector<MFloat> tmpF(noFloatData + nDim);
25631 vector<MUlong> tmpI(noIntData);
25632 tmpF[0] = this->m_azimuthalCartRecCoord[cnt * nDim];
25633 tmpF[1] = this->m_azimuthalCartRecCoord[cnt * nDim + 1];
25634 if(nDim == 3) {
25635 tmpF[2] = this->m_azimuthalCartRecCoord[cnt * nDim + 2];
25636 }
25637 tmpF[nDim] = (it->second)[nDim]; // cellVolume
25638 tmpF[nDim + 1] = (it->second)[nDim]; // cellVolume
25639 tmpF[nDim + 2] = 0; // swepVol
25640
25641 tmpI[0] = 1;
25643 props[maia::fv::cell::p(SolverCell::IsMovingBnd)] = true;
25644 props[maia::fv::cell::p(SolverCell::NearWall)] = true;
25645 tmpI[1] = props.to_ulong(); // cell properties
25646 m_azimuthalNearBoundaryBackup.insert(make_pair(cellId, make_pair(tmpF, tmpI)));
25647
25648 continue;
25649 }
25650 }
25651 }
25652 cnt++;
25653 }
25654 }
25655 commAzimuthalPeriodicData();
25656 }
25657
25658 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
25659 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25660 if(a_isHalo(cellId)) {
25661 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
25662 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = a_cellVolume(cellId);
25663 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
25664 if(mismatchCnt < 0.5 * DOF_VOL) {
25665 m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume = a_cellVolume(cellId);
25666 }
25667 }
25668 }
25669
25670 cerr0 << "done" << endl;
25671}
25672
25673
25680template <MInt nDim, class SysEqn>
25682 TRACE();
25683
25684 MFloatScratchSpace oldVolumes(a_noCells(), 2, AT_, "oldVolumes");
25685 oldVolumes.fill(-1);
25686
25687 for(auto it = m_oldGeomBndryCells.begin(); it != m_oldGeomBndryCells.end(); it++) {
25688 const MInt cellId = it->first;
25689 const MFloat vol = it->second;
25690 oldVolumes(cellId, 0) = vol;
25691 }
25692
25693 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
25694 oldVolumes(cellId, 1) = a_cellVolume(cellId);
25695 }
25696
25697 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
25698 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25699 if(a_isHalo(cellId)) continue;
25700 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
25701 auto it0 = m_oldGeomBndryCells.find(cellId);
25702 if(it0 != m_oldGeomBndryCells.end()) {
25703 const MFloat vol = it0->second;
25704 m_oldGeomBndryCells.erase(it0);
25705 // only set volume from file, if it matches the current volume
25706 const MFloat volDif = fabs(a_cellVolume(cellId) - vol);
25707 if(volDif > 0.0001 * vol) {
25708 m_oldGeomBndryCells.insert(make_pair(cellId, -1));
25709 } else {
25710 a_cellVolume(cellId) = vol;
25711 m_cellVolumesDt1[cellId] = vol;
25712 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = vol;
25713 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
25714 m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume = vol;
25715 }
25716 }
25717 }
25718
25719 // set volumes on halo cells
25720 exchangeData(&a_cellVolume(0), 1);
25721 exchangeData(&oldVolumes[0], 2);
25722
25723 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
25724 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25725 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
25726 if(!a_isHalo(cellId)) continue;
25727 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
25728 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = a_cellVolume(cellId);
25729 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
25730 // only update bndryCell-volume for oldGeomBndryCells
25731 if(oldVolumes(cellId, 0) > 0) {
25732 // check if the halo cell is in the list and remove the entry
25733 auto it0 = m_oldGeomBndryCells.find(cellId);
25734 if(it0 != m_oldGeomBndryCells.end()) m_oldGeomBndryCells.erase(it0);
25735 // only update for low volume difference
25736 const MFloat volDif = fabs(oldVolumes(cellId, 1) - oldVolumes(cellId, 0));
25737 if(volDif > 0.0001 * oldVolumes(cellId, 0)) {
25738 // add entry if volume differs greatly
25739 m_oldGeomBndryCells.insert(make_pair(cellId, -1));
25740 } else {
25741 m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume = oldVolumes(cellId, 0);
25742 }
25743 }
25744 }
25745}
25746
25747
25753template <MInt nDim, class SysEqn>
25755 TRACE();
25756
25757 if(m_noEmbeddedBodies == 0) return;
25758
25759 const MInt noNearBodyState = 5;
25760 MFloatScratchSpace particleFluidVel(m_noEmbeddedBodies, nDim, AT_, "particleFluidVel");
25761 MFloatScratchSpace particleFluidVelDt(m_noEmbeddedBodies, nDim, AT_, "particleFluidVelDt");
25762 MFloatScratchSpace particleFluidVelGrad(m_noEmbeddedBodies, nDim * nDim, AT_, "particleFluidVelGrad");
25763 MFloatScratchSpace particleFluidPressure(m_noEmbeddedBodies, AT_, "particleFluidPressure");
25764 MFloatScratchSpace particleFluidRotation(m_noEmbeddedBodies, nDim, AT_, "particleFluidRotation");
25765 MFloatScratchSpace particleFluidRotationDt(m_noEmbeddedBodies, nDim, AT_, "particleFluidRotationDt");
25766 MFloatScratchSpace particleFluidState(m_noEmbeddedBodies, noNearBodyState, AT_, "particleFluidState");
25767 MFloatScratchSpace bodyRotation(m_noEmbeddedBodies, 3, AT_, "bodyRotation");
25768 for(MInt k = 0; k < m_noEmbeddedBodies; k++) {
25769 getBodyRotation(k, &bodyRotation[3 * k]);
25770 }
25771 MFloat* vel = &(particleFluidVel[0]);
25772 MFloat* velDt = &(particleFluidVelDt[0]);
25773 MFloat* velGradient = &(particleFluidVelGrad[0]);
25774 MFloat* pressure = &(particleFluidPressure[0]);
25775 MFloat* rotation = &(particleFluidRotation[0]);
25776 MFloat* rotationDt = &(particleFluidRotationDt[0]);
25777 MFloat* state = &(particleFluidState[0]);
25778
25779 MIntScratchSpace nearestBodies(m_maxNearestBodies * a_noCells(), AT_, "nearestBodies");
25780 MFloatScratchSpace nearestDist(m_maxNearestBodies * a_noCells(), AT_, "nearestDist");
25781 nearestBodies.fill(-1);
25782 nearestDist.fill(numeric_limits<MFloat>::max());
25783 const MFloat maxDist = 5.0 * m_bodyDiameter[0];
25784 MInt maxBodyCnt = constructDistance(maxDist, nearestBodies, nearestDist);
25785 if(maxBodyCnt > m_maxNearestBodies && domainId() == 0) {
25786 cerr << "constructDistance: maxBodyCnt " << maxBodyCnt << " exceeds m_maxNearestBodies " << m_maxNearestBodies
25787 << ". Retry with higher value." << endl;
25788 }
25789
25790 computeNearBodyFluidVelocity(nearestBodies, nearestDist, vel, velGradient, rotation, vector<MFloat>(), nullptr, state,
25791 pressure, velDt, rotationDt);
25792
25793 const MLong DOF = m_noEmbeddedBodies;
25794 const MLong DOF_TRANS = nDim * m_noEmbeddedBodies;
25795 const MLong DOF_ROT = 3 * m_noEmbeddedBodies;
25796 const MLong DOF_QUAT = 4 * m_noEmbeddedBodies;
25797 const MLong DOF_GRAD = nDim * nDim * m_noEmbeddedBodies;
25798 const MLong DOF_STATE = (MLong)particleFluidState.size();
25799
25800 MString fileName = outputDir() + "bodySamples_00" + to_string(globalTimeStep) + ParallelIo::fileExt();
25801
25802 if(domainId() == 0) {
25803 ParallelIo::size_type count = 0;
25804 ParallelIo parallelIo(fileName, maia::parallel_io::PIO_REPLACE, MPI_COMM_SELF);
25805
25806 parallelIo.defineScalar(maia::parallel_io::PIO_INT, "DOF");
25807 parallelIo.defineScalar(maia::parallel_io::PIO_FLOAT, "bodyDiameter");
25808
25809 count = DOF;
25810 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyTemperature", count);
25811 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "fluidPressure", count);
25812
25813 count = DOF_TRANS;
25814 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyCenter", count);
25815 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyCenterDt1", count);
25816 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyVelocity", count);
25817 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyVelocityDt1", count);
25818 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyAcceleration", count);
25819 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyForce", count);
25820 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "fluidVelocity", count);
25821 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "fluidVelocityDt1", count);
25822
25823 count = DOF_ROT;
25824 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyRotation", count);
25825 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyAngularVelocity", count);
25826 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyAngularVelocityDt1", count);
25827 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyAngularAcceleration", count);
25828 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyTorque", count);
25829 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "fluidRotation", count);
25830 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "fluidRotationDt1", count);
25831
25832 count = DOF_QUAT;
25833 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyQuaternion", count);
25834
25835 count = DOF_GRAD;
25836 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "velocityGradient", count);
25837
25838 count = DOF_STATE;
25839 parallelIo.defineArray(maia::parallel_io::PIO_FLOAT, "bodyState", count);
25840
25841
25842 parallelIo.writeScalar(DOF, "DOF");
25843 parallelIo.writeScalar(m_bodyDiameter[0], "bodyDiameter");
25844
25845 count = DOF;
25846 parallelIo.setOffset(count, 0);
25847 parallelIo.writeArray(m_bodyTemperature, "bodyTemperature");
25848 parallelIo.writeArray(&(pressure[0]), "fluidPressure");
25849
25850 count = DOF_TRANS;
25851 parallelIo.setOffset(count, 0);
25852 parallelIo.writeArray(m_bodyCenter, "bodyCenter");
25853 parallelIo.writeArray(m_bodyCenterDt1, "bodyCenterDt1");
25854 parallelIo.writeArray(&(m_bodyVelocity[0]), "bodyVelocity");
25855 parallelIo.writeArray(&(m_bodyVelocityDt1[0]), "bodyVelocityDt1");
25856 parallelIo.writeArray(&(m_bodyAcceleration[0]), "bodyAcceleration");
25857 parallelIo.writeArray(&(m_bodyForce[0]), "bodyForce");
25858 parallelIo.writeArray(&(vel[0]), "fluidVelocity");
25859 parallelIo.writeArray(&(velDt[0]), "fluidVelocityDt1");
25860
25861 count = DOF_ROT;
25862 parallelIo.setOffset(count, 0);
25863 parallelIo.writeArray(&(bodyRotation[0]), "bodyRotation");
25864 parallelIo.writeArray(&(m_bodyAngularVelocity[0]), "bodyAngularVelocity");
25865 parallelIo.writeArray(&(m_bodyAngularVelocityDt1[0]), "bodyAngularVelocityDt1");
25866 parallelIo.writeArray(&(m_bodyAngularAcceleration[0]), "bodyAngularAcceleration");
25867 parallelIo.writeArray(&(m_bodyTorque[0]), "bodyTorque");
25868 parallelIo.writeArray(&(rotation[0]), "fluidRotation");
25869 parallelIo.writeArray(&(rotationDt[0]), "fluidRotationDt1");
25870
25871 count = DOF_QUAT;
25872 parallelIo.setOffset(count, 0);
25873 parallelIo.writeArray(&(m_bodyQuaternion[0]), "bodyQuaternion");
25874
25875 count = DOF_GRAD;
25876 parallelIo.setOffset(count, 0);
25877 parallelIo.writeArray(&(velGradient[0]), "velocityGradient");
25878
25879 count = DOF_STATE;
25880 parallelIo.setOffset(count, 0);
25881 parallelIo.writeArray(&(state[0]), "bodyState");
25882 }
25883}
25884
25885
25891template <MInt nDim, class SysEqn>
25893 TRACE();
25894
25895 if(m_noPointParticles == 0) return;
25896
25897 MIntScratchSpace partOffsets(noDomains() + 1, AT_, "partOffsets");
25898 partOffsets(0) = 0;
25899 partOffsets(domainId() + 1) = m_noPointParticlesLocal;
25900 MPI_Allgather(&m_noPointParticlesLocal, 1, MPI_INT, &partOffsets[1], 1, MPI_INT, mpiComm(), AT_,
25901 "m_noPointParticlesLocal", "partOffsets[1]");
25902 for(MInt d = 0; d < noDomains(); d++)
25903 partOffsets(d + 1) += partOffsets(d);
25904
25905 MFloatScratchSpace particleFluidPressure(m_noPointParticles, AT_, "particleFluidPressure");
25906 setParticleFluidVelocities(&(particleFluidPressure[0]));
25907
25908 const MLong DOF = m_noPointParticles;
25909 const MLong DOF_LOC = m_noPointParticlesLocal;
25910 const MLong DOF_TRANS = nDim * m_noPointParticles;
25911 const MLong DOF_TRANS_LOC = nDim * m_noPointParticlesLocal;
25912 const MLong DOF_ROT = 3 * m_noPointParticles;
25913 const MLong DOF_ROT_LOC = 3 * m_noPointParticlesLocal;
25914 const MLong DOF_QUAT = 4 * m_noPointParticles;
25915 const MLong DOF_QUAT_LOC = 4 * m_noPointParticlesLocal;
25916 const MLong DOF_GRAD = nDim * nDim * m_noPointParticles;
25917 const MLong DOF_GRAD_LOC = nDim * nDim * m_noPointParticlesLocal;
25918
25919 MString fileName = outputDir() + "partSamples_00" + to_string(globalTimeStep) + ParallelIo::fileExt();
25920
25921 ParallelIo::size_type start = 0;
25922 ParallelIo::size_type count = 0;
25923
25924 using namespace maia::parallel_io;
25925 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
25926
25927 // Creating file header.
25928 parallelIo.defineScalar(PIO_INT, "DOF");
25929
25930 count = DOF;
25931 parallelIo.defineArray(PIO_FLOAT, "partFluidPressure", count);
25932
25933 count = DOF_TRANS;
25934 parallelIo.defineArray(PIO_FLOAT, "partCenter", count);
25935 parallelIo.defineArray(PIO_FLOAT, "partVelocity", count);
25936 parallelIo.defineArray(PIO_FLOAT, "partAcceleration", count);
25937 parallelIo.defineArray(PIO_FLOAT, "partVelocityFluid", count);
25938
25939 count = DOF_ROT;
25940 parallelIo.defineArray(PIO_FLOAT, "partAngularVelocity", count);
25941 parallelIo.defineArray(PIO_FLOAT, "partAngularAcceleration", count);
25942
25943 count = DOF_QUAT;
25944 parallelIo.defineArray(PIO_FLOAT, "partQuaternion", count);
25945
25946 count = DOF_GRAD;
25947 parallelIo.defineArray(PIO_FLOAT, "partVelocityGradientFluid", count);
25948
25949 parallelIo.writeScalar(DOF, "DOF");
25950
25951 start = (ParallelIo::size_type)(partOffsets(domainId()));
25952 count = (ParallelIo::size_type)DOF_LOC;
25953 parallelIo.setOffset(count, start);
25954 parallelIo.writeArray(&(particleFluidPressure[0]), "partFluidPressure");
25955
25956 start = (ParallelIo::size_type)(nDim * partOffsets(domainId()));
25957 count = (ParallelIo::size_type)DOF_TRANS_LOC;
25958 parallelIo.setOffset(count, start);
25959 parallelIo.writeArray(m_particleCoords.data(), "partCenter");
25960 parallelIo.writeArray(m_particleVelocity.data(), "partVelocity");
25961 parallelIo.writeArray(m_particleAcceleration.data(), "partAcceleration");
25962 parallelIo.writeArray(m_particleVelocityFluid.data(), "partVelocityFluid");
25963
25964 start = (ParallelIo::size_type)(3 * partOffsets(domainId()));
25965 count = (ParallelIo::size_type)DOF_ROT_LOC;
25966 parallelIo.setOffset(count, start);
25967 parallelIo.writeArray(m_particleAngularVelocity.data(), "partAngularVelocity");
25968 parallelIo.writeArray(m_particleAngularAcceleration.data(), "partAngularAcceleration");
25969
25970 start = (ParallelIo::size_type)(4 * partOffsets(domainId()));
25971 count = (ParallelIo::size_type)DOF_QUAT_LOC;
25972 parallelIo.setOffset(count, start);
25973 parallelIo.writeArray(m_particleQuaternions.data(), "partQuaternion");
25974
25975 start = (ParallelIo::size_type)(nDim * nDim * partOffsets(domainId()));
25976 count = (ParallelIo::size_type)DOF_GRAD_LOC;
25977 parallelIo.setOffset(count, start);
25978 parallelIo.writeArray(m_particleVelocityGradientFluid.data(), "partVelocityGradientFluid");
25979}
25980
25981
25986template <MInt nDim, class SysEqn>
25988 stringstream time;
25989 time.str("");
25990 MFloat rem = t;
25991 if(rem > 86400.0) {
25992 const MFloat div = floor(rem / 86400.0);
25993 time << ((MInt)div) << " days, ";
25994 rem -= div * 86400.0;
25995 }
25996 if(rem > 3600.0) {
25997 const MFloat div = floor(rem / 3600.0);
25998 time << ((MInt)div) << " hours, ";
25999 rem -= div * 3600.0;
26000 }
26001 if(rem > 60.0) {
26002 const MFloat div = floor(rem / 60.0);
26003 time << ((MInt)div) << " mins, ";
26004 rem -= div * 60.0;
26005 }
26006 time << rem << " secs";
26007 const MString ret = time.str();
26008 return ret;
26009}
26010
26011
26021template <MInt nDim, class SysEqn>
26023 TRACE();
26024
26025 MInt cellId, bndryId, masterCellId;
26026 MInt noSurfaces = a_noSurfaces();
26027 MInt otherId[2] = {1, 0};
26028
26029 for(MInt srfcId = 0; srfcId < noSurfaces; srfcId++) {
26030 for(MInt nghbrId = 0; nghbrId < 2; nghbrId++) {
26031 cellId = a_surfaceNghbrCellId(srfcId, nghbrId);
26032 if(a_bndryId(cellId) < 0) continue;
26033
26034 bndryId = a_bndryId(cellId);
26035 // check whether the cell is a slave cell
26036 if(m_bndryCells->a[bndryId].m_linkedCellId == -1) continue;
26037
26038 masterCellId = m_bndryCells->a[bndryId].m_linkedCellId;
26039
26040 // check whether the other neighbor of the surface is the
26041 // master cell
26042 if(a_surfaceNghbrCellId(srfcId, otherId[nghbrId]) == masterCellId) {
26043 } else {
26044 // shift the Id to the master cell
26045 a_surfaceNghbrCellId(srfcId, nghbrId) = masterCellId;
26046 }
26047 }
26048 }
26049}
26050
26051
26060template <MInt nDim, class SysEqn>
26062 TRACE();
26063
26064 for(MInt cnd = 0; cnd < m_noBndryCandidates; cnd++) {
26065 MInt cellId = m_bndryCandidates[cnd];
26066
26067 MBool isGapCell = false;
26068 if(m_levelSet && m_closeGaps) {
26069 isGapCell = (a_hasProperty(cellId, SolverCell::IsGapCell));
26070 }
26071 MInt startSet = 0;
26072 MInt endSet = 1;
26073 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell)) {
26074 startSet = 1;
26075 endSet = m_noLevelSetsUsedForMb;
26076 }
26077 if(a_hasProperty(cellId, SolverCell::IsInactive) == false) {
26078 MInt minus = true;
26079 for(MInt node = 0; node < m_noCellNodes; node++) {
26080 if(m_candidateNodeValues[IDX_LSSETNODES(cnd, node, 0)] > 0) minus = false;
26081 }
26082 if(minus) {
26083 a_hasProperty(cellId, SolverCell::IsInactive) = true;
26084 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
26085 removeSurfaces(cellId);
26086 }
26087 } else {
26088 MInt plus = true;
26089 for(MInt node = 0; node < m_noCellNodes; node++) {
26090 for(MInt set = startSet; set < endSet; set++)
26091 if(m_candidateNodeValues[IDX_LSSETNODES(cnd, node, set)] <= 0) plus = false;
26092 }
26093 if(plus && c_isLeafCell(cellId)) {
26094 a_hasProperty(cellId, SolverCell::IsInactive) = false;
26095 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = true;
26096 restoreSurfaces(cellId);
26097 }
26098 }
26099 }
26100}
26101
26102
26107template <MInt nDim, class SysEqn>
26109 struct stat buffer;
26110 return (stat(fileName, &buffer) == 0);
26111}
26112
26113
26118template <MInt nDim, class SysEqn>
26120 if(!fileExists(fromName)) {
26121 cerr << "Could not copy file " << fromName << "." << endl;
26122 return -1;
26123 }
26124 if(fileExists(toName)) {
26125 remove(toName);
26126 }
26127 ifstream src(fromName);
26128 ofstream dst(toName);
26129 if(src.good() && dst.good()) {
26130 dst << src.rdbuf();
26131 dst.close();
26132 dst.clear();
26133 src.close();
26134 src.clear();
26135 } else {
26136 cerr << "Could not copy file " << fromName << " (2)." << endl;
26137 return -1;
26138 }
26139 return 0;
26140}
26141
26142
26147template <MInt nDim, class SysEqn>
26149 TRACE();
26150
26151#ifdef DOUBLE_PRECISION_OUTPUT
26152 const char* const dataType = "Float64";
26153#else
26154 const char* const dataType = "Float32";
26155#endif
26156 const char* const iDataType = "Int32";
26157 const char* const uIDataType = "UInt32";
26158
26159 const MString fileName = "stencil_b" + to_string(bndryId) + "_D" + to_string(domainId()) + ".vtp";
26160 const MUint noPoints = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size();
26161 const MUint noLines = noPoints - 1;
26162 const MUint noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
26163 const MUint noRecNghbrs = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size();
26164 for(MInt srfc = 0; srfc < mMin((signed)noRecNghbrs, (signed)noSrfcs); srfc++) {
26165 for(MInt v = 0; v < m_noPVars; v++) {
26166 a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[srfc], v) =
26167 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v];
26168 }
26169 }
26170
26171 ofstream ofl;
26172 ofl.open(fileName.c_str(), ios_base::out | ios_base::trunc);
26173
26174 if(ofl.is_open() && ofl.good()) {
26175 // VTKFile
26176 ofl << "<?xml version=\"1.0\"?>" << endl;
26177 ofl << "<VTKFile type=\"PolyData\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
26178 ofl << "<PolyData>" << endl;
26179
26180 // Dimensions
26181 ofl << "<Piece NumberOfPoints=\"" << noPoints << "\" NumberOfVerts=\"" << 1 << "\" NumberOfLines=\"" << noLines
26182 << "\">" << endl;
26183
26184 // Points
26185 ofl << "<Points>" << endl;
26186 ofl << "<DataArray type=\"" << dataType << "\" NumberOfComponents=\"3\" format=\"ascii\">" << endl;
26187 for(MInt i = 0; i < nDim; i++) {
26188 ofl << a_coordinate(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[noSrfcs], i) << " ";
26189 }
26190 IF_CONSTEXPR(nDim == 2) ofl << "0.0 ";
26191 ofl << endl;
26192 for(MUint srfc = 0; srfc < noSrfcs; srfc++) {
26193 for(MInt i = 0; i < nDim; i++) {
26194 ofl << a_coordinate(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId, i) << " ";
26195 }
26196 IF_CONSTEXPR(nDim == 2) ofl << "0.0 ";
26197 ofl << endl;
26198 }
26199 for(MUint n = noSrfcs + 1; n < noPoints; n++) {
26200 MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
26201 for(MInt i = 0; i < nDim; i++) {
26202 ofl << a_coordinate(nghbrId, i) << " ";
26203 }
26204 IF_CONSTEXPR(nDim == 2) ofl << "0.0 ";
26205 ofl << endl;
26206 }
26207 ofl << "</DataArray>" << endl;
26208 ofl << "</Points>" << endl;
26209
26210 // Verts
26211 ofl << "<Verts>" << endl;
26212 ofl << "<DataArray type=\"" << iDataType << "\" Name=\"connectivity\" format=\"ascii\">" << endl;
26213 ofl << "0" << endl;
26214 ofl << "</DataArray>" << endl;
26215 ofl << "<DataArray type=\"" << uIDataType << "\" Name=\"offsets\" format=\"ascii\">" << endl;
26216 ofl << "1" << endl;
26217 ofl << "</DataArray>" << endl;
26218 ofl << "</Verts>" << endl;
26219
26220 // Lines
26221 ofl << "<Lines>" << endl;
26222 ofl << "<DataArray type=\"" << iDataType << "\" Name=\"connectivity\" format=\"ascii\">" << endl;
26223 for(MUint n = 0; n < noLines; n++) {
26224 ofl << "0 " << n + 1 << " ";
26225 }
26226 ofl << endl;
26227 ofl << "</DataArray>" << endl;
26228 ofl << "<DataArray type=\"" << uIDataType << "\" Name=\"offsets\" format=\"ascii\">" << endl;
26229 for(MUint n = 0; n < noLines; n++) {
26230 ofl << 2 * (n + 1) << " ";
26231 }
26232 ofl << endl;
26233 ofl << "</DataArray>" << endl;
26234 ofl << "</Lines>" << endl;
26235
26236 // CellData
26237 ofl << "<CellData Scalars=\"scalars\">" << endl;
26238
26239 ofl << "<DataArray type=\"" << dataType << "\" Name=\"weights0\" format=\"ascii\">" << endl;
26240 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * noSrfcs] << " ";
26241 for(MUint srfc = 0; srfc < noSrfcs; srfc++)
26242 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * srfc] << " ";
26243 for(MUint n = noSrfcs + 1; n < noPoints; n++)
26244 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n] << " ";
26245 ofl << endl;
26246 ofl << "</DataArray>" << endl;
26247
26248 ofl << "<DataArray type=\"" << dataType << "\" Name=\"weights1\" format=\"ascii\">" << endl;
26249 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * noSrfcs + IPOW2(noSrfcs) - 1] << " ";
26250 for(MUint srfc = 0; srfc < noSrfcs; srfc++)
26251 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * srfc + IPOW2(noSrfcs) - 1] << " ";
26252 for(MUint n = noSrfcs + 1; n < noPoints; n++)
26253 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + IPOW2(noSrfcs) - 1] << " ";
26254 ofl << endl;
26255 ofl << "</DataArray>" << endl;
26256
26257 ofl << "<DataArray type=\"" << dataType << "\" Name=\"weights\" format=\"ascii\">" << endl;
26258 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_imagePointRecConst[noSrfcs] << " ";
26259 for(MUint n = 0; n < noSrfcs; n++)
26260 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_imagePointRecConst[n] << " ";
26261 for(MUint n = noSrfcs + 1; n < noPoints; n++)
26262 ofl << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_imagePointRecConst[n] << " ";
26263 ofl << endl;
26264 ofl << "</DataArray>" << endl;
26265
26266 ofl << "<DataArray type=\"" << dataType << "\" Name=\"u\" format=\"ascii\">" << endl;
26267 ofl << a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[noSrfcs], PV->U) << " ";
26268 for(MUint n = 0; n < noSrfcs; n++)
26269 ofl << a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->U) << " ";
26270 for(MUint n = noSrfcs + 1; n < noPoints; n++)
26271 ofl << a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->U) << " ";
26272 ofl << endl;
26273 ofl << "</DataArray>" << endl;
26274
26275 ofl << "<DataArray type=\"" << dataType << "\" Name=\"v\" format=\"ascii\">" << endl;
26276 ofl << a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[noSrfcs], PV->V) << " ";
26277 for(MUint n = 0; n < noSrfcs; n++)
26278 ofl << a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->V) << " ";
26279 for(MUint n = noSrfcs + 1; n < noPoints; n++)
26280 ofl << a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->V) << " ";
26281 ofl << endl;
26282 ofl << "</DataArray>" << endl;
26283
26284 ofl << "<DataArray type=\"" << iDataType << "\" Name=\"id\" format=\"ascii\">" << endl;
26285 ofl << noSrfcs << " ";
26286 for(MUint n = 0; n < noSrfcs; n++)
26287 ofl << n << " ";
26288 for(MUint n = noSrfcs + 1; n < noPoints; n++)
26289 ofl << n << " ";
26290 ofl << endl;
26291 ofl << "</DataArray>" << endl;
26292 ofl << "</CellData>" << endl;
26293
26294 ofl << "</Piece>" << endl;
26295 ofl << "</PolyData>" << endl;
26296
26297 ofl << "</VTKFile>" << endl;
26298 ofl.close();
26299 ofl.clear();
26300 } else {
26301 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing! (3)" << endl;
26302 }
26303}
26304
26305
26308template <MInt nDim, class SysEqn>
26310#if defined _MB_DEBUG_ || !defined NDEBUG
26311 // needs to be int for mpi
26312 MInt solutionDiverged = 0;
26313 MInt cnt = 0;
26314
26315 for(MInt i = a_noCells(); i--;) {
26316 if(cnt >= 100) break;
26317 if(!a_hasProperty(i, SolverCell::IsActive)) continue;
26318 if(!a_hasProperty(i, SolverCell::IsOnCurrentMGLevel)) continue;
26319 if(a_isHalo(i)) continue;
26320 if(a_isBndryGhostCell(i)) continue;
26321
26322 for(MInt v = 0; v < noVariables(); v++) {
26323 if(!(a_variable(i, v) >= F0 || a_variable(i, v) < F0) || std::isnan(a_variable(i, v))) {
26324 cerr << domainId() << ": LHSB " << c_globalId(i) << " " << a_bndryId(i) << " " << a_level(i) << " " << v << " "
26325 << a_variable(i, v) << " "
26326 << "cells[i].b_properties.to_string()"
26327 << " /v " << a_cellVolume(i) / grid().gridCellVolume(c_level(i)) << " "
26328 << m_cellVolumesDt1[i] / grid().gridCellVolume(c_level(i)) << " "
26329 << a_hasProperty(i, SolverCell::IsSplitCell) << " " << a_hasProperty(i, SolverCell::IsSplitChild) << " "
26330 << a_isPeriodic(i) << " " << a_coordinate(i, 0) << " " << a_coordinate(i, 1) << " "
26331 << a_coordinate(i, mMin(nDim - 1, 2)) << " " << a_levelSetValuesMb(i, 0) << " /v "
26332 << a_cellVolume(i) * a_FcellVolume(i) << " " << m_cellVolumesDt1[i] * a_FcellVolume(i) << endl;
26333 solutionDiverged = 1;
26334 cnt++;
26335 }
26336 }
26337
26338 // setPrimitiveVariables(i);
26339 if(a_cellVolume(i) / grid().gridCellVolume(a_level(i)) > m_fvBndryCnd->m_volumeLimitWall) {
26340 if(a_pvariable(i, maia::fv::PrimitiveVariables<nDim>::RHO) < F0
26341 || a_pvariable(i, maia::fv::PrimitiveVariables<nDim>::P) < F0) {
26342 cerr << domainId() << ": LHSB(2) " << i << " " << c_globalId(i) << " " << a_bndryId(i) << " " << a_level(i)
26343 << " /r " << a_pvariable(i, maia::fv::PrimitiveVariables<nDim>::RHO) << " /p "
26344 << a_pvariable(i, maia::fv::PrimitiveVariables<nDim>::P) << " /v "
26345 << a_cellVolume(i) / grid().gridCellVolume(c_level(i)) << " "
26346 << m_cellVolumesDt1[i] / grid().gridCellVolume(c_level(i)) << " "
26347 << "cells[i].b_properties.to_string()"
26348 << " " << a_hasProperty(i, SolverCell::IsSplitCell) << " " << a_hasProperty(i, SolverCell::IsSplitChild)
26349 << " " << a_isPeriodic(i) << " " << a_coordinate(i, 0) << " " << a_coordinate(i, 1) << " "
26350 << a_coordinate(i, mMin(nDim - 1, 2)) << " /v " << a_cellVolume(i) * a_FcellVolume(i) << " "
26351 << m_cellVolumesDt1[i] * a_FcellVolume(i) << endl;
26352 solutionDiverged = 1;
26353 cnt++;
26354 }
26355 }
26356 }
26357
26358 if(cnt >= 10) cerr << "More than 10 errors. Not reporting any more." << endl;
26359 if(solutionDiverged == 1) {
26360 cerr << "Solution diverged (LHSB) at solver " << domainId() << " " << globalTimeStep << " " << m_RKStep << endl;
26361 // writeVtkErrorFile();
26362 }
26363
26364 MPI_Allreduce(MPI_IN_PLACE, &solutionDiverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
26365 "solutionDiverged");
26366 if(solutionDiverged == 1) {
26367 writeVtkXmlFiles("QOUT", "GEOM", false, true);
26368 MPI_Barrier(mpiComm(), AT_);
26369 mTerm(1, "Solution diverged after LHSB handling.");
26370 }
26371
26372#endif
26373}
26374
26375
26380template <MInt nDim, class SysEqn>
26382 TRACE();
26383
26384 coupling.fill(F0);
26385 const MInt noBCells = m_fvBndryCnd->m_bndryCells->size();
26386 MFloat couplingCheck = F0;
26387
26388 for(MInt bndryId = m_noOuterBndryCells; bndryId < noBCells; bndryId++) {
26389 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
26390
26391 if(a_isHalo(cellId)) continue;
26392 if(a_isBndryGhostCell(cellId)) continue;
26393 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(cellId) > 0) continue;
26394 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
26395
26396 MFloatScratchSpace dummyPvariables(m_bndryCells->a[bndryId].m_noSrfcs, PV->noVariables, AT_, "dummyPvariables");
26397 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
26398 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area < 1e-14) continue;
26399 MFloat rhoSurface = F0;
26400 MFloat pSurface = F0;
26401 for(MInt s = 0; s < mMin((signed)m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size(),
26402 m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs);
26403 s++) {
26404 dummyPvariables(s, PV->P) = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[s]->m_primVars[PV->P];
26405 dummyPvariables(s, PV->RHO) = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[s]->m_primVars[PV->RHO];
26406 }
26407 for(MInt n = 0; n < (signed)m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size(); n++) {
26408 const MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
26409 const MFloat nghbrPvariableP = (n < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs)
26410 ? dummyPvariables(n, PV->P)
26411 : a_pvariable(nghbrId, PV->P);
26412 const MFloat nghbrPvariableRho = (n < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs)
26413 ? dummyPvariables(n, PV->RHO)
26414 : a_pvariable(nghbrId, PV->RHO);
26415 rhoSurface +=
26416 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariableRho;
26417 pSurface += m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariableP;
26418 }
26419 MFloat normal0[3] = {F0, F0, F0};
26420 for(MInt i = 0; i < nDim; i++) {
26421 normal0[i] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
26422 }
26423 MFloat T = sysEqn().temperature_ES(rhoSurface, pSurface);
26424 MFloat mue = SUTHERLANDLAW(T);
26425 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
26426 for(MInt i = 0; i < nDim; i++) {
26427 const MFloat dp0 = -pSurface * normal0[i] * area;
26428 MFloat grad = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[i]];
26429 for(MInt j = 0; j < nDim; j++)
26430 grad += F1B3 * normal0[i] * normal0[j]
26431 * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[j]];
26432 MFloat ds0 = mue * grad * area / sysEqn().m_Re0;
26433 coupling(cellId, i) -= (dp0 + ds0);
26434 couplingCheck -= (dp0 + ds0) * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]];
26435 }
26436 }
26437 }
26438 exchangeDataFV(&coupling[0], nDim, false);
26439
26440 MPI_Allreduce(MPI_IN_PLACE, &couplingCheck, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "couplingCheck");
26441 return couplingCheck;
26442}
26443
26444
26449template <MInt nDim, class SysEqn>
26451 const MFloatScratchSpace& nearestDist,
26452 const MFloat maxDistConstructed) {
26453 TRACE();
26454
26455 MInt noParticlesGlobal = mMax(m_noPointParticles, m_noEmbeddedBodies);
26456 if(noParticlesGlobal == 0) return;
26457 const MFloat DX = (m_bbox[nDim] - m_bbox[0]);
26458 const MFloat epsRef = DX / (POW3(m_UInfinity));
26459 MInt noParticles = mMax(m_noPointParticlesLocal, m_noEmbeddedBodies);
26460 MIntScratchSpace particleOffsets(noDomains() + 1, AT_, "particleOffsets");
26461 particleOffsets(0) = 0;
26462
26463 for(MLong dom = 0; dom < noDomains(); dom++) {
26464 MLong tmpv = (((MLong)noParticlesGlobal) * (dom + 1)) / ((MLong)noDomains());
26465 if(tmpv > numeric_limits<MInt>::max()) mTerm(1, "MInt overflow");
26466 particleOffsets(dom + 1) = (MInt)tmpv;
26467 }
26468 if(m_noEmbeddedBodies > 0) noParticles = particleOffsets(domainId() + 1) - particleOffsets(domainId());
26469
26470 // Memory for computeNearBodyFluidVelocity
26471 MFloatScratchSpace velMem(mMax(1, m_noEmbeddedBodies) * nDim, AT_, "velMem");
26472 MFloatScratchSpace velGradMem(mMax(1, m_noEmbeddedBodies) * nDim * nDim, AT_, "velGradMem");
26473 MFloatScratchSpace particleFluidRotationMem(mMax(1, m_noEmbeddedBodies), nDim, AT_, "particleFluidRotationMem");
26474 MIntScratchSpace skipBodies((m_noPointParticles > 0 ? 1 : m_noEmbeddedBodies), AT_, "skipBodies");
26475 // Memory for Lagrangian point-particles
26476 MFloatScratchSpace pointParticleForceMem(mMax(1, (m_noPointParticles > 0 ? noParticles : -1)), nDim, AT_,
26477 "pointParticleForceMem");
26478 MFloatScratchSpace pointParticleTorqueMem(mMax(1, (m_noPointParticles > 0 ? noParticles : -1)), nDim, AT_,
26479 "pointParticleTorqueMem");
26480 const MFloat distWidth = F1; // scaled with m_bodyDiameter[0]
26481 const MFloat minDistBound = 0.5;
26482 const MFloat maxDistBound = 2.5;
26483 const MFloat correctionBuffer = 1.0;
26484 const MFloat maxAngleBound = 0.5 + correctionBuffer;
26485 const MFloat minAngleBound = -0.5 + correctionBuffer;
26486 const MInt noAngleSetups = (m_noPointParticles > 0 ? 1 : 3);
26487 const MInt noDistSetups = (m_noPointParticles > 0 ? 1 : 3);
26488 struct gradRot {
26489 MFloat grad = F0;
26490 MFloat rotation = F0;
26491 };
26492 for(MInt i = 0; i < noAngleSetups; i++) {
26493 MFloat maxAngle = (maxAngleBound - minAngleBound) / mMax((MFloat)noAngleSetups - 1, F1) * i + minAngleBound;
26494 maxAngle -= correctionBuffer;
26495 if(m_noPointParticles > 0) maxAngle = 1.0;
26496 for(MInt j = 0; j < noDistSetups; j++) {
26497 MFloat* fluidVel = nullptr;
26498 MFloat* fluidVelGrad = nullptr;
26499 MFloat* fluidRotation = nullptr;
26500 MFloat* particleVelocity = nullptr;
26501 MFloat* particleAngularVelocity = nullptr;
26502 MFloat* particleQuaternion = nullptr;
26503 MFloat* particleForce = nullptr;
26504 MFloat* particleTorque = nullptr;
26505 MFloat minDist = F1;
26506 MFloat maxDist = F1;
26507 if(m_noEmbeddedBodies > 0) {
26508 minDist = (maxDistBound - minDistBound) / mMax((MFloat)noDistSetups - 1, F1) * j
26509 + minDistBound; // distances are scaled with body diameter afterwards
26510 maxDist = minDist + distWidth;
26511 if(maxDist * m_bodyDiameter[0] > maxDistConstructed && domainId() == 0)
26512 cerr << "Warning slip statistics: maxDist " << maxDist << " exceeds maxDistConstructed " << maxDistConstructed
26513 << endl;
26514 vector<MFloat> setup = {minDist, maxDist, maxAngle, maxAngle}; // use the same angles for velocity and rotation
26515 fluidVel = &velMem[0];
26516 fluidVelGrad = &velGradMem[0];
26517 fluidRotation = &particleFluidRotationMem[0];
26518 particleVelocity = &m_bodyVelocity[0];
26519 particleAngularVelocity = &m_bodyAngularVelocity[0];
26520 particleQuaternion = &m_bodyQuaternion[0];
26521 particleForce = &m_hydroForce[0];
26522 particleTorque = &m_bodyTorque[0];
26523 computeNearBodyFluidVelocity(nearestBodies, nearestDist, &fluidVel[0], &fluidVelGrad[0], &fluidRotation[0],
26524 setup, &skipBodies[0]);
26525 } else if(m_noPointParticles > 0) {
26526 setParticleFluidVelocities();
26527 fluidVel = &(m_particleVelocityFluid[0]);
26528 fluidVelGrad = &(m_particleVelocityGradientFluid[0]);
26529 particleVelocity = &m_particleVelocity[0];
26530 particleAngularVelocity = &m_particleAngularVelocity[0];
26531 particleQuaternion = &m_particleQuaternions[0];
26532 for(MInt p = 0; p < noParticles; p++) {
26533 const MFloat pmass = F4B3 * PI * m_particleRadii[3 * p] * m_particleRadii[3 * p + 1]
26534 * m_particleRadii[3 * p + 2] * m_densityRatio * m_rhoInfinity;
26535 const MFloat Ix = F1B5 * (POW2(m_particleRadii[3 * p + 1]) + POW2(m_particleRadii[3 * p + 2])) * pmass;
26536 const MFloat Iy = F1B5 * (POW2(m_particleRadii[3 * p + 0]) + POW2(m_particleRadii[3 * p + 2])) * pmass;
26537 const MFloat Iz = F1B5 * (POW2(m_particleRadii[3 * p + 0]) + POW2(m_particleRadii[3 * p + 1])) * pmass;
26538 const MFloat momI[3] = {Ix, Iy, Iz};
26539 for(MInt dim = 0; dim < nDim; dim++) {
26540 MInt id0 = (dim + 1) % 3;
26541 MInt id1 = (id0 + 1) % 3;
26542 pointParticleForceMem[nDim * p + dim] = pmass * m_particleAcceleration[nDim * p + dim];
26543 pointParticleTorqueMem[nDim * p + dim] = momI[dim] * m_particleAngularAcceleration[3 * p + dim];
26544 particleFluidRotationMem[nDim * p + dim] =
26545 F1B2 * (fluidVelGrad[9 * p + 3 * id1 + id0] - fluidVelGrad[9 * p + 3 * id0 + id1]);
26546 }
26547 }
26548 particleForce = &pointParticleForceMem[0];
26549 particleTorque = &pointParticleTorqueMem[0];
26550 fluidRotation = &particleFluidRotationMem[0];
26551 }
26552
26553 // Generate time resolved statistics using particle slip data here
26554 MInt cnt = 0;
26555 MFloat meanPartVel = F0;
26556 MFloat meanPartAngularVel = F0;
26557 MFloat Rep = F0;
26558 MFloat lin_diss = F0;
26559 MFloat FUf = F0;
26560 MFloat FVp = F0;
26561 gradRot nearParticleRot;
26562 gradRot rot_diss;
26563 gradRot meanOmega;
26564 gradRot meanOmegaRel;
26565 gradRot TOmegaF;
26566 MFloat TOmegaP = F0;
26567 for(MInt p = 0; p < noParticles; p++) {
26568 if(m_noEmbeddedBodies > 0) {
26569 p += particleOffsets(domainId());
26570 if(skipBodies[p]) continue;
26571 }
26572 const MFloat refRad =
26573 (m_noPointParticles > 0
26574 ? pow(m_particleRadii[3 * p + 0] * m_particleRadii[3 * p + 1] * m_particleRadii[3 * p + 2], F1B3)
26575 : pow(m_bodyRadii[nDim * p + 0] * m_bodyRadii[nDim * p + 1] * m_bodyRadii[nDim * p + 2], F1B3));
26576 const MFloat diameter = F2 * refRad;
26577 MFloat partVel = F0;
26578 MFloat partAngularVel = F0;
26579 MFloat omegaGrad = F0;
26580 MFloat omegaRotation = F0;
26581 MFloat omegaRelGrad = F0;
26582 MFloat meanOmegaRelRotation = F0;
26583 MFloat vrelAbs = F0;
26584 vector<MFloat> vrel(nDim);
26585 vector<gradRot> omegaRel(nDim);
26586 for(MInt dim = 0; dim < nDim; dim++) {
26587 vrel[dim] = fluidVel[nDim * p + dim] - particleVelocity[nDim * p + dim];
26588 vrelAbs += POW2(vrel[dim]);
26589 lin_diss += particleForce[nDim * p + dim] * vrel[dim];
26590 partVel += POW2(particleVelocity[nDim * p + dim]);
26591 FUf += particleForce[p * nDim + dim] * fluidVel[nDim * p + dim];
26592 FVp += particleForce[p * nDim + dim] * particleVelocity[nDim * p + dim];
26593
26594 // rotationional dynamics
26595 MInt id0 = (dim + 1) % nDim;
26596 MInt id1 = (id0 + 1) % nDim;
26597 nearParticleRot.grad =
26598 F1B2
26599 * (fluidVelGrad[POW2(nDim) * p + nDim * id1 + id0] - fluidVelGrad[POW2(nDim) * p + nDim * id0 + id1]);
26600 nearParticleRot.rotation = fluidRotation[p * nDim + dim];
26601 omegaRel[dim].grad = nearParticleRot.grad - particleAngularVelocity[p * nDim + dim];
26602 omegaRel[dim].rotation = nearParticleRot.rotation - particleAngularVelocity[p * nDim + dim];
26603 rot_diss.grad += particleTorque[nDim * p + dim] * omegaRel[dim].grad;
26604 rot_diss.rotation += particleTorque[nDim * p + dim] * omegaRel[dim].rotation;
26605 omegaGrad += POW2(nearParticleRot.grad);
26606 omegaRotation += POW2(nearParticleRot.rotation);
26607 omegaRelGrad += POW2(omegaRel[dim].grad);
26608 meanOmegaRelRotation += POW2(omegaRel[dim].rotation);
26609 partAngularVel += POW2(particleAngularVelocity[p * nDim + dim]);
26610 TOmegaF.grad += particleTorque[nDim * p + dim] * nearParticleRot.grad;
26611 TOmegaF.rotation += particleTorque[nDim * p + dim] * nearParticleRot.rotation;
26612 TOmegaP += particleTorque[nDim * p + dim] * particleAngularVelocity[p * nDim + dim];
26613 }
26614 meanPartVel += sqrt(partVel);
26615 meanPartAngularVel += sqrt(partAngularVel);
26616 meanOmega.grad += sqrt(omegaGrad);
26617 meanOmega.rotation += sqrt(omegaRotation);
26618 meanOmegaRel.grad += sqrt(omegaRelGrad);
26619 meanOmegaRel.rotation += sqrt(meanOmegaRelRotation);
26620 Rep += sqrt(vrelAbs) * diameter * m_rhoInfinity * sysEqn().m_Re0 / sysEqn().m_muInfinity;
26621 cnt++;
26622 }
26623
26624 vector<MFloat> communicateData = {lin_diss,
26625 FUf,
26626 FVp,
26627 rot_diss.grad,
26628 rot_diss.rotation,
26629 meanPartVel,
26630 Rep,
26631 meanOmega.grad,
26632 meanOmega.rotation,
26633 meanOmegaRel.grad,
26634 meanOmegaRel.rotation,
26635 meanPartAngularVel,
26636 TOmegaF.grad,
26637 TOmegaF.rotation,
26638 TOmegaP};
26639 MPI_Allreduce(MPI_IN_PLACE, &cnt, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cnt");
26640 MPI_Allreduce(MPI_IN_PLACE, communicateData.data(), communicateData.size(), MPI_DOUBLE, MPI_SUM, mpiComm(), AT_,
26641 "MPI_IN_PLACE", "communicateData.data()");
26642 MUint id = 0;
26643 lin_diss = (epsRef / POW3(DX)) * communicateData[id++];
26644 FUf = (epsRef / POW3(DX)) * communicateData[id++];
26645 FVp = (epsRef / POW3(DX)) * communicateData[id++];
26646 rot_diss.grad = (epsRef / POW3(DX)) * communicateData[id++];
26647 rot_diss.rotation = (epsRef / POW3(DX)) * communicateData[id++];
26648 meanPartVel = communicateData[id++] / (m_UInfinity * cnt);
26649 Rep = communicateData[id++];
26650 meanOmega.grad = (DX / (m_UInfinity * cnt)) * communicateData[id++];
26651 meanOmega.rotation = (DX / (m_UInfinity * cnt)) * communicateData[id++];
26652 meanOmegaRel.grad = (DX / (m_UInfinity * cnt)) * communicateData[id++];
26653 meanOmegaRel.rotation = (DX / (m_UInfinity * cnt)) * communicateData[id++];
26654 meanPartAngularVel = (DX / (m_UInfinity * cnt)) * communicateData[id++];
26655 TOmegaF.grad = (epsRef / POW3(DX)) * communicateData[id++];
26656 TOmegaF.rotation = (epsRef / POW3(DX)) * communicateData[id++];
26657 TOmegaP = (epsRef / POW3(DX)) * communicateData[id++];
26658
26659 if(id != communicateData.size()) mTerm(1, AT_, "Communication messed up in slipStatistics;");
26660 if(domainId() == 0) {
26661 ofstream ofl;
26662 ofl.open("slipStatistics_angle_" + to_string(maxAngle) + "_minDist_" + to_string(minDist),
26663 ios_base::out | ios_base::app);
26664 MString seperator = " ";
26665 if(ofl.is_open() && ofl.good()) {
26666 if(!m_restart && m_printHeaderSlip) {
26667 ofl << "# 1:ts 2:time 3:physicalTime "
26668 << " 4:maxAngle 5:minDist 6:maxDist 7:noBodies "
26669 << " 8:Rep(m)"
26670 << " 9:linDiss(m)"
26671 << " 10:rotDiss(G) 11:rotDiss(R)"
26672 << " 12:meanOmega(G) 13:meanOmega(R)"
26673 << " 14:meanOmegaRel(G) 15:meanOmega(R)"
26674 << " 16:meanPartVel 17:meanPartAngularVal "
26675 << " 18:F*U_f(m) 19:F*v_P "
26676 << " 20:T*O_f(G) 21:T*O_f(R) 22:T*O_p "
26677 << " " << endl;
26678 m_printHeaderSlip = false;
26679 }
26680 ofl << globalTimeStep << " " << m_time << " " << m_physicalTime << seperator << " " << maxAngle << " "
26681 << minDist << " " << maxDist << " " << cnt << seperator << " " << Rep / MFloat(cnt) << " " << lin_diss
26682 << " " << rot_diss.grad << " " << rot_diss.rotation << " " << meanOmega.grad << " " << meanOmega.rotation
26683 << " " << meanOmegaRel.grad << " " << meanOmegaRel.rotation << " " << meanPartVel << " "
26684 << meanPartAngularVel << " " << FUf << " " << FVp << " " << TOmegaF.grad << " " << TOmegaF.rotation << " "
26685 << TOmegaP << endl;
26686 ofl.close();
26687 }
26688 }
26689
26690 if(m_saveSlipInterval > 0) {
26691 MInt noTimeStepsSaved = m_slipDataTimeSteps.size();
26692 for(MInt p = 0; p < noParticles; p++) {
26693 MInt globalPId = p + particleOffsets(domainId());
26694 if(i == 0 && j == 0) {
26695 for(MInt dim = 0; dim < nDim; dim++) {
26696 m_slipDataParticleVel[nDim * noParticles * noTimeStepsSaved + p * nDim + dim] =
26697 (!(skipBodies[globalPId] == 1) ? particleVelocity[globalPId * nDim + dim] : -1234);
26698 m_slipDataParticleForce[nDim * noParticles * noTimeStepsSaved + p * nDim + dim] =
26699 (!(skipBodies[globalPId] == 1) ? particleForce[globalPId * nDim + dim] : -1234);
26700 m_slipDataParticlePosition[nDim * noParticles * noTimeStepsSaved + p * nDim + dim] =
26701 m_bodyCenter[globalPId * nDim + dim];
26702 }
26703 for(MInt dim = 0; dim < 4; dim++) {
26704 m_slipDataParticleQuaternion[4 * noParticles * noTimeStepsSaved + p * 4 + dim] =
26705 (!(skipBodies[globalPId] == 1) ? particleQuaternion[globalPId * 4 + dim] : -1234);
26706 }
26707 for(MInt dim = 0; dim < nDim; dim++) {
26708 m_slipDataParticleAngularVel[nDim * noParticles * noTimeStepsSaved + p * nDim + dim] =
26709 (!(skipBodies[globalPId] == 1) ? particleAngularVelocity[globalPId * nDim + dim] : -1234);
26710 m_slipDataParticleTorque[nDim * noParticles * noTimeStepsSaved + p * nDim + dim] =
26711 (!(skipBodies[globalPId] == 1) ? particleTorque[globalPId * nDim + dim] : -1234);
26712 }
26713 }
26714 for(MInt dim = 0; dim < nDim; dim++) {
26715 m_slipDataParticleFluidVel[noTimeStepsSaved * noParticles * nDim * m_noDistSetups * m_noAngleSetups
26716 + p * m_noDistSetups * m_noAngleSetups * nDim + i * nDim * m_noDistSetups
26717 + j * nDim + dim] =
26718 (!(skipBodies[globalPId] == 1) ? fluidVel[globalPId * nDim + dim] : -1234);
26719 m_slipDataParticleFluidVelRot[noTimeStepsSaved * noParticles * nDim * m_noDistSetups * m_noAngleSetups
26720 + p * m_noDistSetups * m_noAngleSetups * nDim + i * nDim * m_noDistSetups
26721 + j * nDim + dim] =
26722 (!(skipBodies[globalPId] == 1) ? fluidRotation[globalPId * nDim + dim] : -1234);
26723 }
26724 for(MInt dim = 0; dim < POW2(nDim); dim++) {
26725 m_slipDataParticleFluidVelGrad[noTimeStepsSaved * noParticles * POW2(nDim) * m_noDistSetups
26726 * m_noAngleSetups
26727 + p * m_noDistSetups * m_noAngleSetups * POW2(nDim)
26728 + i * POW2(nDim) * m_noDistSetups + j * POW2(nDim) + dim] =
26729 (!(skipBodies[globalPId] == 1) ? fluidVelGrad[globalPId * POW2(nDim) + dim] : -1234);
26730 }
26731 }
26732 }
26733 }
26734 }
26735 if(m_saveSlipInterval > 0) {
26736 m_slipDataTimeSteps.push_back(globalTimeStep);
26737 }
26738}
26739
26740
26745template <MInt nDim, class SysEqn>
26747 TRACE();
26748
26749 MInt noTimeStepsSaved = m_slipDataTimeSteps.size();
26750 if(noTimeStepsSaved == 0) return;
26751 MInt noLocalParticles = m_particleOffsets[domainId() + 1] - m_particleOffsets[domainId()];
26752 MInt noGlobalParticles = m_noEmbeddedBodies;
26753 MInt noSetups = m_noAngleSetups * m_noDistSetups;
26754 MFloatScratchSpace outputParticleVel(mMax(1, noLocalParticles) * nDim * noTimeStepsSaved, AT_, "outputParticleVel");
26755 MFloatScratchSpace outputParticleAngularVel(mMax(1, noLocalParticles) * nDim * noTimeStepsSaved, AT_,
26756 "outputParticleAngularVel");
26757 MFloatScratchSpace outputParticleQuaternion(mMax(1, noLocalParticles) * 4 * noTimeStepsSaved, AT_,
26758 "outputParticleQuaternion");
26759 MFloatScratchSpace outputVel(mMax(1, noLocalParticles) * nDim * noTimeStepsSaved * noSetups, AT_, "outputVel");
26760 MFloatScratchSpace outputVelGrad(mMax(1, noLocalParticles) * POW2(nDim) * noTimeStepsSaved * noSetups, AT_,
26761 "outputVelGrad");
26762 MFloatScratchSpace outputParticleFluidRotation(mMax(1, noLocalParticles) * nDim * noTimeStepsSaved * noSetups, AT_,
26763 "outputParticleFluidRotation");
26764 MFloatScratchSpace outputParticleForce(mMax(1, noLocalParticles) * nDim * noTimeStepsSaved, AT_,
26765 "outputParticleForce");
26766 MFloatScratchSpace outputParticleTorque(mMax(1, noLocalParticles) * nDim * noTimeStepsSaved, AT_,
26767 "outputParticleTorque");
26768 MFloatScratchSpace outputParticlePosition(mMax(1, noLocalParticles) * nDim * noTimeStepsSaved, AT_,
26769 "outputParticlePosition");
26770 MIntScratchSpace outputCollision(mMax(1, noLocalParticles) * noTimeStepsSaved, AT_, "outputCollision");
26771 outputParticleVel.fill(F0);
26772 outputParticleAngularVel.fill(F0);
26773 outputParticleQuaternion.fill(-F1);
26774 outputVel.fill(F0);
26775 outputVelGrad.fill(F0);
26776 outputParticleFluidRotation.fill(F0);
26777 outputParticleForce.fill(F0);
26778 outputParticlePosition.fill(F0);
26779 outputParticleTorque.fill(F0);
26780 outputCollision.fill(0);
26781
26782 MIntScratchSpace localToGlobal(mMax(1, noLocalParticles) * noTimeStepsSaved, AT_, "localToGlobal");
26783 MIntScratchSpace particleGlobalId(mMax(1, noLocalParticles), AT_, "particleGlobalId");
26784 for(MInt p = 0; p < noLocalParticles; p++) {
26785 particleGlobalId(p) = p + m_particleOffsets[domainId()];
26786 }
26787 for(MInt ts = 0; ts < noTimeStepsSaved; ts++) {
26788 for(MInt p = 0; p < noLocalParticles; p++) {
26789 localToGlobal(ts * noLocalParticles + p) = ts * noGlobalParticles + particleGlobalId(p);
26790 }
26791 }
26792 MIntScratchSpace dataOffsets(noDomains() + 1, AT_, "dataOffsets");
26793 for(MLong dom = 0; dom < noDomains() + 1; dom++) {
26794 dataOffsets(dom) = noTimeStepsSaved * m_particleOffsets[dom];
26795 }
26796
26797 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticleVel[0], noLocalParticles * noTimeStepsSaved,
26798 noGlobalParticles * noTimeStepsSaved, 1, nDim, noDomains(), domainId(),
26799 mpiComm(), localToGlobal, dataOffsets, outputParticleVel);
26800 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticleAngularVel[0], noLocalParticles * noTimeStepsSaved,
26801 noGlobalParticles * noTimeStepsSaved, 1, nDim, noDomains(), domainId(),
26802 mpiComm(), localToGlobal, dataOffsets, outputParticleAngularVel);
26803 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticleQuaternion[0], noLocalParticles * noTimeStepsSaved,
26804 noGlobalParticles * noTimeStepsSaved, 1, 4, noDomains(), domainId(),
26805 mpiComm(), localToGlobal, dataOffsets, outputParticleQuaternion);
26806 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticleFluidVel[0], noLocalParticles * noTimeStepsSaved,
26807 noGlobalParticles * noTimeStepsSaved, 1, nDim * noSetups, noDomains(),
26808 domainId(), mpiComm(), localToGlobal, dataOffsets, outputVel);
26809 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticleFluidVelGrad[0], noLocalParticles * noTimeStepsSaved,
26810 noGlobalParticles * noTimeStepsSaved, 1, POW2(nDim) * noSetups, noDomains(),
26811 domainId(), mpiComm(), localToGlobal, dataOffsets, outputVelGrad);
26813 &m_slipDataParticleFluidVelRot[0], noLocalParticles * noTimeStepsSaved, noGlobalParticles * noTimeStepsSaved, 1,
26814 nDim * noSetups, noDomains(), domainId(), mpiComm(), localToGlobal, dataOffsets, outputParticleFluidRotation);
26815 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticleForce[0], noLocalParticles * noTimeStepsSaved,
26816 noGlobalParticles * noTimeStepsSaved, 1, nDim, noDomains(), domainId(),
26817 mpiComm(), localToGlobal, dataOffsets, outputParticleForce);
26818 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticlePosition[0], noLocalParticles * noTimeStepsSaved,
26819 noGlobalParticles * noTimeStepsSaved, 1, nDim, noDomains(), domainId(),
26820 mpiComm(), localToGlobal, dataOffsets, outputParticlePosition);
26821 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticleTorque[0], noLocalParticles * noTimeStepsSaved,
26822 noGlobalParticles * noTimeStepsSaved, 1, nDim, noDomains(), domainId(),
26823 mpiComm(), localToGlobal, dataOffsets, outputParticleTorque);
26824 maia::mpi::communicateGlobalyOrderedData(&m_slipDataParticleCollision[0], noLocalParticles * noTimeStepsSaved,
26825 noGlobalParticles * noTimeStepsSaved, 1, 1, noDomains(), domainId(),
26826 mpiComm(), localToGlobal, dataOffsets, outputCollision);
26827
26828 MLongScratchSpace totalOffsetsDOF(noDomains() + 1, AT_, "totalOffsetsDOF_TRANS");
26829 MLongScratchSpace totalOffsetsDOF_TRANS(noDomains() + 1, AT_, "totalOffsetsDOF_TRANS");
26830 MLongScratchSpace totalOffsetsDOF_QUAT(noDomains() + 1, AT_, "totalOffsetsDOF_QUAT");
26831 MLongScratchSpace totalOffsetsDOF_ROT(noDomains() + 1, AT_, "totalOffsetsDOF_ROT");
26832 MLongScratchSpace totalOffsetsDOF_GRAD_Fluid(noDomains() + 1, AT_, "totalOffsetsDOF_GRAD_Fluid");
26833 MLongScratchSpace totalOffsetsDOF_TRANS_Fluid(noDomains() + 1, AT_, "totalOffsetsDOF_TRANS_Fluid");
26834 MLongScratchSpace totalOffsetsDOF_ROT_Fluid(noDomains() + 1, AT_, "totalOffsetsDOF_ROT_Fluid");
26835 for(MLong dom = 0; dom < noDomains() + 1; dom++) {
26836 totalOffsetsDOF(dom) = dataOffsets(dom);
26837 totalOffsetsDOF_QUAT(dom) = dataOffsets(dom) * 4;
26838 totalOffsetsDOF_TRANS(dom) = dataOffsets(dom) * nDim;
26839 totalOffsetsDOF_ROT(dom) = dataOffsets(dom) * nDim;
26840 totalOffsetsDOF_TRANS_Fluid(dom) = dataOffsets(dom) * nDim * noSetups;
26841 totalOffsetsDOF_ROT_Fluid(dom) = dataOffsets(dom) * nDim * noSetups;
26842 totalOffsetsDOF_GRAD_Fluid(dom) = dataOffsets(dom) * POW2(nDim) * noSetups;
26843 }
26844 const ParallelIo::size_type DOF = totalOffsetsDOF(domainId() + 1) - totalOffsetsDOF(domainId());
26845 const ParallelIo::size_type DOF_start = totalOffsetsDOF(domainId());
26846 const ParallelIo::size_type DOF_QUAT = totalOffsetsDOF_QUAT(domainId() + 1) - totalOffsetsDOF_QUAT(domainId());
26847 const ParallelIo::size_type DOF_QUAT_start = totalOffsetsDOF_QUAT(domainId());
26848 const ParallelIo::size_type DOF_TRANS = totalOffsetsDOF_TRANS(domainId() + 1) - totalOffsetsDOF_TRANS(domainId());
26849 const ParallelIo::size_type DOF_TRANS_start = totalOffsetsDOF_TRANS(domainId());
26850 const ParallelIo::size_type DOF_ROT = totalOffsetsDOF_ROT(domainId() + 1) - totalOffsetsDOF_ROT(domainId());
26851 const ParallelIo::size_type DOF_ROT_start = totalOffsetsDOF_ROT(domainId());
26852 const ParallelIo::size_type DOF_TRANS_Fluid =
26853 totalOffsetsDOF_TRANS_Fluid(domainId() + 1) - totalOffsetsDOF_TRANS_Fluid(domainId());
26854 const ParallelIo::size_type DOF_TRANS_Fluid_start = totalOffsetsDOF_TRANS_Fluid(domainId());
26855 const ParallelIo::size_type DOF_ROT_Fluid =
26856 totalOffsetsDOF_ROT_Fluid(domainId() + 1) - totalOffsetsDOF_ROT_Fluid(domainId());
26857 const ParallelIo::size_type DOF_ROT_Fluid_start = totalOffsetsDOF_ROT_Fluid(domainId());
26858 const ParallelIo::size_type DOF_GRAD_Fluid =
26859 totalOffsetsDOF_GRAD_Fluid(domainId() + 1) - totalOffsetsDOF_GRAD_Fluid(domainId());
26860 const ParallelIo::size_type DOF_GRAD_Fluid_start = totalOffsetsDOF_GRAD_Fluid(domainId());
26861 stringstream fn;
26862 fn.clear();
26863 fn << outputDir() << "correlationData_" << to_string(globalTimeStep);
26864 fn << ParallelIo::fileExt();
26865 MString fileName = fn.str();
26866 ParallelIo::size_type start = 0;
26867 ParallelIo::size_type count = 0;
26868 if(ParallelIo::fileExists(fileName, mpiComm()) && domainId() == 0) {
26869 stringstream fn2;
26870 fn2 << outputDir() << "correlationData_" << to_string(globalTimeStep);
26871 fn2 << ParallelIo::fileExt();
26872 time_t now = std::time(0);
26873 tm* ltm = localtime(&now);
26874 fn2 << "_" << ltm->tm_year << "_" << ltm->tm_mon << "_" << ltm->tm_mday << "_" << ltm->tm_hour << "_" << ltm->tm_min
26875 << "_" << ltm->tm_sec;
26876 MString fileName2 = fn2.str();
26877 rename(fileName.c_str(), fileName2.c_str());
26878 }
26879
26880 using namespace maia::parallel_io;
26881 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
26882
26883 count = m_slipDataTimeSteps.size();
26884 parallelIo.defineArray(PIO_INT, "slipDataTimeSteps", count);
26885
26886 count = totalOffsetsDOF(noDomains());
26887 parallelIo.defineArray(PIO_INT, "bodyInCollision", count);
26888
26889 count = totalOffsetsDOF_TRANS(noDomains());
26890 parallelIo.defineArray(PIO_FLOAT, "particleVelocity", count);
26891 parallelIo.defineArray(PIO_FLOAT, "particleForce", count);
26892 parallelIo.defineArray(PIO_FLOAT, "particlePosition", count);
26893
26894 count = totalOffsetsDOF_ROT(noDomains());
26895 parallelIo.defineArray(PIO_FLOAT, "particleAngularVelocity", count);
26896 parallelIo.defineArray(PIO_FLOAT, "particleTorque", count);
26897
26898 count = totalOffsetsDOF_QUAT(noDomains());
26899 parallelIo.defineArray(PIO_FLOAT, "particleQuaternion", count);
26900
26901 count = totalOffsetsDOF_TRANS_Fluid(noDomains());
26902 parallelIo.defineArray(PIO_FLOAT, "particleFluidVel", count);
26903
26904 count = totalOffsetsDOF_ROT_Fluid(noDomains());
26905 parallelIo.defineArray(PIO_FLOAT, "particleFluidVelRot", count);
26906
26907 count = totalOffsetsDOF_GRAD_Fluid(noDomains());
26908 parallelIo.defineArray(PIO_FLOAT, "particleFluidVelGrad", count);
26909
26910 start = 0;
26911 count = m_slipDataTimeSteps.size();
26912 parallelIo.setOffset(count, start);
26913 parallelIo.writeArray(&m_slipDataTimeSteps[0], "slipDataTimeSteps");
26914
26915 start = DOF_start;
26916 count = DOF;
26917 parallelIo.setOffset(count, start);
26918 parallelIo.writeArray(&outputCollision[0], "bodyInCollision");
26919
26920 start = DOF_TRANS_start;
26921 count = DOF_TRANS;
26922 parallelIo.setOffset(count, start);
26923 parallelIo.writeArray(&outputParticleVel[0], "particleVelocity");
26924 parallelIo.writeArray(&outputParticleForce[0], "particleForce");
26925 parallelIo.writeArray(&outputParticlePosition[0], "particlePosition");
26926
26927 start = DOF_ROT_start;
26928 count = DOF_ROT;
26929 parallelIo.setOffset(count, start);
26930 parallelIo.writeArray(&outputParticleAngularVel[0], "particleAngularVelocity");
26931 parallelIo.writeArray(&outputParticleTorque[0], "particleTorque");
26932
26933 start = DOF_QUAT_start;
26934 count = DOF_QUAT;
26935 parallelIo.setOffset(count, start);
26936 parallelIo.writeArray(&outputParticleQuaternion[0], "particleQuaternion");
26937
26938 start = DOF_TRANS_Fluid_start;
26939 count = DOF_TRANS_Fluid;
26940 parallelIo.setOffset(count, start);
26941 parallelIo.writeArray(&outputVel[0], "particleFluidVel");
26942
26943 start = DOF_ROT_Fluid_start;
26944 count = DOF_ROT_Fluid;
26945 parallelIo.setOffset(count, start);
26946 parallelIo.writeArray(&outputParticleFluidRotation[0], "particleFluidVelRot");
26947
26948 start = DOF_GRAD_Fluid_start;
26949 count = DOF_GRAD_Fluid;
26950 parallelIo.setOffset(count, start);
26951 parallelIo.writeArray(&outputVelGrad[0], "particleFluidVelGrad");
26952
26953 m_slipDataTimeSteps.clear();
26954 MInt dim = 1;
26955 for(MInt i = 0; i < dim * m_noSlipDataOutputs; i++) {
26956 m_slipDataParticleCollision[i] = -5;
26957 }
26958 dim = 4;
26959 for(MInt i = 0; i < dim * m_noSlipDataOutputs; i++) {
26960 m_slipDataParticleQuaternion[i] = -F1;
26961 }
26962 dim = nDim;
26963 for(MInt i = 0; i < dim * m_noSlipDataOutputs; i++) {
26964 m_slipDataParticleAngularVel[i] = -F1;
26965 m_slipDataParticleTorque[i] = -F1;
26966 }
26967 for(MInt i = 0; i < dim * m_noSlipDataOutputs * noSetups; i++) {
26968 m_slipDataParticleFluidVelRot[i] = -F1;
26969 }
26970 dim = nDim;
26971 for(MInt i = 0; i < dim * m_noSlipDataOutputs; i++) {
26972 m_slipDataParticleVel[i] = -F1;
26973 m_slipDataParticleForce[i] = -F1;
26974 m_slipDataParticlePosition[i] = -F1;
26975 }
26976 for(MInt i = 0; i < dim * m_noSlipDataOutputs * noSetups; i++) {
26977 m_slipDataParticleFluidVel[i] = -F1;
26978 }
26979 dim = POW2(nDim);
26980 for(MInt i = 0; i < dim * m_noSlipDataOutputs * noSetups; i++) {
26981 m_slipDataParticleFluidVelGrad[i] = -F1;
26982 }
26983}
26984
26985
26990template <MInt nDim, class SysEqn>
26992 TRACE();
26993
26994 ASSERT(m_levelSetMb, "Wrong Function call, only for m_levelSetMb! Otherwise use preTimeStep in fvsolver.cpp");
26995
26996 RECORD_TIMER_START(m_timers[Timers::PreTime]);
26997
26998 reInitSolutionStep(mode);
26999 writeListOfActiveFlowCells();
27000
27001 RECORD_TIMER_STOP(m_timers[Timers::PreTime]);
27002}
27003
27004
27009template <MInt nDim, class SysEqn>
27011 TRACE();
27012
27013 RECORD_TIMER_START(m_timers[Timers::PostTime]);
27014 RECORD_TIMER_START(m_timers[Timers::PostSolu]);
27015
27016 MBool convergence = false;
27017
27019 RECORD_TIMER_START(m_timers[Timers::ResidualMb]);
27020 convergence = this->maxResidual();
27021 RECORD_TIMER_STOP(m_timers[Timers::ResidualMb]);
27022
27024 RECORD_TIMER_START(m_timers[Timers::SurfaceForces]);
27025 this->computeBoundarySurfaceForces();
27026 RECORD_TIMER_STOP(m_timers[Timers::SurfaceForces]);
27027
27031 RECORD_TIMER_START(m_timers[Timers::LevelSetCorr]);
27032 convergence = mMin(convergence, constructGFieldCorrector());
27033 RECORD_TIMER_STOP(m_timers[Timers::LevelSetCorr]);
27034
27035
27036 RECORD_TIMER_STOP(m_timers[Timers::PostSolu]);
27037 RECORD_TIMER_STOP(m_timers[Timers::PostTime]);
27038
27039 return convergence;
27040}
27041
27042
27053template <MInt nDim, class SysEqn>
27055 TRACE();
27056
27057 const MFloat eps0 = 1e-12;
27058 const MInt noChecks = 11;
27059 MFloatScratchSpace cellCheck(a_noCells(), noChecks, AT_, "cellCheck");
27060 cellCheck.fill(std::numeric_limits<MFloat>::max());
27061
27062 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
27063 cellCheck(cellId, 0) = F1;
27064 cellCheck(cellId, 1) = a_cellVolume(cellId);
27065 cellCheck(cellId, 2) = m_cellVolumesDt1[cellId];
27066 cellCheck(cellId, 3) = (MFloat)a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel);
27067 cellCheck(cellId, 4) = (MFloat)a_hasProperty(cellId, SolverCell::IsInactive);
27068 cellCheck(cellId, 5) = a_levelSetValuesMb(cellId, 0);
27069 cellCheck(cellId, 6) = (MFloat)a_isGapCell(cellId);
27070 cellCheck(cellId, 7) = (MFloat)a_wasGapCell(cellId);
27071 cellCheck(cellId, 8) = (MFloat)a_hasProperty(cellId, SolverCell::NearWall);
27072 cellCheck(cellId, 9) = (MFloat)a_bndryId(cellId) > -1 ? 1 : -1;
27073 cellCheck(cellId, 10) = (MFloat)a_hasProperty(cellId, SolverCell::WasInactive);
27074 }
27075
27076 exchangeData(&cellCheck(0), noChecks);
27077
27078 for(MInt cellId = noInternalCells(); cellId < a_noCells(); cellId++) {
27079 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
27080 if(a_isBndryGhostCell(cellId)) continue;
27081 // Azimuthal periodic window/halo cells are not identical in the sense of the cartesian grid!
27082 if(grid().azimuthalPeriodicity() && a_isPeriodic(cellId)) continue;
27083
27084 ASSERT((MInt)cellCheck(cellId, 0) == 1, to_string(a_isHalo(cellId)));
27085
27086 if(mode == 2) {
27087 if((MInt)cellCheck(cellId, 6) != a_isGapCell(cellId)) {
27088 cerr << domainId() << ": ERR7 checkHaloCells " << globalTimeStep << " " << c_globalId(cellId) << endl;
27089 }
27090
27091 if((MInt)cellCheck(cellId, 7) != a_wasGapCell(cellId)) {
27092 cerr << domainId() << ": ERR7 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27093 }
27094 continue;
27095 }
27096
27097
27098 if(fabs(cellCheck(cellId, 1) - a_cellVolume(cellId)) > eps0) {
27099 cerr << domainId() << ": ERR1 checkHaloCells " << cellId << " " << c_globalId(cellId) << " "
27100 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild)
27101 << " " << a_isHalo(cellId) << " " << a_isWindow(cellId) << " " << a_level(cellId) << " "
27102 << a_cellVolume(cellId) << " " << cellCheck(cellId, 1) << " "
27103 << (cellCheck(cellId, 1) - grid().gridCellVolume(a_level(cellId))) / grid().gridCellVolume(a_level(cellId))
27104 << " "
27105 << (a_cellVolume(cellId) - grid().gridCellVolume(a_level(cellId))) / grid().gridCellVolume(a_level(cellId))
27106 << " " << fabs(cellCheck(cellId, 1) - a_cellVolume(cellId)) / grid().gridCellVolume(a_level(cellId)) << endl;
27107 }
27108 if(fabs(cellCheck(cellId, 2) - m_cellVolumesDt1[cellId]) > eps0 && mode != 3) {
27109 cerr << domainId() << ": ERR2 checkHaloCells " << globalTimeStep << " " << c_globalId(cellId) << " "
27110 << m_cellVolumesDt1[cellId] << " " << cellCheck(cellId, 2) << " " << c_isLeafCell(cellId) << endl;
27111 }
27112 if((MInt)cellCheck(cellId, 3) != a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
27113 cerr << domainId() << ": ERR3 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27114 }
27115
27116 if(fabs(cellCheck(cellId, 5) - a_levelSetValuesMb(cellId, 0)) > eps0) {
27117 cerr << domainId() << ": ERR5 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27118 }
27119
27120 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
27121
27122 if(mode != 1) {
27123 if((MInt)cellCheck(cellId, 4) != a_hasProperty(cellId, SolverCell::IsInactive)) {
27124 cerr << domainId() << ": ERR4 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27125 }
27126 }
27127
27128 if((MInt)cellCheck(cellId, 6) != a_isGapCell(cellId)) {
27129 cerr << domainId() << ": ERR6 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27130 }
27131
27132 if((MInt)cellCheck(cellId, 7) != a_wasGapCell(cellId)) {
27133 cerr << domainId() << ": ERR7 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27134 }
27135 if((MInt)cellCheck(cellId, 8) != a_hasProperty(cellId, SolverCell::NearWall)) {
27136 cerr << domainId() << ": ERR8 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27137 }
27138 const MInt isbndry = a_bndryId(cellId) > -1 ? 1 : -1;
27139 if((MInt)cellCheck(cellId, 9) != isbndry) {
27140 cerr << domainId() << ": ERR9 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27141 }
27142
27143 if(mode != 3) {
27144 if((MInt)cellCheck(cellId, 10) != a_hasProperty(cellId, SolverCell::WasInactive)) {
27145 cerr << domainId() << ": ERR10 checkHaloCells " << globalTimeStep << " " << cellId << endl;
27146 }
27147 }
27148 }
27149}
27150
27151
27160template <MInt nDim, class SysEqn>
27162 TRACE();
27163
27164 ASSERT(m_gapInitMethod == 0, "");
27165 if(!m_closeGaps) return;
27166
27167 exchangeGapInfo();
27168
27169 ASSERT(!m_gapOpened, "");
27170 ASSERT(m_levelSet, "");
27171
27172 // set the m_gapOpened-property and initialize emerging-Gap-Cells!
27173 const MFloat eps = sqrt(nDim) * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
27174
27175 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27176 if(a_isBndryGhostCell(cellId)) continue;
27177 // if ( a_isHalo( cellId ) ) continue;
27178 if(!a_hasProperty(cellId, SolverCell::WasGapCell)) continue;
27179 if(a_level(cellId) != maxRefinementLevel()) continue;
27180 if(!a_hasProperty(cellId, SolverCell::WasInactive)) continue;
27181 if(a_hasProperty(cellId, SolverCell::IsGapCell)) continue;
27182
27183 if(a_levelSetValuesMb(cellId, 0) < -eps) continue;
27184
27185 // for all cells with: WasGapCell, WasInactive, !IsGapCell and small ls-values!
27186 // would be more accurate to use the cornerLs-Values instead of eps-approach!
27187
27188 // set variables to initial value, which will be corrected later in initEmergingGapCells()!
27189 a_variable(cellId, CV->RHO) = m_rhoInfinity;
27190 a_variable(cellId, CV->RHO_E) = m_rhoEInfinity;
27191 a_variable(cellId, CV->RHO_VV[0]) = F0;
27192 a_variable(cellId, CV->RHO_VV[1]) = F0;
27193 IF_CONSTEXPR(nDim == 3) a_variable(cellId, CV->RHO_VV[2]) = F0;
27194 a_pvariable(cellId, PV->RHO) = m_rhoInfinity;
27195 a_pvariable(cellId, PV->U) = F0;
27196 a_pvariable(cellId, PV->V) = F0;
27197 IF_CONSTEXPR(nDim == 3) a_pvariable(cellId, PV->W) = F0;
27198 a_pvariable(cellId, PV->P) = m_PInfinity;
27199
27200 cerr << domainId() << ": old gap cell activated at timeStep " << globalTimeStep << ": cellId " << cellId << " "
27201 << c_globalId(cellId) << " lvsVal: " << a_levelSetValuesMb(cellId, 0)
27202 << " inactive: " << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
27203
27204 m_gapOpened = true;
27205 }
27206
27207 MInt gapOpened = (MInt)m_gapOpened;
27208 MPI_Allreduce(MPI_IN_PLACE, &gapOpened, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "gapOpened");
27209 m_gapOpened = (MBool)gapOpened;
27210
27211 if(domainId() == 0 && m_gapOpened) {
27212 cerr << "Gap Opening Initialized at timestep " << globalTimeStep << endl;
27213 }
27214}
27215
27216
27223template <MInt nDim, class SysEqn>
27225 TRACE();
27226
27227 ASSERT(m_levelSet && m_closeGaps, "");
27228 ASSERT(m_gapInitMethod > 0, "");
27229
27230 m_gapCellExchangeInit = false;
27231
27232 m_gapCellId.clear();
27233 m_gapCellId.resize(a_noCells());
27234 for(MInt i = 0; i < a_noCells(); i++)
27235 m_gapCellId[i] = -1;
27236
27237 // return early if no gapCells were found!
27238 if(m_noneGapRegions) return;
27239
27240 ASSERT(m_initGapCell, "");
27241
27242 // set gapCellId
27243 for(MUint it = 0; it < m_gapCells.size(); it++) {
27244 const MInt cellId = m_gapCells[it].cellId;
27245 m_gapCellId[cellId] = (MInt)it;
27246 }
27247
27248 // check if any gap opens
27249 MBool anyGapOpening = false;
27250 for(MInt region = 0; region < m_noGapRegions; region++) {
27251 if(m_gapState[region] == 2) anyGapOpening = true;
27252 }
27253
27254 // NOTE: split-childs are not yet added as gapCells as a region cann't be found for them immedeatly.
27255 // However, splitcells are still added and used for the interpolation!
27256 // Split-childs will be handeled at the end!
27257
27258 // b) categorise Gap-Cells
27259
27260 // 1) during initGapClosure:
27261 // Types:
27262 // 2 - body-shadowed gap-Cell :
27263 // 3 - gap-shadowed internalCell : delete surfaces
27264 // 4 - gap-shadowed Bndry-Cell : delete surface, remove from oldBndry-Cell-List, set gridVolume
27265 // 5 - Bndry-Cell : correct Bndry-Velocity, and cellVolumes
27266 // 6 - emerging bndryCell : correct Bndry-Velocity, and cellVolumes
27267 // 7 - new Gap-BndryCell : correct Bndry-Velocity, and cellVolumes
27268 // 8 - internal-Cell :
27269 // 9 - emerging internal Cell :
27270 // 99 - new body-bndry-Cell :
27271
27272 // NOTE: for now mass during initGapClosure is lost!
27273 // This mass-loss needs to be approximated!
27274 // Or alternatevly the mass can be redistributed towards sourrounding cells
27275
27276 MInt outInfo1 = 1;
27277 MInt outInfo2 = 1;
27278 for(MInt region = 0; region < m_noGapRegions; region++) {
27279 if(m_gapState[region] != -2) continue;
27280 for(MUint it = 0; it < m_gapCells.size(); it++) {
27281 MInt regionId = m_gapCells[it].region;
27282 if(regionId != region) continue;
27283 MInt cellId = m_gapCells[it].cellId;
27284
27285 // all Gap-Cells in that region (including Halo-Cells!)
27286 // if(a_level(cellId) != maxRefinementLevel()) continue;
27287 if(a_level(cellId) < m_lsCutCellMinLevel || !c_isLeafCell(cellId)) continue;
27288
27289 ASSERT(!a_wasGapCell(cellId), "");
27290 ASSERT(m_gapCells[it].status == 0, "");
27291 MInt flowCornerBodySet = 0;
27292 MInt flowCorner = 0;
27293 MInt bodyId = a_associatedBodyIds(cellId, 0);
27294 MInt bodySet = m_bodyToSetTable[bodyId];
27295
27296 MInt cndId = m_bndryCandidateIds[cellId];
27297
27298
27299 if(cndId < 0) {
27300 if(a_levelSetValuesMb(cellId, bodySet) > F0) {
27301 flowCornerBodySet = m_noCellNodes;
27302 } else {
27303 flowCornerBodySet = 0;
27304 }
27305 if(a_levelSetValuesMb(cellId, 0) > F0) {
27306 flowCorner = m_noCellNodes;
27307 } else {
27308 flowCorner = 0;
27309 }
27310 } else {
27311 for(MInt node = 0; node < m_noCellNodes; node++) {
27312 if(m_candidateNodeValues[IDX_LSSETNODES(cndId, node, bodySet)] > F0) flowCornerBodySet++;
27313 if(m_candidateNodeValues[IDX_LSSETNODES(cndId, node, 0)] > F0) flowCorner++;
27314 }
27315 }
27316
27317
27318 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
27319 // TODO labels:FVMB use a_isBndryCell and IsInactive to differe here!
27320 // check if flowCorner are even nevessary!
27321 if(flowCorner == m_noCellNodes) {
27322 cerr << "UnExpected GapCell (1) at initGapClosure! " << c_globalId(cellId) << " " << a_isBndryCell(cellId)
27323 << " " << a_hasProperty(cellId, SolverCell::IsInactive) << " " << cndId << endl;
27324 } else if(flowCorner > 0 && flowCorner < m_noCellNodes) {
27325 // new bndry-Cell (was body-shadowed before)
27326 m_gapCells[it].status = 99;
27327 } else { // flowCorner == 0
27328 // body-shadowed Gap-Cell
27329 m_gapCells[it].status = 2;
27330 }
27331
27332 } else { // wasActive
27333 if(flowCorner == m_noCellNodes) {
27334 auto it1 = m_oldBndryCells.find(cellId);
27335 if(it1 != m_oldBndryCells.end()) {
27336 // emerging internal-Cell due to body-movement
27337 m_gapCells[it].status = 9;
27338 } else {
27339 // internal-Gap-Cell
27340 m_gapCells[it].status = 8;
27341 }
27342
27343
27344 } else if(flowCorner > 0 && flowCorner < m_noCellNodes) {
27345 if(flowCornerBodySet == 0) {
27346 // emerging-Bndry-Cell
27347 m_gapCells[it].status = 6;
27348 } else if(flowCornerBodySet == m_noCellNodes) {
27349 // new Gap-Bndry-Cell
27350 m_gapCells[it].status = 7;
27351 } else { // flowCornerBodySet > 0 && flowCornerBodySet < m_noCellNodes
27352 // bndry-Cell
27353 m_gapCells[it].status = 5;
27354 }
27355
27356
27357 } else { // flowCorner == 0 (wasActive but will be inactive!)
27358
27359 auto it1 = m_oldBndryCells.find(cellId);
27360 if(it1 != m_oldBndryCells.end()) {
27361 // gap-Shadowed Bndry-Cell
27362 m_gapCells[it].status = 4;
27363 if(outInfo2) {
27364 cerr << "--> Deleting oldBndryCells shadowed by the Gap in region " << regionId << endl;
27365 outInfo2 = 0;
27366 }
27367 removeSurfaces(cellId);
27368 m_oldBndryCells.erase(it1);
27369 a_cellVolume(cellId) = grid().gridCellVolume(a_level(cellId));
27370 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
27371 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId));
27372 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = grid().gridCellVolume(a_level(cellId));
27373 for(MInt v = 0; v < m_noFVars; v++) {
27374 a_rightHandSide(cellId, v) = F0;
27375 m_rhs0[cellId][v] = F0;
27376 }
27377
27378 } else {
27379 // gap-Shadowed InternalCell
27380 m_gapCells[it].status = 3;
27381 if(outInfo1) {
27382 cerr << "--> Deleting Gap-Shadowed Cells in region " << regionId << endl;
27383 outInfo1 = 0;
27384 }
27385 removeSurfaces(cellId);
27386 ASSERT(fabs(grid().gridCellVolume(a_level(cellId)) - a_cellVolume(cellId)) < 0.00001, "");
27387 for(MInt v = 0; v < m_noFVars; v++) {
27388 a_rightHandSide(cellId, v) = F0;
27389 m_rhs0[cellId][v] = F0;
27390 }
27391 }
27392 }
27393 }
27394 }
27395 }
27396
27397 // 2) during gap-Shrinking
27398 // 30 : internal gap-Cell
27399 // 31 : gap or body-shadowed gapCell
27400 // 32 : new gap Bndry-Cell which used to be inactive (with lost gap-status)
27401 // 33 : new gap Bndry-Cell which used to be inactive (also wasGapCell)
27402 // 34 : gap-Bndry-Cell was bndryCell before
27403 // 35 : gap-Bndry-Cell was internal Cell before
27404 for(MInt region = 0; region < m_noGapRegions; region++) {
27405 if(m_gapState[region] != -1) continue;
27406 for(MUint it = 0; it < m_gapCells.size(); it++) {
27407 const MInt regionId = m_gapCells[it].region;
27408 if(regionId != region) continue;
27409 const MInt cellId = m_gapCells[it].cellId;
27410 const MInt status = m_gapCells[it].status;
27411
27412 if(status == 1) {
27413 // only inactive Cells may loose their gap-property during gap-shrinking!
27414 /*
27415 MInt flowCorner = 0;
27416 MInt cndId = m_bndryCandidateIds[ cellId ];
27417 if(cndId < 0) {
27418 if(a_levelSetValuesMb(cellId, 0) > F0) {
27419 flowCorner = m_noCellNodes;
27420 } else {
27421 flowCorner = 0;
27422 }
27423 } else {
27424 for ( MInt node = 0; node < m_noCellNodes; node++ ) {
27425 if(m_candidateNodeValues[ IDX_LSSETNODES(cndId, node, 0) ] > F0) flowCorner++;
27426 }
27427 }
27428 if(flowCorner > 0) {
27429 cerr << "CAUTION: Gap-Cell-Loss during shrinking " << c_globalId(cellId) << " "
27430 << a_levelSetValuesMb(cellId, 0) << " " << -eps << " "
27431 << a_hasProperty(cellId, SolverCell::WasInactive) << endl;
27432 }
27433 */
27434 } else {
27435 // is GapCell and might be gap-Cell before
27436
27437 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
27438 if(a_isBndryGhostCell(cellId)) continue;
27439
27440 // if(a_level(cellId) != maxRefinementLevel()) continue;
27441 if(a_level(cellId) < m_lsCutCellMinLevel || !c_isLeafCell(cellId)) continue;
27442
27443 MInt flowCornerBodySet = 0;
27444 MInt flowCorner = 0;
27445 MInt bodyId = a_associatedBodyIds(cellId, 0);
27446 MInt bodySet = m_bodyToSetTable[bodyId];
27447
27448 MInt cndId = m_bndryCandidateIds[cellId];
27449
27450
27451 if(cndId < 0) {
27452 if(a_levelSetValuesMb(cellId, bodySet) > F0) {
27453 flowCornerBodySet = m_noCellNodes;
27454 } else {
27455 flowCornerBodySet = 0;
27456 }
27457 if(a_levelSetValuesMb(cellId, 0) > F0) {
27458 flowCorner = m_noCellNodes;
27459 } else {
27460 flowCorner = 0;
27461 }
27462 } else {
27463 for(MInt node = 0; node < m_noCellNodes; node++) {
27464 if(m_candidateNodeValues[IDX_LSSETNODES(cndId, node, bodySet)] > F0) flowCornerBodySet++;
27465 if(m_candidateNodeValues[IDX_LSSETNODES(cndId, node, 0)] > F0) flowCorner++;
27466 }
27467 }
27468
27469 if(flowCorner == m_noCellNodes) {
27470 // internal Gap-Cell
27471 m_gapCells[it].status = 30;
27472
27473
27474 } else if(flowCorner == 0) {
27475 // gap-or Body-shadowed Gap-Cell
27476 m_gapCells[it].status = 31;
27477
27478 } else { // Bndry-Cell
27479
27480 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
27481 // new Bndry-Cell
27482
27483 if(flowCornerBodySet == 8) {
27484 // new Gap-Bndry-Cell
27485
27486 } else {
27487 // new body-Bndry-Cell
27488 }
27489 } else {
27490 // old Bndry-Cell
27491 }
27492 }
27493 }
27494 }
27495 }
27496
27497 // 3) during gap-Widening
27498 // Types:
27499 // 10 : internal gap-Cell
27500 // 11 : gap or body-shadowed gapCell
27501 // 12 : new gap Bndry-Cell which used to be inactive (with lost gap-status)
27502 // 13 : new gap Bndry-Cell which used to be inactive (also wasGapCell)
27503 // 14 : gap-Bndry-Cell was bndryCell before
27504 // 15 : gap-Bndry-Cell was internal Cell before
27505 // 16 : new small gap Bndry-Cell with wasinactive neighbors (-> can't be linked easyly!)
27506
27507 vector<MInt> partialGapOpened;
27508 vector<MInt> fullyGapOpened;
27509 vector<MInt> fullyGapBndry;
27510 for(MInt region = 0; region < m_noGapRegions; region++) {
27511 partialGapOpened.push_back(0);
27512 fullyGapOpened.push_back(0);
27513 fullyGapBndry.push_back(0);
27514 if(m_gapState[region] != 3) continue;
27515 for(MUint it = 0; it < m_gapCells.size(); it++) {
27516 MInt regionId = m_gapCells[it].region;
27517 if(regionId != region) continue;
27518 MInt cellId = m_gapCells[it].cellId;
27519
27520 MInt status = m_gapCells[it].status;
27521
27522 if(status == 0) {
27523 /*
27524 //only inactive Cells may gain gap-property during gap-widening!
27525 MInt flowCorner = 0;
27526 MInt cndId = m_bndryCandidateIds[ cellId ];
27527 if(cndId < 0) {
27528 if(a_levelSetValuesMb(cellId, 0) > F0) {
27529 flowCorner = m_noCellNodes;
27530 } else {
27531 flowCorner = 0;
27532 }
27533 } else {
27534 for ( MInt node = 0; node < m_noCellNodes; node++ ) {
27535 if(m_candidateNodeValues[ IDX_LSSETNODES(cndId, node, 0) ] > F0) flowCorner++;
27536 }
27537 }
27538 if(flowCorner > 0) {
27539 cerr << "CAUTION: Gap-Cell-Gain during widening " << c_globalId(cellId) << " "
27540 << a_levelSetValuesMb(cellId, 0) << " " << -eps << " "
27541 << a_hasProperty(cellId, SolverCell::WasInactive) << endl;
27542 }
27543
27544 */
27545 } else {
27546 // a cell which lost its Gap-status or a remains a gapCell
27547 // now-check if it will be:
27548 // - an internalCell (only if the cell !wasInactive before),
27549 // - an inactive Cell (so still shadowed by a body)
27550 // - an active bndryCell
27551 // (then the Cell needs to be initialised by Cell-linking or its former bndryCell-status)
27552
27553 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
27554 if(a_isBndryGhostCell(cellId)) continue;
27555 // if(a_level(cellId) != maxRefinementLevel() ) continue;
27556 if(a_level(cellId) < m_lsCutCellMinLevel || !c_isLeafCell(cellId)) continue;
27557
27558 MInt flowCornerBodySet = 0;
27559 MInt flowCorner = 0;
27560 MInt bodyId = a_associatedBodyIds(cellId, 0);
27561 MInt bodySet = m_bodyToSetTable[bodyId];
27562
27563 MInt cndId = m_bndryCandidateIds[cellId];
27564
27565
27566 if(cndId < 0) {
27567 if(a_levelSetValuesMb(cellId, bodySet) > F0) {
27568 flowCornerBodySet = m_noCellNodes;
27569 } else {
27570 flowCornerBodySet = 0;
27571 }
27572 if(a_levelSetValuesMb(cellId, 0) > F0) {
27573 flowCorner = m_noCellNodes;
27574 } else {
27575 flowCorner = 0;
27576 }
27577 } else {
27578 for(MInt node = 0; node < m_noCellNodes; node++) {
27579 if(m_candidateNodeValues[IDX_LSSETNODES(cndId, node, bodySet)] > F0) flowCornerBodySet++;
27580 if(m_candidateNodeValues[IDX_LSSETNODES(cndId, node, 0)] > F0) flowCorner++;
27581 }
27582 }
27583
27584
27585 if(flowCorner == m_noCellNodes) {
27586 // internal gap-Cell
27587
27588
27589 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
27590 // if the call was inactive before and is suddenly a completely emergerd cell,
27591 // fullyGapOpening has occoured, this is only possible
27592 // if the cell looses its gap-Status!
27593 // ASSERT(status == 1, "");
27594 if(status != 1) {
27595 cerr << "Incorrect status " << c_globalId(cellId) << a_hasProperty(cellId, SolverCell::WasInactive) << " "
27596 << a_hasProperty(cellId, SolverCell::IsInactive) << " " << a_isGapCell(cellId) << " "
27597 << a_wasGapCell(cellId) << endl;
27598 }
27599 m_gapCells[it].status = 21;
27600 fullyGapOpened[region]++;
27601
27602 } else {
27603 // the cell was an active cell before!
27604 m_gapCells[it].status = 10;
27605 }
27606
27607
27608 } else if(flowCorner == 0) {
27609 // the cell should be inactive
27610 // but can be either body or gap-shadowed
27611 ASSERT(a_hasProperty(cellId, SolverCell::IsInactive), "");
27612 m_gapCells[it].status = 11;
27613 if(status == 1) ASSERT(flowCornerBodySet == 0, "");
27614
27615 } else {
27616 // a gap-bndry-Cell which has lost its Gap-status or is still a Gap-Cell
27617
27618 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
27619 // a gap or body-shadowed Cell has become a new gap-bndry-Cell
27620 // needs to be linked to a master-Cell and thus initialised!
27621 if(status == 1) {
27622 m_gapCells[it].status = 22;
27623 fullyGapBndry[region]++;
27624 } else { // status -1
27625 m_gapCells[it].status = 13;
27626
27627 // check for partial gap-opening:
27628 MInt masterId = -1;
27629 MFloat maxVolActive = F0;
27630 MInt noInternalNghbrs = 0;
27631 const MInt rootId = cellId;
27632 for(MInt dir = 0; dir < m_noDirs; dir++) {
27633 if(!checkNeighborActive(rootId, dir) || a_hasNeighbor(rootId, dir) == 0) continue;
27634 const MInt nghbrId = c_neighborId(rootId, dir);
27635 if(nghbrId < 0) continue;
27636 if(!a_isHalo(nghbrId)) noInternalNghbrs++;
27637 if(a_hasProperty(nghbrId, SolverCell::WasInactive)) continue;
27638 if(a_hasProperty(nghbrId, SolverCell::IsSplitCell)) continue;
27639 if(a_hasProperty(nghbrId, SolverCell::IsSplitChild)) continue;
27640 if(a_cellVolume(nghbrId) > maxVolActive) {
27641 masterId = nghbrId;
27642 maxVolActive = a_cellVolume(nghbrId);
27643 }
27644 }
27645 if(masterId > -1) continue;
27646 if(a_isHalo(cellId) && noInternalNghbrs == 0) continue;
27647 if(a_isHalo(cellId) && a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
27648
27649 m_gapCells[it].status = 16;
27650 partialGapOpened[region]++;
27651 }
27652
27653 } else {
27654 // check if it used to be bndry-Cell before
27655 auto it1 = m_oldBndryCells.find(cellId);
27656 if(it1 != m_oldBndryCells.end()) {
27657 // cell was also a bndry-Cell before
27658 m_gapCells[it].status = 14;
27659 } else {
27660 // former internal Cell
27661 m_gapCells[it].status = 15;
27662 }
27663 }
27664 }
27665 }
27666 }
27667 }
27668
27669 // partial gap-opening occours if
27670 // a) a new bndry-Cell emerges which does not have an active neighbor!
27671
27672 MPI_Allreduce(MPI_IN_PLACE, &partialGapOpened[0], m_noGapRegions, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
27673 "partialGapOpened[0]");
27674 MPI_Allreduce(MPI_IN_PLACE, &fullyGapOpened[0], m_noGapRegions, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
27675 "fullyGapOpened[0]");
27676 MPI_Allreduce(MPI_IN_PLACE, &fullyGapBndry[0], m_noGapRegions, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
27677 "fullyGapBndry[0]");
27678
27679 MBool anyPartialGapOpened = false;
27680 for(MInt region = 0; region < m_noGapRegions; region++) {
27681 if(partialGapOpened[region] > 0) {
27682 anyPartialGapOpened = true;
27683 break;
27684 }
27685 }
27686
27687 MBool anyFullyGapOpened = false;
27688 for(MInt region = 0; region < m_noGapRegions; region++) {
27689 if(fullyGapOpened[region] > 0) {
27690 anyFullyGapOpened = true;
27691 break;
27692 }
27693 }
27694
27695 if(anyPartialGapOpened) {
27696 for(MInt region = 0; region < m_noGapRegions; region++) {
27697 if(domainId() == 0 && partialGapOpened[region] && !fullyGapOpened[region]) {
27698 cerr << "Partial Gap Opening at region " << region << " with " << partialGapOpened[region] << " Cells." << endl;
27699 }
27700 }
27701
27702 initGapCellExchange();
27703
27704 for(MInt region = 0; region < m_noGapRegions; region++) {
27705 if(!partialGapOpened[region]) continue;
27706 if(fullyGapOpened[region]) continue;
27707 for(MUint it = 0; it < m_gapCells.size(); it++) {
27708 const MInt regionId = m_gapCells[it].region;
27709 if(regionId != region) continue;
27710 const MInt cellId = m_gapCells[it].cellId;
27711 const MInt status = m_gapCells[it].status;
27712
27713 if(status != 16) continue;
27714
27715 MInt largestNeighbor = checkNeighborActivity(cellId);
27716
27717 if(largestNeighbor >= 0) {
27718 MInt largestNeighborGapCellId = m_gapCellId[largestNeighbor];
27719 m_gapCells[largestNeighborGapCellId].status = 17;
27720 // trigger reverse exchange!
27721 if(a_isHalo(largestNeighbor)) {
27722 m_gapCells[largestNeighborGapCellId].status = -99;
27723 }
27724 }
27725 }
27726 }
27727
27728 gapCellExchange(1);
27729 }
27730
27731
27732 // 4) during initGapOpening
27733 // Types:
27734 // 21: arising gap-Cell : interpolate variables, wasInactive = false, restoreSurfaces,
27735 // 22: new body-Bndry-Cell : interpolate variables ,
27736 // link to !wasInactive neighbor,
27737 // insert in oldBndryCells, dalta-Function for cell velocity
27738 // 23: old Gap-Bndry-Cell : delete from oldBndry-Cell, set oldCellVolume to current-Volume,
27739 // reset rhs0
27740 // 24: gap-bndry-Cel : cellVolumes as in first TimeStep
27741 // 25: internal gap-Cell :
27742 // 26: body-shadowed gap-Cell :
27743 // 27: bndry-Cell/was internal :
27744 // 28: new body-Bndry-Cell : interpolate variables , wasInactive = false,
27745 // (former 22) insert in oldBndryCells,
27746 // 29: large new body-Bndry-Cell : interpolate variables , wasInactive = false,
27747 // (former 22)
27748 // 99: submerging bndry-cell : delte from oldBndryCells without mass-Redistribution
27749 // and reset as inactive cell
27750
27751 // NOTE: currently arising gap-Cells and new body-Bndry-Cells are initialised by linear-Interpolation
27752 // between the cell-staates on both sides of the gap.
27753 // Additionally mass is added to the system though volume increase for oldGap-Bndry-Cells!
27754 // This initialised mass can be weight against the lost mass in initGapClosure!
27755
27756 vector<MInt> noArisingGapCells;
27757 vector<MInt> noArisingGapCellsHalo;
27758 vector<MInt> noNewBndryCells;
27759 vector<MInt> noNewBndryCellsHalo;
27760
27761 vector<MInt> interpolationCells;
27762
27763 for(MInt region = 0; region < m_noGapRegions; region++) {
27764 noArisingGapCells.push_back(0);
27765 noArisingGapCellsHalo.push_back(0);
27766 noNewBndryCells.push_back(0);
27767 noNewBndryCellsHalo.push_back(0);
27768 if(m_gapState[region] != 2) continue;
27769 for(MUint it = 0; it < m_gapCells.size(); it++) {
27770 const MInt regionId = m_gapCells[it].region;
27771 if(regionId != region) continue;
27772 const MInt cellId = m_gapCells[it].cellId; // all previous Gap-Cells in that region
27773
27774 // if(a_isHalo(cellId)) continue;
27775 // if(a_hasProperty( cellId, SolverCell::IsSplitChild)) continue;
27776 if(a_isBndryGhostCell(cellId)) continue;
27777 ASSERT(a_level(cellId) == maxRefinementLevel(), "");
27778 // at gap opening, all previous gap cells should be reined to the highest Level!
27779 if(a_level(cellId) != maxRefinementLevel()) continue;
27780
27781 ASSERT(!a_isGapCell(cellId), "");
27782 ASSERT(m_gapCells[it].status == 1, "");
27783 // G0 now coinsides with the set of the according body!
27784
27785 MInt flowCorner = 0;
27786 MInt bodyId = a_associatedBodyIds(cellId, 0);
27787 MInt bodySet = m_bodyToSetTable[bodyId];
27788
27789 MInt cndId = m_bndryCandidateIds[cellId];
27790
27791 if(cndId < 0) {
27792 if(a_levelSetValuesMb(cellId, bodySet) > F0) {
27793 flowCorner = m_noCellNodes;
27794 } else {
27795 flowCorner = 0;
27796 }
27797 } else {
27798 for(MInt node = 0; node < m_noCellNodes; node++) {
27799 if(m_candidateNodeValues[IDX_LSSETNODES(cndId, node, bodySet)] > F0) flowCorner++;
27800 }
27801 }
27802
27803 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
27804 if(flowCorner == m_noCellNodes) {
27805 // arising gap-Cell
27806 m_gapCells[it].status = 21;
27807 if(a_isHalo(cellId)) {
27808 noArisingGapCellsHalo[region]++;
27809 } else {
27810 noArisingGapCells[region]++;
27811 }
27812
27813 } else if(flowCorner == 0) {
27814 // body-shadowed gap-Cell
27815 m_gapCells[it].status = 26;
27816
27817 } else {
27818 // will be bndry-Cell
27819 if(a_isHalo(cellId)) {
27820 noNewBndryCellsHalo[region]++;
27821 } else {
27822 noNewBndryCells[region]++;
27823 }
27824 m_gapCells[it].status = 22;
27825 }
27826
27827
27828 } else { // was active
27829
27830 auto it1 = m_oldBndryCells.find(cellId);
27831 if(it1 != m_oldBndryCells.end()) {
27832 if(flowCorner == m_noCellNodes) {
27833 // will be internal-Cell
27834 // old-Gap-bndry-Cell
27835 m_gapCells[it].status = 23;
27836
27837 // delete former bndry-Cell
27838 //--> releasing mass into the fluid
27839 // shall be treated just as if the cell had been an internal-Cell before!
27840 for(MInt v = 0; v < m_noFVars; v++) {
27841 a_rightHandSide(cellId, v) = F0;
27842 m_rhs0[cellId][v] = F0;
27843 }
27844
27845 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = grid().gridCellVolume(a_level(cellId));
27846 a_cellVolume(cellId) = grid().gridCellVolume(a_level(cellId));
27847 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
27848 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId));
27849 m_oldBndryCells.erase(it1);
27850
27851 } else if(flowCorner == 0) {
27852 // submerging bndry-cell
27853 // will be inactive cell, was bndry-Cell
27854 m_gapCells[it].status = 99;
27855
27856 // delete former bndry-Cell
27857 //--> releasing mass into the fluid
27858 // shall be treated just as if the cell had been an internal-Cell before!
27859 for(MInt v = 0; v < m_noFVars; v++) {
27860 a_rightHandSide(cellId, v) = F0;
27861 m_rhs0[cellId][v] = F0;
27862 }
27863 removeSurfaces(cellId);
27864
27865 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = grid().gridCellVolume(a_level(cellId));
27866 a_cellVolume(cellId) = grid().gridCellVolume(a_level(cellId));
27867 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
27868 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId));
27869 m_oldBndryCells.erase(it1);
27870
27871
27872 } else {
27873 // gap-bndry-cell
27874 m_gapCells[it].status = 24;
27875 // handeled regularly as emerging cell!
27876 }
27877
27878 } else { // not a old Bndry-Cell
27879
27880 // TODO labels:FVMB use a_isBndryCell and IsInactive to differe here!
27881 if(flowCorner == m_noCellNodes) {
27882 // will be internal-Cell
27883 // gap-internal-cell
27884 m_gapCells[it].status = 25;
27885
27886 } else if(flowCorner == 0) {
27887 cerr << "UnExpected GapCell (2) at initGapOpening! " << c_globalId(cellId) << endl;
27888
27889 } else {
27890 // was internal, will be bndry-Cell
27891 // cerr << "UnExpected GapCell (3) at initGapOpening! " << c_globalId(cellId) << endl;
27892 m_gapCells[it].status = 27;
27893 }
27894 }
27895 }
27896 }
27897 }
27898
27899 MPI_Allreduce(MPI_IN_PLACE, &noArisingGapCells[0], m_noGapRegions, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
27900 "noArisingGapCells[0]");
27901 MPI_Allreduce(MPI_IN_PLACE, &noNewBndryCells[0], m_noGapRegions, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
27902 "noNewBndryCells[0]");
27903 MPI_Allreduce(MPI_IN_PLACE, &noArisingGapCellsHalo[0], m_noGapRegions, MPI_INT, MPI_SUM, mpiComm(), AT_,
27904 "MPI_IN_PLACE", "noArisingGapCellsHalo[0]");
27905 MPI_Allreduce(MPI_IN_PLACE, &noNewBndryCellsHalo[0], m_noGapRegions, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
27906 "noNewBndryCellsHalo[0]");
27907
27908 // c) special Treatment if any Gap Opens:
27909 // meaning either gapState 2 or fullyGapOpening during gap-Widening!
27910 if(anyGapOpening || anyFullyGapOpened) {
27911 for(MInt region = 0; region < m_noGapRegions; region++) {
27912 if(m_gapState[region] == 2 && domainId() == 0) {
27913 cerr << "Number of Arising-Gap-Cells " << noArisingGapCells[region] << " in region " << region << endl;
27914 cerr << "Number of new-Bndry-Cells " << noNewBndryCells[region] << " in region " << region << endl;
27915 } else if(domainId() == 0 && m_gapState[region] == 3) {
27916 cerr << "Number of Fully arising-Gap-Cells " << fullyGapOpened[region] << " in region " << region << endl;
27917 cerr << "Number of new-Bndry-Cells " << fullyGapBndry[region] << " in region " << region << endl;
27918 }
27919 }
27920
27921 initGapCellExchange();
27922
27923 // 2) init arising GapCells and new Bndry-Cells
27924 for(MInt region = 0; region < m_noGapRegions; region++) {
27925 if(m_gapState[region] != 2 && !fullyGapOpened[region]) continue;
27926 for(MUint it = 0; it < m_gapCells.size(); it++) {
27927 const MInt regionId = m_gapCells[it].region;
27928 if(regionId != region) continue;
27929 const MInt cellId = m_gapCells[it].cellId;
27930 const MInt status = m_gapCells[it].status;
27931
27932 if(status == 21) {
27933 if(!a_isHalo(cellId)) {
27934 interpolationCells.push_back(cellId);
27935 }
27936
27937 // these are all arings-Gap-Cells:
27938 //(sudden change towards internal Cells)
27939 // they need to be initialised before the cell-linking
27940 ASSERT(!a_hasProperty(cellId, SolverCell::IsInactive), "");
27941
27942 // 1) restore all surfaces
27943 restoreSurfaces(cellId);
27944
27945 // 2) init with the infinity-variables!
27946
27947 a_pvariable(cellId, PV->RHO) = m_rhoInfinity;
27948 a_pvariable(cellId, PV->U) = F0;
27949 a_pvariable(cellId, PV->V) = F0;
27950 IF_CONSTEXPR(nDim == 3) a_pvariable(cellId, PV->W) = F0;
27951 a_pvariable(cellId, PV->P) = m_PInfinity;
27952
27953 // 3) set the correct Volume
27954 a_cellVolume(cellId) = grid().gridCellVolume(a_level(cellId));
27955 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId));
27956 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
27957
27958 // 4) initialise rightHandSide
27959 for(MInt v = 0; v < m_noFVars; v++) {
27960 a_rightHandSide(cellId, v) = F0;
27961 m_rhs0[cellId][v] = F0;
27962 }
27963
27964 // 5) treat as if the cell would have been active before
27965 // this way, no special Linking is necessary!
27966 // and small bndry-cells can be linked to the large arising Gap-Cells
27967 // -> less checkNeighborActive!
27968 ASSERT(a_hasProperty(cellId, SolverCell::WasInactive), "");
27969 a_hasProperty(cellId, SolverCell::WasInactive) = false;
27970
27971 } else if(status == 22) {
27972 if(!a_isHalo(cellId)) {
27973 interpolationCells.push_back(cellId);
27974 }
27975
27976 ASSERT(!a_hasProperty(cellId, SolverCell::IsInactive), "");
27977 // 1) init with the infinity-variables!
27978
27979 a_pvariable(cellId, PV->RHO) = m_rhoInfinity;
27980 a_pvariable(cellId, PV->U) = F0;
27981 a_pvariable(cellId, PV->V) = F0;
27982 IF_CONSTEXPR(nDim == 3) a_pvariable(cellId, PV->W) = F0;
27983 a_pvariable(cellId, PV->P) = m_PInfinity;
27984
27985 // 2) initialise rightHandSide
27986 for(MInt v = 0; v < m_noFVars; v++) {
27987 a_rightHandSide(cellId, v) = F0;
27988 m_rhs0[cellId][v] = F0;
27989 }
27990 }
27991 }
27992 }
27993
27994 // for security/backup reasons!
27995 gapCellExchange(1);
27996
27997 // 3) interpolate primativeVariables for arising GapCells and new bndry-Cells
27998 // status 21,22
27999 vector<MInt> noIterations;
28000 for(MInt region = 0; region < m_noGapRegions; region++) {
28001 noIterations.push_back(0);
28002 noIterations[region] = noArisingGapCells[region] + (MInt)(noNewBndryCells[region] / IPOW2(nDim))
28003 + fullyGapOpened[region] + fullyGapBndry[region];
28004 noIterations[region] = mMax(noIterations[region], 100);
28005 }
28006
28007 MPI_Allreduce(MPI_IN_PLACE, &noIterations[0], m_noGapRegions, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
28008 "noIterations[0]");
28009
28010 for(MInt region = 0; region < m_noGapRegions; region++) {
28011 if(m_gapState[region] != 2 && !fullyGapOpened[region]) continue;
28012#if defined _MB_DEBUG_ || !defined NDEBUG
28013 if(domainId() == 0) {
28014 cerr << "Starting to iterate for region: " << region << " with " << noIterations[region] << " Iterations! "
28015 << endl;
28016 }
28017#endif
28018 // iterate over the global number of arisingGapCells
28019 for(MInt loop = 0; loop < noIterations[region]; loop++) {
28020 for(MUint i = 0; i < interpolationCells.size(); i++) {
28021 const MInt cellId = interpolationCells[i];
28022 const MInt it = m_gapCellId[cellId];
28023 ASSERT(it >= 0, "");
28024 const MInt regionId = m_gapCells[it].region;
28025 if(regionId != region) continue;
28026 const MInt status = m_gapCells[it].status;
28027
28028 ASSERT(status == 21 || status == 22, "");
28029 ASSERT(!a_isHalo(cellId), "");
28030
28031 // all-arising gap-cells in the region:
28032 MInt noNghbrs = 0;
28033 MFloat pVariables[5] = {F0, F0, F0, F0, F0};
28034
28035 for(MInt dir = 0; dir < m_noDirs; dir++) {
28036 if(!checkNeighborActive(cellId, dir) || a_hasNeighbor(cellId, dir) == 0) continue;
28037 MInt nghbrId = c_neighborId(cellId, dir);
28038 if(nghbrId < 0) continue;
28039 ASSERT(!a_hasProperty(nghbrId, SolverCell::IsInactive), "");
28040 if(!a_wasGapCell(nghbrId) && a_hasProperty(nghbrId, SolverCell::WasInactive)) continue;
28041
28042 /*
28043 if(!a_wasGapCell(nghbrId)) {
28044 //TODO labels:FVMB change to ASSERT!
28045 if(loop == 0) {
28046 cerr << "Interpolation from not-gap-Cell -> Strange "
28047 << a_hasProperty(nghbrId, SolverCell::IsInactive)
28048 << a_hasProperty(nghbrId, SolverCell::WasInactive)
28049 << a_isBndryCell(nghbrId) << " " << c_globalId(cellId) << endl;
28050 }
28051 if(!a_hasProperty(cellId, SolverCell::IsInactive) &&
28052 !a_hasProperty(cellId, SolverCell::WasInactive)) {
28053 cerr << "CAUTION: Interpolation-Cell has a active Neighbor which was not a Gap-Cell "
28054 << c_globalId(cellId) << " " << c_globalId(nghbrId) << endl;
28055 }
28056 continue;
28057 }
28058 */
28059 MInt nghbrGapId = m_gapCellId[nghbrId];
28060 if(nghbrGapId >= 0) {
28061 // if the neighbor is a gap-cell further checks can be done:
28062
28063 MInt nghbrStatus = m_gapCells[nghbrGapId].status;
28064 // avoid inactive-neighbors
28065 if(nghbrStatus == 26) continue;
28066
28067 // skip gap-bndry-cells and only use internal cells for interpolation!
28068 if(nghbrStatus == 23 || nghbrStatus == 24) {
28069 // gap-bndry-Cell
28070 //-> find avtive gap-Cell be going one Step further in the same direction!
28071 if(!checkNeighborActive(nghbrId, dir) || a_hasNeighbor(nghbrId, dir) == 0) continue;
28072 nghbrId = c_neighborId(nghbrId, dir);
28073 if(nghbrId < 0) continue;
28074 nghbrGapId = m_gapCellId[nghbrId];
28075 nghbrStatus = m_gapCells[nghbrGapId].status;
28076
28077 if(nghbrStatus == 23) {
28078 // going another Step further
28079 if(!checkNeighborActive(nghbrId, dir) || a_hasNeighbor(nghbrId, dir) == 0) continue;
28080 nghbrId = c_neighborId(nghbrId, dir);
28081 if(nghbrId < 0) continue;
28082 nghbrGapId = m_gapCellId[nghbrId];
28083 nghbrStatus = m_gapCells[nghbrGapId].status;
28084 }
28085 }
28086
28087 // skip gap-bndry-cells and only use internal cells for interpolation!
28088 if(nghbrStatus == 10 || nghbrStatus == 14) {
28089 // gap-bndry-Cell
28090 //-> find avtive gap-Cell be going one Step further in the same direction!
28091 if(!checkNeighborActive(nghbrId, dir) || a_hasNeighbor(nghbrId, dir) == 0) continue;
28092 nghbrId = c_neighborId(nghbrId, dir);
28093 if(nghbrId < 0) continue;
28094 nghbrGapId = m_gapCellId[nghbrId];
28095 nghbrStatus = m_gapCells[nghbrGapId].status;
28096
28097 if(nghbrStatus == 10) {
28098 // going another Step further
28099 if(!checkNeighborActive(nghbrId, dir) || a_hasNeighbor(nghbrId, dir) == 0) continue;
28100 nghbrId = c_neighborId(nghbrId, dir);
28101 if(nghbrId < 0) continue;
28102 nghbrGapId = m_gapCellId[nghbrId];
28103 nghbrStatus = m_gapCells[nghbrGapId].status;
28104 }
28105 }
28106 if(nghbrStatus == 26) continue;
28107
28108 if(m_gapState[region] == 2 && a_wasGapCell(nghbrId) && nghbrStatus != 25 && nghbrStatus != 21
28109 && nghbrStatus != 23 && nghbrStatus != 22 && nghbrStatus != 24) {
28110 cerr << "Caution: using strange neighbor for interpolation: " << c_globalId(cellId) << " " << status
28111 << " " << c_globalId(nghbrId) << " " << a_wasGapCell(nghbrId) << " "
28112 << a_hasProperty(nghbrId, SolverCell::WasInactive) << " " << nghbrStatus << endl;
28113 } else if(m_gapState[region] == 3 && a_wasGapCell(nghbrId) && nghbrStatus != 21 && nghbrStatus != 22
28114 && nghbrStatus != 10 && nghbrStatus != 14) {
28115 cerr << "Caution: using strange neighbor for interpolation: " << c_globalId(cellId) << " " << status
28116 << " " << c_globalId(nghbrId) << " " << a_wasGapCell(nghbrId) << " "
28117 << a_hasProperty(nghbrId, SolverCell::WasInactive) << " " << nghbrStatus << endl;
28118 }
28119 }
28120
28121 if(a_hasProperty(nghbrId, SolverCell::IsInactive)) continue;
28122
28123 ASSERT(!a_hasProperty(nghbrId, SolverCell::IsInactive), "");
28124 if(!a_wasGapCell(nghbrId) && a_hasProperty(nghbrId, SolverCell::WasInactive)) continue;
28125
28126 // only use former internal-Cells for interpolation!
28127 auto it1 = m_oldBndryCells.find(nghbrId);
28128 if(it1 != m_oldBndryCells.end()) continue;
28129
28130
28131 noNghbrs++;
28132 pVariables[0] += a_pvariable(nghbrId, PV->RHO);
28133 pVariables[1] += a_pvariable(nghbrId, PV->P);
28134 pVariables[2] += a_pvariable(nghbrId, PV->U);
28135 pVariables[3] += a_pvariable(nghbrId, PV->V);
28136 IF_CONSTEXPR(nDim == 3) pVariables[4] += a_pvariable(nghbrId, PV->W);
28137
28138 // if(!a_isHalo(cellId) && loop == 0)
28139 // cerr << "Neighbors of Arising Gap-Cell " << c_globalId(cellId) << " "
28140 // << c_globalId(nghbrId) << " status " << nghbrStatus << endl;
28141 }
28142 if(noNghbrs > 0) {
28143 a_pvariable(cellId, PV->RHO) = pVariables[0] / noNghbrs;
28144 a_pvariable(cellId, PV->P) = pVariables[1] / noNghbrs;
28145 a_pvariable(cellId, PV->U) = pVariables[2] / noNghbrs;
28146 a_pvariable(cellId, PV->V) = pVariables[3] / noNghbrs;
28147 IF_CONSTEXPR(nDim == 3) a_pvariable(cellId, PV->W) = pVariables[4] / noNghbrs;
28148 }
28149 }
28150
28151 gapCellExchange(0);
28152 }
28153 }
28154
28155 // 2) set wasInactive to false for large bndry-Cells
28156 // some cells with status 22 are changed to status 29!
28157 // (bndry-Cells outside the small-Cell-Treatment and thus should be stable)
28158 // -> the smaller neighboring cells can be linked to them esier!
28159
28160 for(MInt region = 0; region < m_noGapRegions; region++) {
28161 if(m_gapState[region] != 2) continue;
28162 for(MUint it = 0; it < m_gapCells.size(); it++) {
28163 MInt regionId = m_gapCells[it].region;
28164 if(regionId != region) continue;
28165 MInt cellId = m_gapCells[it].cellId;
28166 MInt status = m_gapCells[it].status;
28167
28168 if(status != 22) continue;
28169
28170 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_volume / grid().gridCellVolume(a_level(cellId)) > 0.5) {
28171 a_hasProperty(cellId, SolverCell::WasInactive) = false;
28172 m_oldBndryCells.insert(make_pair(cellId, F0));
28173 m_gapCells[it].status = 29;
28174 }
28175 if(noArisingGapCells[region] == 0 && fullyGapOpened[region] == 0) {
28176 // if only bndry-cells are arising: (this means that gapWidth < cellLength)
28177 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_volume / grid().gridCellVolume(a_level(cellId))
28178 > (0.5 * 0.5)) {
28179 a_hasProperty(cellId, SolverCell::WasInactive) = false;
28180 m_oldBndryCells.insert(make_pair(cellId, F0));
28181 m_gapCells[it].status = 29;
28182 }
28183 }
28184 }
28185 }
28186
28187
28188 // 4) set conservativeVariables of Gap-Cells
28189 // and set wasInactive accoring to checkNeighborActivity for bndry-Cells
28190 for(MInt region = 0; region < m_noGapRegions; region++) {
28191 if(m_gapState[region] != 2) continue;
28192 for(MUint it = 0; it < m_gapCells.size(); it++) {
28193 MInt regionId = m_gapCells[it].region;
28194 if(regionId != region) continue;
28195 MInt cellId = m_gapCells[it].cellId;
28196 MInt status = m_gapCells[it].status;
28197
28198 if(status != 21 && status != 22 && status != 29) continue;
28199
28200 setConservativeVariables(cellId);
28201
28202 // init oldVariable
28203 for(MInt varId = 0; varId < CV->noVariables; varId++) {
28204 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
28205 }
28206
28207 if(status != 21) {
28208 //= bndry-Cells
28209 // status == 22 or 29
28210 // activate further neighbors which have small cells with wasInactive
28211 MInt largestNeighbor = checkNeighborActivity(cellId);
28212 if(largestNeighbor > 0) {
28213 MInt largestNeighborGapCellId = m_gapCellId[largestNeighbor];
28214 m_gapCells[largestNeighborGapCellId].status = 28;
28215 if(a_isHalo(largestNeighbor)) {
28216 m_gapCells[largestNeighborGapCellId].status = -99;
28217 }
28218 }
28219 }
28220 }
28221 }
28222
28223 gapCellExchange(1);
28224
28225
28226 // 5) match Cell-types at initGapOpening and estimate total-mass-loss
28227 /*
28228
28229 for(MInt region = 0; region < m_noGapRegions; region++) {
28230 if(m_gapState[region] != 2) continue;
28231 for(MUint it = 0; it < m_gapCells.size(); it++){
28232 MInt regionId = m_gapCells[it].region;
28233 if(regionId != region) continue;
28234 MInt cellId = m_gapCells[it].cellId;
28235 MInt status = m_gapCells[it].status;
28236
28237 if(a_isHalo(cellId)) continue;
28238
28239 //find the status of the cell at initGapClosure
28240 MUint it1 = m_gapCellsBackup.size();
28241 for( MUint it2 = 0; it2 < m_gapCellsBackup.size(); it2++){
28242 if(m_gapCellsBackup[it2].cellId == cellId ) {
28243 it1 = it2;
28244 break;
28245 }
28246 }
28247
28248 if(it1 == m_gapCellsBackup.size()) {
28249 //cerr << "WasGapCell at initGapOpening not found in gapCellBackup " << c_globalId(cellId)
28250 // << " " << status << endl;
28251 continue;
28252 }
28253 MInt oldstatus = m_gapCellsBackup[it1].status;
28254
28255
28256 if(status == 21 && oldstatus != 4) {
28257 cerr << "Arising-Gap-Cell doesn't match gap-shadowed Cell " << c_globalId(cellId) << " "
28258 << oldstatus << endl;
28259
28260 } else if (status == 26 && oldstatus != 9) {
28261 cerr << "Body-shadowed Gap-Cells not matching " << c_globalId(cellId) << " "
28262 << oldstatus << endl;
28263 } else if (status == 23 && oldstatus != 7) {
28264 cerr << "Gap-Bndry-Cells not matching " << c_globalId(cellId) << " " << oldstatus << endl;
28265 } else if(status == 22 && oldstatus != 5) {
28266 cerr << "Body-Bndry-Cells not matching " << c_globalId(cellId) << " " << oldstatus << endl;
28267 }
28268
28269 }
28270 }
28271 */
28272 }
28273
28274
28275 // now add splitChilds and set the correct Gap-state, region and status
28276 // for initGapopening, also update the changes from the splitCell to the splitChilds!
28277 MInt noGapSplitChild = 0;
28278 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
28279 const MInt cellId = m_splitCells[sc];
28280 if(m_gapCellId[cellId] < 0) continue;
28281 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
28282 const MInt splitChildId = m_splitChilds[sc][ssc];
28283 a_isGapCell(splitChildId) = a_isGapCell(cellId);
28284 a_wasGapCell(splitChildId) = a_wasGapCell(cellId);
28285 if(a_isGapCell(splitChildId) || a_wasGapCell(splitChildId)) {
28286 noGapSplitChild++;
28287 const MInt region = m_gapCells[m_gapCellId[cellId]].region;
28288 const MInt status = m_gapCells[m_gapCellId[cellId]].status;
28289 const MInt body1 = m_gapCells[m_gapCellId[cellId]].bodyIds[0];
28290 const MInt body2 = m_gapCells[m_gapCellId[cellId]].bodyIds[1];
28291 const MInt gapId = m_gapCells.size();
28292 m_gapCells.emplace_back(splitChildId, region, status, body1, body2);
28293 m_gapCellId[splitChildId] = gapId;
28294 a_hasProperty(splitChildId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::WasInactive);
28295
28296 if(region > m_noGapRegions) continue;
28297 // for initGapOpening: update splitchilds variables based on splitcell-values:
28298 if(m_gapState[region] == 2) {
28299 for(MInt var = 0; var < m_noCVars; var++) {
28300 a_variable(splitChildId, var) = a_variable(cellId, var);
28301 a_oldVariable(splitChildId, var) = a_variable(cellId, var);
28302 }
28303 for(MInt var = 0; var < m_noPVars; var++) {
28304 a_pvariable(splitChildId, var) = a_pvariable(cellId, var);
28305 }
28306 for(MInt var = 0; var < m_noFVars; var++) {
28307 a_rightHandSide(splitChildId, var) = a_rightHandSide(cellId, var);
28308 m_rhs0[splitChildId][var] = m_rhs0[cellId][var];
28309 }
28310 } else if(m_gapState[region] == -2) {
28311 // for initGapClosure: remove splitchilds Surfaces
28312 a_hasProperty(splitChildId, SolverCell::IsInactive) = a_hasProperty(cellId, SolverCell::IsInactive);
28313 for(MInt v = 0; v < m_noFVars; v++) {
28314 a_rightHandSide(splitChildId, v) = a_rightHandSide(cellId, v);
28315 m_rhs0[splitChildId][v] = m_rhs0[cellId][v];
28316 }
28317 if(!a_hasProperty(splitChildId, SolverCell::WasInactive)
28318 && a_hasProperty(splitChildId, SolverCell::IsInactive)) {
28319 removeSurfaces(cellId);
28320 }
28321 }
28322 }
28323 }
28324 }
28325 MPI_Allreduce(MPI_IN_PLACE, &noGapSplitChild, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "noGapSplitChild");
28326
28327#if defined _MB_DEBUG_ || !defined NDEBUG
28328 if(domainId() == 0 && anyGapOpening) cerr << " Finished gap-Handling" << endl;
28329#endif
28330
28331 if(noGapSplitChild > 0) {
28332 initGapCellExchange();
28333 gapCellExchange(1);
28334
28335#if defined _MB_DEBUG_ || !defined NDEBUG
28336 if(domainId() == 0) {
28337 cerr << "Number of Gap-Split-Childs " << noGapSplitChild << endl;
28338 }
28339#endif
28340 }
28341}
28342
28343
28348template <MInt nDim, class SysEqn>
28350 TRACE();
28351
28352 ASSERT(m_levelSet && m_closeGaps, "");
28353 ASSERT(m_gapInitMethod > 0, "");
28354
28355 // const MFloat eps = sqrt( nDim ) * c_cellLengthAtLevel(m_lsCutCellBaseLevel);
28356
28357 // general Checks in all cases:
28358 for(MInt region = 0; region < m_noGapRegions; region++) {
28359 for(MUint it = 0; it < m_gapCells.size(); it++) {
28360 const MInt regionId = m_gapCells[it].region;
28361 if(regionId != region) continue;
28362 const MInt cellId = m_gapCells[it].cellId;
28363 const MInt status = m_gapCells[it].status;
28364
28365 ASSERT(a_cellVolume(cellId) > 0, "");
28366
28367 if(a_cellVolume(cellId) > grid().gridCellVolume(a_level(cellId))) {
28368 const MInt globalId = cellId < c_noCells() ? c_globalId(cellId) : -1;
28369 cerr << "Large Volume " << globalId << " " << status << endl;
28370 }
28371
28372 // ASSERT(m_cellVolumesDt1[ cellId ] > 0 , "");
28373 if(m_cellVolumesDt1[cellId] < 0) {
28374 const MInt globalId = cellId < c_noCells() ? c_globalId(cellId) : -1;
28375 cerr << "Negative Dt-Volume " << globalId << " " << status << " "
28376 << m_cellVolumesDt1[cellId] / grid().gridCellVolume(a_level(cellId)) << endl;
28377 }
28378
28379 if(m_cellVolumesDt1[cellId] > grid().gridCellVolume(a_level(cellId))) {
28380 const MInt globalId = cellId < c_noCells() ? c_globalId(cellId) : -1;
28381 cerr << "Large Dt-Volume " << globalId << " " << status << " "
28382 << m_cellVolumesDt1[cellId] / grid().gridCellVolume(a_level(cellId)) << endl;
28383 }
28384 }
28385 }
28386
28387 // current bndry-cells are checked in updateGapBoundaryCells!
28388
28389 // during gapClosure
28390 for(MInt region = 0; region < m_noGapRegions; region++) {
28391 if(m_gapState[region] != -2) continue;
28392 for(MUint it = 0; it < m_gapCells.size(); it++) {
28393 const MInt regionId = m_gapCells[it].region;
28394 if(regionId != region) continue;
28395 const MInt cellId = m_gapCells[it].cellId;
28396 const MInt status = m_gapCells[it].status;
28397 if(status == 3 || status == 4) {
28398 ASSERT(a_hasProperty(cellId, SolverCell::IsInactive), "");
28399 for(MInt dir = 0; dir < m_noDirs; dir++) {
28400 ASSERT(m_cellSurfaceMapping[cellId][dir] == -1, "");
28401 }
28402 auto it1 = m_oldBndryCells.find(cellId);
28403 ASSERT(it1 == m_oldBndryCells.end(), "");
28404 } else if(status == 5 || status == 6 || status == 7) {
28405 ASSERT(a_isBndryCell(cellId), "");
28406
28407 } else if(status == 8 || status == 9) {
28408 ASSERT(!a_hasProperty(cellId, SolverCell::IsInactive), "");
28409 ASSERT(!a_isBndryCell(cellId), "");
28410 ASSERT(abs(a_cellVolume(cellId) - grid().gridCellVolume(a_level(cellId))) < 0.000001, "");
28411 } else if(status == 2) {
28412 ASSERT(a_hasProperty(cellId, SolverCell::IsInactive), "");
28413 }
28414 }
28415 }
28416
28417 // during gap widening
28418 for(MInt region = 0; region < m_noGapRegions; region++) {
28419 if(m_gapState[region] != 3) continue;
28420 for(MUint it = 0; it < m_gapCells.size(); it++) {
28421 const MInt regionId = m_gapCells[it].region;
28422 if(regionId != region) continue;
28423 const MInt cellId = m_gapCells[it].cellId;
28424 const MInt status = m_gapCells[it].status;
28425
28426 ASSERT((status >= 10 && status < 18) || (status == 0 /*&& a_levelSetValuesMb(cellId, 0) < -eps*/)
28427 || (status == 21 || status == 22 || status == 28 || status == 29),
28428 to_string(status));
28429
28430 // check that all active cells either are a bndry-Cell or were active before
28431 if(!a_hasProperty(cellId, SolverCell::IsInactive) && !a_isBndryCell(cellId)) {
28432 ASSERT(!a_hasProperty(cellId, SolverCell::WasInactive), "");
28433 }
28434
28435 if(status == 10)
28436 ASSERT(a_cellVolume(cellId) - grid().gridCellVolume(a_level(cellId)) < 0.00001, to_string(c_globalId(cellId)));
28437
28438 if(status != 11) {
28439 if(a_cellVolume(cellId) < 0 || m_cellVolumesDt1[cellId] < 0) {
28440 cerr << "Volume-Error in gap-Cell " << c_globalId(cellId) << " " << status << " "
28441 << a_hasProperty(cellId, SolverCell::IsInactive) << " " << a_isHalo(cellId) << endl;
28442 }
28443 }
28444
28445 if(status == 12 || status == 13) {
28446 if(a_isHalo(cellId)) {
28447 /*
28448 auto it1 = m_linkedHaloCells.find( cellId );
28449 if(it1 == m_linkedHaloCells.end()) {
28450 cerr << "CAUTION: unable to link Halo-gap BndryCell during Gap-Widening " << c_globalId(cellId)
28451 << " " << status << " " << a_hasProperty(cellId, SolverCell::IsInactive)
28452 << " " << a_isBndryCell(cellId) << " " << a_hasProperty(cellId, SolverCell::WasInactive)
28453 << " " << a_isHalo(cellId)
28454 << endl;
28455 }
28456 */
28457 } else if(!a_hasProperty(cellId, SolverCell::IsSplitChild)) {
28458 if(!a_hasProperty(cellId, SolverCell::IsTempLinked)) {
28459 cerr << "CAUTION: unable to link gap BndryCell during Gap-Widening " << c_globalId(cellId) << " " << status
28460 << " " << a_hasProperty(cellId, SolverCell::IsInactive) << " " << a_isBndryCell(cellId) << " "
28461 << a_hasProperty(cellId, SolverCell::WasInactive) << " " << a_isHalo(cellId) << endl;
28462 }
28463 }
28464
28465 } else if(status == 14 || status == 15) {
28466 if(a_cellVolume(cellId) < 0 || a_cellVolume(cellId) > grid().gridCellVolume(a_level(cellId))) {
28467 // cerr << "Invalid Volume " << c_globalId(cellId) << " " << status
28468 // << " " << a_isHalo(cellId) << " " << a_cellVolume(cellId) << " "
28469 // << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " "
28470 // << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << endl;
28471 }
28472 }
28473 }
28474 }
28475
28476 // during gap opening
28477 for(MInt region = 0; region < m_noGapRegions; region++) {
28478 if(m_gapState[region] != 2) continue;
28479 for(MUint it = 0; it < m_gapCells.size(); it++) {
28480 const MInt regionId = m_gapCells[it].region;
28481 if(regionId != region) continue;
28482 const MInt cellId = m_gapCells[it].cellId;
28483 const MInt status = m_gapCells[it].status;
28484
28485 ASSERT(((status > 20 && status <= 29) || status == 99 || status == 98), to_string(status));
28486
28487 if(status == 21) {
28488 if(a_cellVolume(cellId) > grid().gridCellVolume(a_level(cellId))
28489 || a_cellVolume(cellId) < grid().gridCellVolume(a_level(cellId))) {
28490 cerr << "Incorrect Cell-Volume of arising Gap-Cell" << c_globalId(cellId) << " " << a_cellVolume(cellId)
28491 << " " << grid().gridCellVolume(a_level(cellId)) << endl;
28492 }
28493
28494 // surface-check
28495 ASSERT(!a_hasProperty(cellId, SolverCell::IsInactive), "");
28496
28497 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
28498 for(MInt dir = 0; dir < m_noDirs; dir++) {
28499 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
28500 MInt nghbrId = c_neighborId(cellId, dir);
28501 if(nghbrId < 0) continue;
28502 if(a_isHalo(cellId) && a_isHalo(nghbrId)) continue;
28503 if(srfcId < 0) {
28504 cerr << "CAUTION: Arising-Gap-Cell is missing surfaces " << c_globalId(cellId) << " " << dir << " "
28505 << a_levelSetValuesMb(cellId, 0) << " " << a_isHalo(cellId) << " "
28506 << a_hasProperty(cellId, SolverCell::IsNotGradient) << endl;
28507 }
28508 }
28509 } else if(status == 22 && false) {
28510 if(!a_isHalo(cellId)) {
28511 if(!a_hasProperty(cellId, SolverCell::IsTempLinked)) {
28512 cerr << "CAUTION: unable to link gap BndryCell during initGapOpening " << c_globalId(cellId) << " "
28513 << status << " " << a_hasProperty(cellId, SolverCell::IsInactive) << " " << a_isBndryCell(cellId)
28514 << " " << a_hasProperty(cellId, SolverCell::WasInactive) << " " << a_isHalo(cellId) << endl;
28515 }
28516 }
28517 }
28518 }
28519 }
28520
28521 // during gap shrinking
28522 for(MInt region = 0; region < m_noGapRegions; region++) {
28523 if(m_gapState[region] != -1) continue;
28524 for(MUint it = 0; it < m_gapCells.size(); it++) {
28525 MInt regionId = m_gapCells[it].region;
28526 if(regionId != region) continue;
28527 MInt cellId = m_gapCells[it].cellId;
28528
28529 if(!a_isBndryCell(cellId)) continue;
28530 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
28531 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
28532
28533 if(a_wasGapCell(cellId) && !a_isGapCell(cellId)) continue;
28534
28535 MInt bndryId = a_bndryId(cellId);
28536 if(bndryId < -1) continue;
28537 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
28538 for(MInt i = 0; i < nDim; i++) {
28539 ASSERT(abs(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]]) < 0.00000001, "");
28540 }
28541 MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
28542 if(ghostCellId < 0) continue;
28543 }
28544 }
28545 }
28546
28547 // checkGapHaloCells:
28548 const MInt noChecks = 4;
28549 MFloatScratchSpace cellCheck(a_noCells(), noChecks, AT_, "cellCheck");
28550 cellCheck.fill(std::numeric_limits<MFloat>::max());
28551
28552 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
28553 cellCheck(cellId, 0) = (MFloat)a_isGapCell(cellId);
28554 cellCheck(cellId, 1) = (MFloat)a_wasGapCell(cellId);
28555 cellCheck(cellId, 2) = -F1;
28556 cellCheck(cellId, 3) = -F1;
28557 if(a_isGapCell(cellId) || a_wasGapCell(cellId)) {
28558 const MInt region = m_gapCells[m_gapCellId[cellId]].region;
28559 const MInt status = m_gapCells[m_gapCellId[cellId]].status;
28560 cellCheck(cellId, 2) = (MFloat)region;
28561 cellCheck(cellId, 3) = (MFloat)status;
28562 }
28563 }
28564
28565 exchangeDataFV(&cellCheck(0), noChecks);
28566
28567 for(MInt cellId = noInternalCells(); cellId < a_noCells(); cellId++) {
28568 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
28569 if((MInt)cellCheck(cellId, 0) != a_isGapCell(cellId)) {
28570 cerr << domainId() << ": ERR0 checkGapHaloCells " << globalTimeStep << " " << c_globalId(cellId) << endl;
28571 }
28572 if((MInt)cellCheck(cellId, 1) != a_wasGapCell(cellId)) {
28573 cerr << domainId() << ": ERR1 checkGapHaloCells " << globalTimeStep << " " << c_globalId(cellId) << endl;
28574 }
28575 MInt region = -1;
28576 MInt status = -1;
28577 if(a_isGapCell(cellId) || a_wasGapCell(cellId)) {
28578 region = m_gapCells[m_gapCellId[cellId]].region;
28579 status = m_gapCells[m_gapCellId[cellId]].status;
28580 }
28581
28582 if((MInt)cellCheck(cellId, 2) != region) {
28583 cerr << domainId() << ": ERR2 checkGapHaloCells " << globalTimeStep << " " << c_globalId(cellId) << endl;
28584 }
28585 if((MInt)cellCheck(cellId, 3) != status) {
28586 cerr << domainId() << ": ERR3 checkGapHaloCells " << globalTimeStep << " " << c_globalId(cellId) << endl;
28587 }
28588 }
28589}
28590
28591
28597template <MInt nDim, class SysEqn>
28599 TRACE();
28600
28601 ASSERT(m_gapInitMethod == 0, "");
28602
28603 m_gapCellId.clear();
28604 m_gapCellId.resize(a_noCells());
28605 for(MInt i = 0; i < a_noCells(); i++)
28606 m_gapCellId[i] = -1;
28607
28608 for(MUint it = 0; it < m_gapCells.size(); it++) {
28609 const MInt cellId = m_gapCells[it].cellId;
28610 m_gapCellId[cellId] = (MInt)it;
28611 }
28612
28613 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
28614 const MInt cellId = m_splitCells[sc];
28615 if(m_gapCellId[cellId] < 0) continue;
28616 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
28617 const MInt splitChildId = m_splitChilds[sc][ssc];
28618 if(a_isGapCell(splitChildId) || a_wasGapCell(splitChildId)) {
28619 const MInt gapId = m_gapCells.size();
28620 const MInt region = m_gapCells[m_gapCellId[cellId]].region;
28621 const MInt status = m_gapCells[m_gapCellId[cellId]].status;
28622 const MInt body1 = m_gapCells[m_gapCellId[cellId]].bodyIds[0];
28623 const MInt body2 = m_gapCells[m_gapCellId[cellId]].bodyIds[1];
28624 m_gapCells.emplace_back(splitChildId, region, status, body1, body2);
28625 m_gapCellId[splitChildId] = gapId;
28626 }
28627 }
28628 }
28629}
28630
28631
28640template <MInt nDim, class SysEqn>
28642 TRACE();
28643
28644 ASSERT(m_levelSet && m_closeGaps, "");
28645 ASSERT(m_gapInitMethod > 0, "");
28646
28647 // during initGapClosure
28648 for(MInt region = 0; region < m_noGapRegions; region++) {
28649 if(m_gapState[region] != -2) continue;
28650
28651 // easy-first try: static initialisation:
28652 // sweptVolume = sweptVolumeDt = 0
28653 // cellVolume = cellVolumeDt = bndry-Cell-volume
28654 // velocity = 0
28655
28656 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
28657 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
28658 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
28659 const MInt gapCellId = m_gapCellId[cellId];
28660 if(gapCellId < 0) continue;
28661 const MInt regionId = m_gapCells[gapCellId].region;
28662 if(regionId != region) continue;
28663
28664 const MInt status = m_gapCells[gapCellId].status;
28665
28666 // do cell-Volume update based on split-cell volumes
28667 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
28668 for(MInt v = 0; v < m_noFVars; v++) {
28669 a_rightHandSide(cellId, v) = F0;
28670 m_rhs0[cellId][v] = F0;
28671 }
28672 m_sweptVolumeDt1[bndryId] = 0;
28673 m_sweptVolume[bndryId] = 0;
28674 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
28675 for(MInt i = 0; i < nDim; i++) {
28676 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = 0;
28677 }
28678 }
28679 continue;
28680 }
28681 // change to ASSERT!
28682 if(status != 5 && status != 6 && status != 7 && status != 99) {
28683 cerr << "UnExpected Bndry-Cell-Status (1) " << c_globalId(cellId) << " " << status << endl;
28684 }
28685
28686 // all active gap-bndry-Cells, now reseted:
28687 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
28688 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
28689 m_sweptVolumeDt1[bndryId] = 0;
28690 m_sweptVolume[bndryId] = 0;
28691 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
28692 for(MInt i = 0; i < nDim; i++) {
28693 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = 0;
28694 }
28695 }
28696 for(MInt v = 0; v < m_noFVars; v++) {
28697 a_rightHandSide(cellId, v) = F0;
28698 m_rhs0[cellId][v] = F0;
28699 }
28700 }
28701 }
28702
28703 // during gap-widening or shrinking
28704 for(MInt region = 0; region < m_noGapRegions; region++) {
28705 if(m_gapState[region] != 3 && m_gapState[region] != -1) continue;
28706
28707 // easy-first try: static initialisation:
28708 // sweptVolume = sweptVolumeDt = 0
28709 // cellVolume = cellVolumeDt = bndry-Cell-volume
28710 // velocity = 0
28711
28712 for(MUint it = 0; it < m_gapCells.size(); it++) {
28713 const MInt regionId = m_gapCells[it].region;
28714 if(regionId != region) continue;
28715 const MInt cellId = m_gapCells[it].cellId;
28716 const MInt status = m_gapCells[it].status;
28717
28718 if(!a_isBndryCell(cellId)) continue;
28719 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
28720 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
28721
28722 if(a_wasGapCell(cellId) && !a_isGapCell(cellId)) continue;
28723
28724 // do this on split-Child-basis
28725 // if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
28726
28727 MInt bndryId = a_bndryId(cellId);
28728 if(bndryId < -1) continue;
28729
28730 // do cell-Volume update based on split-cell volumes
28731 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
28732 for(MInt v = 0; v < m_noFVars; v++) {
28733 a_rightHandSide(cellId, v) = F0;
28734 m_rhs0[cellId][v] = F0;
28735 }
28736 m_sweptVolumeDt1[bndryId] = 0;
28737 m_sweptVolume[bndryId] = 0;
28738 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
28739 for(MInt i = 0; i < nDim; i++) {
28740 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = 0;
28741 }
28742 }
28743 continue;
28744 }
28745
28746 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
28747 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
28748 m_sweptVolumeDt1[bndryId] = 0;
28749 m_sweptVolume[bndryId] = 0;
28750 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
28751 for(MInt i = 0; i < nDim; i++) {
28752 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = 0;
28753 }
28754 }
28755
28756 // for partial-Gap-Opening:
28757 // largestNeighbor of a new small gap Cell
28758 if(status == 17) {
28759 MFloat dV = F0;
28760 MFloat dt = timeStep(true);
28761
28762 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
28763 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
28764 for(MInt i = 0; i < nDim; i++) {
28765 MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
28766 dV -= dt * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] * nml * area;
28767 }
28768 }
28769
28770 MFloat cellVolume = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
28771
28772 if(dV > cellVolume) {
28773 dV = cellVolume;
28774 // get<2>(m_gapCells[gapCellId]) = 99;
28775 }
28776
28777 m_sweptVolume[bndryId] = dV;
28778 m_sweptVolumeDt1[bndryId] = dV;
28779
28780 // reduce bndry-Cell velocity to fit the boundary-Condition!
28781 MFloat delta = maia::math::deltaFun(m_volumeFraction[bndryId], F0, F1);
28782 for(MInt i = 0; i < nDim; i++) {
28783 a_pvariable(cellId, PV->VV[i]) =
28784 delta * a_pvariable(cellId, PV->VV[i])
28785 + (F1 - delta) * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->VV[i]];
28786 }
28787 setConservativeVariables(cellId);
28788 for(MInt varId = 0; varId < CV->noVariables; varId++) {
28789 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
28790 }
28791 }
28792
28793 // Plan-B: estimate the interface-velocity based on the volume-change!
28794 /*
28795 //compute the surface-velocity based on the volume-change of the cell
28796 MFloat vol = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_volume;
28797 MFloat volDt1 = m_cellVolumesDt1[ cellId ];
28798
28799 auto it1 = m_oldBndryCells.find( cellId );
28800 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
28801 cerr << "WasInactive " << m_cellVolumesDt1[ cellId ]/grid().gridCellVolume( a_level(cellId) ) << endl;
28802 } else if(it1 != m_oldBndryCells.end()) {
28803 cerr << "WasBndryCell " << m_cellVolumesDt1[ cellId ]/grid().gridCellVolume( a_level(cellId) )
28804 << " " << m_sweptVolumeDt1[a_bndryId( cellId )] << endl;
28805 } else {
28806 cerr << "WasActive " << m_cellVolumesDt1[ cellId ]/grid().gridCellVolume( a_level(cellId) ) << endl;
28807 }
28808
28809 MFloat dV = vol - volDt1;
28810 MFloat dt = timeStep(true);
28811 MFloat sign = (dV > 0) ? 1.0 : -1.0;
28812
28813 for( MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++){
28814 MFloat area = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_area;
28815 MFloat absVel = abs(dV / (area * dt));
28816 for( MInt i=0; i<nDim; i++ ) {
28817 MFloat nml = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_normalVector[ i ];
28818
28819 MFloat velocity = sign * absVel *nml;
28820 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = velocity;
28821
28822 cerr << globalTimeStep << " " << c_globalId(cellId) << " "
28823 << vol /grid().gridCellVolume( a_level(cellId) ) << " "
28824 << volDt1 / grid().gridCellVolume( a_level(cellId) ) << " " << i << " " << velocity
28825 << " " << nml << " " << m_sweptVolumeDt1[a_bndryId( cellId )] << endl;
28826
28827 }
28828 }
28829 */
28830 }
28831 }
28832
28833 // during initGapOpening (handeled in updateCellVolumeGCL! )
28834
28835 // easy-first try: just as upon-restart
28836 // sweptVolume = sweptVolumeDt = dV
28837 // cellVolume = bndry-Cell-volume
28838 // cellVolumeDt1 = cellVolume - deltaVolume
28839 // velocity = body-velocity
28840
28841 for(MInt region = 0; region < m_noGapRegions; region++) {
28842 if(m_gapState[region] != 2) continue;
28843
28844 // Plan-A
28845
28846 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
28847 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
28848 MInt gapCellId = m_gapCellId[cellId];
28849 if(gapCellId < 0) continue;
28850
28851 const MInt regionId = m_gapCells[gapCellId].region;
28852 if(regionId != region) continue;
28853
28854 ASSERT(a_wasGapCell(cellId), "");
28855
28856 // do this on split-Child-basis
28857 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
28858
28859 MInt status = m_gapCells[gapCellId].status;
28860
28861 if(status == 27) {
28862 // wasInternal Cell before
28863 // treated regularly
28864 continue;
28865 }
28866
28867 if(status != 22 && status != 24 && status != 28 && status != 29) {
28868 cerr << "UnExpected Bndry-Cell-Status (2) " << c_globalId(cellId) << " " << status << endl;
28869 }
28870
28871 MFloat dV = F0;
28872 MFloat dt = timeStep(true);
28873
28874 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
28875 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
28876 for(MInt i = 0; i < nDim; i++) {
28877 MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
28878 dV -= dt * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] * nml * area;
28879 }
28880 }
28881
28882 MFloat cellVolume = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
28883
28884 if(dV > cellVolume) {
28885 dV = cellVolume;
28886 // gap-Cells, for which dV needs to be limited!
28887 m_gapCells[gapCellId].status = 98;
28888 }
28889
28890 m_sweptVolume[bndryId] = dV;
28891 m_sweptVolumeDt1[bndryId] = dV;
28892
28893
28894 if(status == 22 || status == 28 || status == 29) {
28895 // reduce velocity in the cells to fit the boundary-Condition!
28896 // as the values are interpolated from non-boundary cells, this is necessary for all
28897 // new bndry-cells!
28898 MFloat delta = maia::math::deltaFun(m_volumeFraction[bndryId], F0, F1);
28899 for(MInt i = 0; i < nDim; i++) {
28900 a_pvariable(cellId, PV->VV[i]) =
28901 delta * a_pvariable(cellId, PV->VV[i])
28902 + (F1 - delta) * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->VV[i]];
28903 }
28904 setConservativeVariables(cellId);
28905 for(MInt varId = 0; varId < CV->noVariables; varId++) {
28906 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
28907 }
28908 }
28909 }
28910
28911 gapCellExchange(1);
28912
28913
28914 // Plan-B: static initialisation:
28915 // not working!
28916 /*
28917 for(MUint it = 0; it < m_gapCells.size(); it++){
28918 MInt regionId = m_gapCells[it].region;
28919 if(regionId != region) continue;
28920 MInt cellId = m_gapCells[it].cellId;
28921
28922 if(!a_isBndryCell(cellId)) continue;
28923 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
28924 if (a_hasProperty( cellId , SolverCell::IsInactive ) ) continue;
28925
28926
28927 MInt bndryId = a_bndryId( cellId );
28928 if(bndryId < -1 ) continue;
28929
28930 a_cellVolume( cellId ) = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_volume;
28931 m_cellVolumesDt1[ cellId ] = a_cellVolume( cellId );
28932 m_sweptVolumeDt1[bndryId] = 0;
28933 m_sweptVolume[bndryId] = 0;
28934 for( MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++){
28935 for( MInt i=0; i<nDim; i++ ) {
28936 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = 0;
28937 }
28938 }
28939 }
28940
28941 gapCellExchange(1);
28942 */
28943 /*
28944 if(status == 24 ) {
28945 //a bndry-Cell which was active before
28946
28947 MInt bndryId = a_bndryId( cellId );
28948 if(bndryId < -1 ) continue;
28949
28950 MFloat cellVolumes = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_volume;
28951 MFloat deltaVol = cellVolumes - m_cellVolumesDt1[ cellId ];
28952 MFloat sweptVolume = (deltaVol - (F1-m_RKalpha[ m_noRKSteps-2 ]) * m_sweptVolumeDt1[ bndryId ]) /
28953 m_RKalpha[ m_noRKSteps-2 ]; MFloat velocity = F0; MFloat dt = timeStep(true); MFloat noSurfaces = 0;
28954 MFloat surfaceVel = F0;
28955
28956 for( MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++ ){
28957
28958 surfaceVel = F0;
28959 for( MInt i = 0; i<nDim; i++) {
28960 surfaceVel += m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]];
28961 }
28962 //if(surfaceVel > 0 ) {
28963 noSurfaces++;
28964 MFloat area = m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_area;
28965 velocity -= sweptVolume / (dt*area);
28966 // }
28967 }
28968 velocity = velocity / noSurfaces;
28969
28970 cerr << "Velocity calculation: " << c_globalId(cellId) << " " << velocity << " "
28971 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->VV[0]] << " "
28972 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->VV[1]] << " "
28973 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->VV[2]] << " "
28974 << surfaceVel << endl;
28975
28976 */
28977 }
28978
28979
28980 // g0-region-velocity:
28981 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
28982 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
28983 MInt gapCellId = m_gapCellId[cellId];
28984 if(gapCellId < 0) continue;
28985
28986 const MInt regionId = m_gapCells[gapCellId].region;
28987 if(regionId != m_noGapRegions) continue;
28988
28989 MFloat vel[3];
28990 for(MInt i = 0; i < nDim; i++) {
28991 vel[i] = m_gapCells[gapCellId].surfaceVelocity[i];
28992 }
28993
28994 MFloat dV = 0;
28995 const MFloat dt = timeStep(true);
28996 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
28997 const MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
28998 for(MInt i = 0; i < nDim; i++) {
28999 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] = vel[i];
29000 //= 0;
29001 const MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
29002 dV -= dt * vel[i] * nml * area;
29003 }
29004 }
29005 if(dV * 100 / 5 > grid().gridCellVolume(a_level(cellId))) {
29006 cerr << "Large Volume change in G0-region cell! " << dV << " " << dV / m_cellVolumesDt1[cellId] << endl;
29007 }
29008 }
29009
29010 // update-Split-childs based on split-cell volumes
29011
29012 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
29013 const MInt cellId = m_splitCells[sc];
29014 if(m_gapCellId[cellId] > -1) continue;
29015 MFloat cvol = F0;
29016 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
29017 const MInt splitChildId = m_splitChilds[sc][ssc];
29018 MFloat vol = m_fvBndryCnd->m_bndryCells->a[a_bndryId(splitChildId)].m_volume;
29019 cvol += vol;
29020 a_cellVolume(splitChildId) = vol * a_cellVolume(cellId);
29021 m_cellVolumesDt1[splitChildId] = vol * m_cellVolumesDt1[cellId];
29022 }
29023 cvol = mMax(1e-15, cvol);
29024 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
29025 const MInt splitChildId = m_splitChilds[sc][ssc];
29026 a_cellVolume(splitChildId) /= cvol;
29027 m_cellVolumesDt1[splitChildId] /= cvol;
29028 }
29029 }
29030}
29031
29032
29037template <MInt nDim, class SysEqn>
29039 TRACE();
29040
29041 if(!m_levelSetMb) return;
29042
29043 ASSERT(m_temporarilyLinkedCells.size() < 1, "");
29044
29045 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29046 a_hasProperty(cellId, SolverCell::IsTempLinked) = false;
29047 }
29048
29049 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
29050 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
29051 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
29052 if(!a_hasProperty(cellId, SolverCell::WasInactive)) continue;
29053 // a) new boundary cell: was inactive before and is !inactive
29054 // -> emerging BndryCells will be linked
29055
29056 // only link the split parent cell!!
29057 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
29058
29059 // avoid double-linking
29060 if(a_hasProperty(cellId, SolverCell::IsTempLinked)) continue;
29061
29062 // initialise oldVariable, will be resetted below!
29063 for(MInt v = 0; v < m_noCVars; v++) {
29064 a_oldVariable(cellId, v) = F0;
29065 }
29066
29067 // old-version is not linking gapCells!
29068 if(m_levelSet && m_closeGaps && m_gapInitMethod == 0 && a_hasProperty(cellId, SolverCell::WasGapCell)
29069 && !a_hasProperty(cellId, SolverCell::IsGapCell)) {
29070 continue;
29071 }
29072
29073 // Ensure that azimuthal cells are not linked. Otherwise exchange is needed
29074 // Here azimuthal halos are skipped. They are not used in the time step integration
29075 // anyway
29076 if(grid().azimuthalPeriodicity() && a_isPeriodic(cellId)) continue;
29077
29078 // masterId is the the neighbour to the boundary-cell with the largest cell-volume!
29079 MInt masterId = -1;
29080 MInt tripleLink = -1;
29081 MFloat maxVol = F0;
29082 MInt noInternalNghbrs = 0;
29083 MInt noWasActiveNghbrs = 0;
29084 const MInt rootId = cellId;
29085 for(MInt dir = 0; dir < m_noDirs; dir++) {
29086 if(!checkNeighborActive(rootId, dir) || a_hasNeighbor(rootId, dir) == 0) continue;
29087 const MInt nghbrId = c_neighborId(rootId, dir);
29088 if(nghbrId < 0) continue;
29089 if(!a_isHalo(nghbrId)) noInternalNghbrs++;
29090 if(a_hasProperty(nghbrId, SolverCell::WasInactive)) continue;
29091 noWasActiveNghbrs++;
29092 if(a_hasProperty(nghbrId, SolverCell::IsSplitCell)) continue;
29093 if(a_hasProperty(nghbrId, SolverCell::IsSplitChild)) continue;
29094 if(a_cellVolume(nghbrId) > maxVol) {
29095 masterId = nghbrId;
29096 maxVol = a_cellVolume(nghbrId);
29097 }
29098 }
29099
29100
29101 if(a_isHalo(cellId) && noInternalNghbrs == 0) continue;
29102 if(masterId > -1 && a_isHalo(cellId) && a_isHalo(masterId)) continue;
29103
29104 // linking the master-cell and the boundary-cell
29105 //-> copying the masters-variables into the boundary-cell!
29106 if(masterId > -1) {
29107 m_temporarilyLinkedCells.push_back(make_tuple(cellId, masterId, tripleLink));
29108 a_hasProperty(cellId, SolverCell::IsTempLinked) = true;
29109 for(MInt v = 0; v < m_noCVars; v++) {
29110 a_variable(cellId, v) = a_variable(masterId, v);
29111 a_oldVariable(cellId, v) = a_oldVariable(masterId, v);
29112 }
29113 for(MInt v = 0; v < m_noPVars; v++) {
29114 a_pvariable(cellId, v) = a_pvariable(masterId, v);
29115 }
29116
29117 } else { // no-master found
29118
29119 // special treatment for the linking of gapCells
29120 /*
29121 if ( m_levelSet && m_closeGaps && m_gapInitMethod > 0) {
29122 // use levelSet value for masterId determination, so that the same linking is achived on
29123 // all ranks!
29124 MFloat lsValue = -99;
29125 if(m_gapCellId[cellId] > -1){
29126 if(m_gapCells[m_gapCellId[cellId]].status == 22 && false) {
29127 // 1: for initGapOpening
29128 // a) try linking new bndry-Cells(type 22) with arising gap-Cells(type21) in a double-link
29129 for ( MInt dir = 0; dir < m_noDirs; dir++ ) {
29130 if ( !checkNeighborActive (cellId , dir) || a_hasNeighbor(cellId, dir) == 0 )
29131 continue;
29132 MInt nghbrId = c_neighborId( cellId , dir );
29133 if ( nghbrId < 0 ) continue;
29134 if ( a_hasProperty( nghbrId , SolverCell::IsSplitCell ) ) continue;
29135 if ( a_hasProperty( nghbrId , SolverCell::IsSplitChild ) ) continue;
29136 if(m_gapCellId[nghbrId] > -1){
29137 if(m_gapCells[m_gapCellId[nghbrId]].status == 21) {
29138 if(a_levelSetValuesMb(nghbrId, 0) > lsValue) {
29139 masterId = nghbrId;
29140 lsValue = a_levelSetValuesMb(nghbrId, 0);
29141 ASSERT(abs(a_cellVolume(masterId) - grid().gridCellVolume(a_level(cellId))) < 0.00001, "");
29142 }
29143 }
29144 }
29145 }
29146 m_temporarilyLinkedCells.push_back( make_tuple(cellId,masterId, tripleLink) );
29147 a_hasProperty( cellId , SolverCell::IsTempLinked ) = true;
29148 for ( MInt v = 0; v < m_noVars; v++ ) {
29149 a_variable( cellId , v ) = a_variable( masterId , v );
29150 a_oldVariable( cellId , v ) = a_oldVariable( masterId , v );
29151 a_pvariable( cellId , v ) =a_pvariable( masterId , v );
29152 }
29153
29154 if(masterId < 0 ) {
29155 //b) if this is not working create a triple-link
29156 // so first find the direct neighbor with the largest cellVolume
29157 // and second, its masterId which should be an arising gap-Cell and
29158 // finish by creating the triple-link !
29159 maxVol = F0;
29160 lsValue = -99;
29161 //cerr << "Searching neighbor for " << c_globalId(cellId) << endl;
29162 for ( MInt dir = 0; dir < m_noDirs; dir++ ) {
29163 if ( !checkNeighborActive (cellId , dir) || a_hasNeighbor(cellId, dir) == 0 )
29164 continue;
29165 MInt nghbrId = c_neighborId( cellId , dir );
29166 if ( nghbrId < 0 ) continue;
29167 if ( a_hasProperty( nghbrId , SolverCell::IsSplitCell ) ) continue;
29168 if ( a_hasProperty( nghbrId , SolverCell::IsSplitChild ) ) continue;
29169 if ( a_cellVolume( nghbrId ) > maxVol ) {
29170 tripleLink = nghbrId;
29171 maxVol = a_cellVolume( nghbrId );
29172 }
29173 }
29174 if(tripleLink > 0) {
29175 if(a_isHalo(tripleLink)) {
29176
29177 }
29178
29179
29180 //cerr << " Using neighbor " << c_globalId(tripleLink) << endl;
29181 if(a_hasProperty( tripleLink , SolverCell::IsTempLinked )) {
29182 //tripleLink already has a singe-link
29183 MUint it = m_temporarilyLinkedCells.size();
29184 for( MUint it2 = 0; it2 < m_temporarilyLinkedCells.size(); it2++){
29185 if(get<0>(m_temporarilyLinkedCells[it2]) == tripleLink ) {
29186 it = it2;
29187 break;
29188 }
29189 }
29190 ASSERT(it < m_temporarilyLinkedCells.size(), "");
29191 masterId = get<1>(m_temporarilyLinkedCells[it]);
29192 //cerr << " Reusing masterId " << c_globalId(masterId) << endl;
29193 //replace the masterId, and link the two smaller cells with each other!
29194 m_temporarilyLinkedCells.erase(m_temporarilyLinkedCells.begin()+it);
29195 m_temporarilyLinkedCells.push_back( make_tuple(cellId,masterId, tripleLink) );
29196 a_hasProperty( cellId , SolverCell::IsTempLinked ) = true;
29197 for ( MInt v = 0; v < m_noVars; v++ ) {
29198 a_variable( cellId , v ) = a_variable( masterId , v );
29199 a_oldVariable( cellId , v ) = a_oldVariable( masterId , v );
29200 a_pvariable( cellId , v ) =a_pvariable( masterId , v );
29201 }
29202
29203 } else {
29204 // tipleCellId doesn't have a link on this domain yet
29205 // now, due the same procedure from the top
29206 // So firt try to find the largest wasactive neighbor,
29207 // and othwise the gapCell-Neigbor with the largest ls-Value
29208 lsValue = -99;
29209 maxVol = F0;
29210 for ( MInt dir = 0; dir < m_noDirs; dir++ ) {
29211 if ( !checkNeighborActive (rootId , dir) || a_hasNeighbor( rootId , dir ) == 0 ) continue;
29212 const MInt nghbrId = c_neighborId( rootId , dir );
29213 if ( nghbrId < 0 ) continue;
29214 if ( a_hasProperty( nghbrId , SolverCell::WasInactive ) ) continue;
29215 if ( a_hasProperty( nghbrId , SolverCell::IsSplitCell ) ) continue;
29216 if ( a_hasProperty( nghbrId , SolverCell::IsSplitChild ) ) continue;
29217 if ( a_cellVolume( nghbrId ) > maxVol ) {
29218 masterId = nghbrId;
29219 maxVol = a_cellVolume( nghbrId );
29220 }
29221 }
29222 if (masterId < 0) {
29223 for ( MInt dir = 0; dir < m_noDirs; dir++ ) {
29224 if ( !checkNeighborActive (cellId , dir) || a_hasNeighbor(cellId, dir) == 0 )
29225 continue;
29226 MInt nghbrId = c_neighborId( tripleLink , dir );
29227 if ( nghbrId < 0 ) continue;
29228 if ( a_hasProperty( nghbrId , SolverCell::IsSplitCell ) ) continue;
29229 if ( a_hasProperty( nghbrId , SolverCell::IsSplitChild ) ) continue;
29230 if(m_gapCellId[nghbrId] > -1){
29231 if(m_gapCells[m_gapCellId[nghbrId]].status == 21) {
29232 if(a_levelSetValuesMb(nghbrId, 0) > lsValue) {
29233 masterId = nghbrId;
29234 lsValue = a_levelSetValuesMb(nghbrId, 0);
29235 ASSERT(abs(a_cellVolume(masterId) - grid().gridCellVolume(a_level(cellId))) < 0.00001, "");
29236 }
29237 }
29238 }
29239 }
29240 }
29241 if(masterId < 0) {
29242 cerr << "WTF, still no master found?! " << endl;
29243 }
29244 //cerr << " Using masterId " << c_globalId(masterId) << endl;
29245 if( a_isHalo( cellId ) && a_isHalo(masterId) && a_isHalo(tripleLink)) continue;
29246 m_temporarilyLinkedCells.push_back( make_tuple(cellId,masterId, tripleLink) );
29247 a_hasProperty( cellId , SolverCell::IsTempLinked ) = true;
29248 a_hasProperty( tripleLink , SolverCell::IsTempLinked ) = true;
29249 for ( MInt v = 0; v < m_noVars; v++ ) {
29250 a_variable( cellId , v ) = a_variable( masterId , v );
29251 a_oldVariable( cellId , v ) = a_oldVariable( masterId , v );
29252 a_pvariable( cellId , v ) =a_pvariable( masterId , v );
29253
29254 a_variable(tripleLink, v ) = a_variable( masterId , v );
29255 a_oldVariable(tripleLink, v ) = a_oldVariable( masterId , v );
29256 a_pvariable(tripleLink, v ) =a_pvariable( masterId , v );
29257 }
29258 }
29259 }
29260 }
29261
29262 } else if (m_gapCells[m_gapCellId[cellId]].status == 13) {
29263 cerr << "Unlinked new bndry-Cell " << c_globalId(cellId) << endl;
29264 continue;
29265
29266 cerr << "Searching neighbor for " << c_globalId(cellId) << endl;
29267 // 2: for partial gapOpening at gapWidening
29268 // this is nesessary for new bndry-cells, where only the diagonal neighbor wasactive before
29269 // in order to avoid triple-linking the cells without a direct neighbor that wasactive
29270 // are linked to a neighbor that was inactive before!
29271 maxVol = F0;
29272 MInt largestNeighbor = F0;
29273 for ( MInt dir = 0; dir < m_noDirs; dir++ ) {
29274 if ( !checkNeighborActive (cellId , dir) || a_hasNeighbor(cellId, dir) == 0 )
29275 continue;
29276 MInt nghbrId = c_neighborId( cellId , dir );
29277 if ( nghbrId < 0 ) continue;
29278 if ( a_hasProperty( nghbrId , SolverCell::IsSplitCell ) ) continue;
29279 if ( a_hasProperty( nghbrId , SolverCell::IsSplitChild ) ) continue;
29280 if ( a_cellVolume( nghbrId ) > maxVol ) {
29281 largestNeighbor = nghbrId;
29282 maxVol = a_cellVolume( nghbrId );
29283 }
29284 }
29285 //must have at least on acvive neighbor
29286 ASSERT(largestNeighbor > 0, "");
29287 //if the largest neighbor would have been active before, a regular link would have
29288 // been possible
29289 ASSERT(a_hasProperty(largestNeighbor, SolverCell::WasInactive), "");
29290
29291 if(a_hasProperty( largestNeighbor , SolverCell::IsTempLinked )) {
29292
29293
29294 }
29295
29296
29297 if(masterId > 0) {
29298 cerr << "Creating single-link" << endl;
29299 cerr << "Found unlinked neighbor " << c_globalId(masterId) << endl;
29300 tripleLink = -1;
29301 if ( masterId > -1 && a_isHalo( cellId ) && a_isHalo(masterId) ) continue;
29302 m_temporarilyLinkedCells.push_back( make_tuple(cellId,masterId, tripleLink) );
29303 a_hasProperty( cellId , SolverCell::IsTempLinked ) = true;
29304 for ( MInt v = 0; v < m_noVars; v++ ) {
29305 a_variable( cellId , v ) = a_variable( masterId , v );
29306 a_oldVariable( cellId , v ) = a_oldVariable( masterId , v );
29307 a_pvariable( cellId , v ) =a_pvariable( masterId , v );
29308 }
29309 } else if(masterId < 0 && tripleLink > -1 ) {
29310 cerr << "Creating triple-Link" << endl;
29311 cerr << " Using neighbor " << c_globalId(tripleLink) << endl;
29312 if(a_hasProperty( tripleLink , SolverCell::IsTempLinked )) {
29313 //tripleLink already has a singe-link
29314 MUint it = m_temporarilyLinkedCells.size();
29315 for( MUint it2 = 0; it2 < m_temporarilyLinkedCells.size(); it2++){
29316 if(get<0>(m_temporarilyLinkedCells[it2]) == tripleLink ) {
29317 it = it2;
29318 break;
29319 }
29320 }
29321 if(it == m_temporarilyLinkedCells.size()){
29322 cerr << "tripleLink is already part of a triple Link " << endl;
29323 }
29324 masterId = get<1>(m_temporarilyLinkedCells[it]);
29325 cerr << " Reusing masterId " << c_globalId(masterId) << endl;
29326 m_temporarilyLinkedCells.erase(m_temporarilyLinkedCells.begin()+it );
29327 m_temporarilyLinkedCells.push_back( make_tuple(cellId,masterId, tripleLink) );
29328 a_hasProperty( cellId , SolverCell::IsTempLinked ) = true;
29329 for ( MInt v = 0; v < m_noVars; v++ ) {
29330 a_variable( cellId , v ) = a_variable( masterId , v );
29331 a_oldVariable( cellId , v ) = a_oldVariable( masterId , v );
29332 a_pvariable( cellId , v ) =a_pvariable( masterId , v );
29333 }
29334
29335 } else {
29336 //tipleCellId doesn't have a link yet
29337 maxVol = F0;
29338 for ( MInt dir = 0; dir < m_noDirs; dir++ ) {
29339 if ( !checkNeighborActive (tripleLink , dir) ||
29340 a_hasNeighbor(tripleLink, dir) == 0 ) continue;
29341 MInt nghbrId = c_neighborId( tripleLink , dir );
29342 if ( nghbrId < 0 ) continue;
29343 if ( a_hasProperty( nghbrId , SolverCell::WasInactive ) ) continue;
29344 if ( a_hasProperty( nghbrId , SolverCell::IsSplitCell ) ) continue;
29345 if ( a_hasProperty( nghbrId , SolverCell::IsSplitChild ) ) continue;
29346 if ( a_cellVolume( nghbrId ) > maxVol ) {
29347 masterId = nghbrId;
29348 maxVol = a_cellVolume( nghbrId );
29349 }
29350 }
29351 if(masterId > 0) {
29352 cerr << " Using masterId " << c_globalId(masterId) << endl;
29353 if( a_isHalo( cellId ) && a_isHalo(masterId) && a_isHalo(tripleLink)) continue;
29354 m_temporarilyLinkedCells.push_back( make_tuple(cellId,masterId, tripleLink) );
29355 a_hasProperty( cellId , SolverCell::IsTempLinked ) = true;
29356 a_hasProperty(tripleLink, SolverCell::IsTempLinked ) = true;
29357 for ( MInt v = 0; v < m_noVars; v++ ) {
29358 a_variable( cellId , v ) = a_variable( masterId , v );
29359 a_oldVariable( cellId , v ) = a_oldVariable( masterId , v );
29360 a_pvariable( cellId , v ) =a_pvariable( masterId , v );
29361
29362 a_variable(tripleLink, v ) = a_variable( masterId , v );
29363 a_oldVariable(tripleLink, v ) = a_oldVariable( masterId , v );
29364 a_pvariable(tripleLink, v ) =a_pvariable( masterId , v );
29365 }
29366 }
29367 }
29368 }
29369
29370
29371 }
29372 }
29373
29374
29375
29376 }
29377 */
29378 if(masterId < 0) {
29379 cerr << domainId() << " Still no temporary master found for emerged cell " << cellId << " "
29380 << c_globalId(cellId) << " " << a_isHalo(cellId) << " " << a_isWindow(cellId) << " "
29381 << a_hasProperty(cellId, SolverCell::IsNotGradient) << " " << noInternalNghbrs << " " << noWasActiveNghbrs
29382 << " " << a_hasProperty(cellId, SolverCell::IsSplitChild) << " " << a_levelSetValuesMb(cellId, 0) << " "
29383 << a_hasProperty(cellId, SolverCell::IsGapCell) << " " << a_hasProperty(cellId, SolverCell::WasGapCell)
29384 << " "
29385 << m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_volume / grid().gridCellVolume(a_level(cellId))
29386 << " " << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
29387 if(m_closeGaps && m_gapCellId[cellId] > 0)
29388 cerr << m_gapCellId[cellId] << " " << m_gapCells[m_gapCellId[cellId]].status << endl;
29389 }
29390 }
29391
29392 // the second-halo-layer is not linked!
29393 if(masterId < 0) {
29394 ASSERT(a_isHalo(cellId), "");
29395 ASSERT(a_hasProperty(cellId, SolverCell::IsNotGradient), "");
29396 }
29397
29398 // Do not use azimuthal halo cell as master because azimuthal halos are skipped
29399 // further above.
29400 if(grid().azimuthalPeriodicity() && a_isPeriodic(masterId)) {
29401 if(tripleLink >= 0) {
29402 mTerm(1, AT_, "Triple link with azimuthalPeriodicity");
29403 }
29404 continue;
29405 }
29406
29407
29408 // create linkedHalo- and -Window-Cells list
29409 // a) for single-links
29410 if(tripleLink < 0 && masterId > -1 && a_isHalo(cellId) != a_isHalo(masterId)) {
29411 if(c_globalId(cellId) < 0 || c_globalId(masterId) < 0) {
29412 cerr << domainId() << ": GID " << cellId << " " << masterId << " " << c_globalId(cellId) << " "
29413 << c_globalId(masterId) << " " << a_isPeriodic(cellId) << " " << a_isPeriodic(masterId) << endl;
29414 }
29415 ASSERT(c_globalId(cellId) > -1 && c_globalId(masterId) > -1, "");
29416 if(a_isHalo(cellId)) {
29417 ASSERT(a_isWindow(masterId), "");
29418 MInt ndom = grid().findNeighborDomainId(c_globalId(cellId));
29419 MInt idx = grid().domainIndex(ndom);
29420 ASSERT(neighborDomain(idx) == ndom, "");
29421 m_linkedHaloCells[idx].push_back(cellId);
29422 m_linkedWindowCells[idx].push_back(masterId);
29423 } else {
29424 // masterId is Halo-Cell
29425 ASSERT(a_isHalo(masterId), "");
29426 ASSERT(a_isWindow(cellId), "");
29427 MInt ndom = grid().findNeighborDomainId(c_globalId(masterId));
29428 MInt idx = grid().domainIndex(ndom);
29429 ASSERT(neighborDomain(idx) == ndom, "");
29430 m_linkedHaloCells[idx].push_back(masterId);
29431 m_linkedWindowCells[idx].push_back(cellId);
29432 }
29433
29434 } // b) for triple-links
29435 else if(tripleLink > -1 && masterId > -1
29436 && (a_isHalo(cellId) != a_isHalo(tripleLink) || a_isHalo(tripleLink) != a_isHalo(masterId))) {
29437 // if one of the linked Cells is a halo-Cell and the others are not!
29438 // if they are all halo-Cells, the link is handeled on the other rank!
29439
29440 ASSERT(c_globalId(cellId) > -1 && c_globalId(masterId) > -1 && c_globalId(tripleLink), "");
29441 // split triple-problmen in multiple single-link problems:
29442 // single link between: - tripleLink and masterId
29443 // - tripleLink and cellId
29444
29445 MInt ndom11 = grid().findNeighborDomainId(c_globalId(tripleLink));
29446 MInt ndom22 = grid().findNeighborDomainId(c_globalId(cellId));
29447 MInt ndom33 = grid().findNeighborDomainId(c_globalId(masterId));
29448
29449 cerr << domainId() << "Parallel Triple-Link Halo-Cells: " << c_globalId(cellId) << " " << c_globalId(tripleLink)
29450 << " " << c_globalId(masterId) << " " << a_isHalo(cellId) << " " << a_isHalo(tripleLink) << " "
29451 << a_isHalo(masterId) << " Domains " << ndom22 << " " << ndom11 << " " << ndom33 << endl;
29452
29453
29454 if(a_isHalo(tripleLink) && !a_isHalo(masterId)) {
29455 ASSERT(a_isWindow(masterId), "");
29456 MInt ndom = grid().findNeighborDomainId(c_globalId(tripleLink));
29457 MInt idx = grid().domainIndex(ndom);
29458 ASSERT(neighborDomain(idx) == ndom, "");
29459 m_linkedHaloCells[idx].push_back(tripleLink);
29460 m_linkedWindowCells[idx].push_back(masterId);
29461
29462 } else if(a_isHalo(masterId) && !a_isHalo(tripleLink)) {
29463 ASSERT(a_isWindow(tripleLink), "");
29464 MInt ndom = grid().findNeighborDomainId(c_globalId(masterId));
29465 MInt idx = grid().domainIndex(ndom);
29466 ASSERT(neighborDomain(idx) == ndom, "");
29467 m_linkedHaloCells[idx].push_back(masterId);
29468 m_linkedWindowCells[idx].push_back(tripleLink);
29469 }
29470
29471 if(a_isHalo(tripleLink) && !a_isHalo(cellId)) {
29472 ASSERT(a_isWindow(cellId), "");
29473 MInt ndom = grid().findNeighborDomainId(c_globalId(tripleLink));
29474 MInt idx = grid().domainIndex(ndom);
29475 ASSERT(neighborDomain(idx) == ndom, "");
29476 m_linkedHaloCells[idx].push_back(tripleLink);
29477 m_linkedWindowCells[idx].push_back(cellId);
29478
29479 } else if(!a_isHalo(tripleLink) && a_isHalo(cellId)) {
29480 ASSERT(a_isWindow(tripleLink), "");
29481 MInt ndom = grid().findNeighborDomainId(c_globalId(cellId));
29482 MInt idx = grid().domainIndex(ndom);
29483 ASSERT(neighborDomain(idx) == ndom, "");
29484 m_linkedHaloCells[idx].push_back(cellId);
29485 m_linkedWindowCells[idx].push_back(tripleLink);
29486 }
29487
29488 if(a_isHalo(masterId) && !a_isHalo(cellId)) {
29489 } else if(!a_isHalo(masterId) && a_isHalo(cellId)) {
29490 }
29491 }
29492 }
29493
29494 // sort by globalId to synchronize order across domains
29495 for(MInt i = 0; i < noNeighborDomains(); i++) {
29496 sort(m_linkedHaloCells[i].begin(), m_linkedHaloCells[i].end(),
29497 [this](const MInt& a, const MInt& b) { return c_globalId(a) < c_globalId(b); });
29498 sort(m_linkedWindowCells[i].begin(), m_linkedWindowCells[i].end(),
29499 [this](const MInt& a, const MInt& b) { return c_globalId(a) < c_globalId(b); });
29500 }
29501}
29502
29503
29511template <MInt nDim, class SysEqn>
29513 TRACE();
29514
29515 ASSERT(cellId >= 0, "");
29516
29517 if(!a_hasProperty(cellId, SolverCell::WasInactive)) return -1;
29518 if(a_hasProperty(cellId, SolverCell::IsInactive)) return -2;
29519
29520 MInt masterId = -1;
29521 MInt largestNeighbor = -1;
29522 MFloat maxVol = F0;
29523 MFloat maxVolActive = F0;
29524 MInt noInternalNghbrs = 0;
29525 for(MInt dir = 0; dir < m_noDirs; dir++) {
29526 if(!checkNeighborActive(cellId, dir) || a_hasNeighbor(cellId, dir) == 0) continue;
29527 const MInt nghbrId = c_neighborId(cellId, dir);
29528 if(nghbrId < 0) continue;
29529 if(a_hasProperty(nghbrId, SolverCell::IsSplitCell)) continue;
29530 if(a_hasProperty(nghbrId, SolverCell::IsSplitChild)) continue;
29531 if(a_cellVolume(nghbrId) > maxVolActive && !a_hasProperty(nghbrId, SolverCell::WasInactive)) {
29532 masterId = nghbrId;
29533 maxVolActive = a_cellVolume(nghbrId);
29534 }
29535 if(a_cellVolume(nghbrId) > maxVol) {
29536 largestNeighbor = nghbrId;
29537 maxVol = a_cellVolume(nghbrId);
29538 }
29539 }
29540
29541 if(masterId > -1) return -1;
29542 if(a_isHalo(cellId) && noInternalNghbrs == 0) return -1;
29543
29544 ASSERT(a_hasProperty(largestNeighbor, SolverCell::WasInactive), "");
29545 ASSERT(largestNeighbor > 0, "");
29546
29547 // reverse the further search!
29548 if(a_cellVolume(largestNeighbor) < a_cellVolume(cellId)) {
29549 MInt backup = cellId;
29550 cellId = largestNeighbor;
29551 largestNeighbor = backup;
29552 }
29553
29554 /*
29555 cerr << "New small gap-bndry cell is " << c_globalId(cellId)
29556 << " with volume "
29557 << m_fvBndryCnd->m_bndryCells->a[ a_bndryId( cellId ) ].m_volume /grid().gridCellVolume(a_level(cellId)) << "
29558 "
29559 << a_isHalo(cellId) << " "
29560 << a_hasProperty( cellId, Cell::IsWindow )
29561 << " largestNeighbor is " << c_globalId(largestNeighbor)
29562 << " with volume " << m_fvBndryCnd->m_bndryCells->a[ a_bndryId( largestNeighbor )
29563 ].m_volume/grid().gridCellVolume(a_level(largestNeighbor)) << " "
29564 << a_isHalo(largestNeighbor) << " "
29565 << a_hasProperty( largestNeighbor, Cell::IsWindow ) << " "
29566 << domainId()
29567 << endl;
29568 */
29569
29570 ASSERT(a_wasGapCell(largestNeighbor) || a_isGapCell(largestNeighbor), "");
29571
29572
29573 // initialise the largest-Neighbor for partial-gap-opening!
29574 const MInt region = m_gapCells[m_gapCellId[cellId]].region;
29575 ASSERT(region > -1 && region < m_noGapRegions, "");
29576 if(m_gapState[region] != 2) {
29577 // find a neighbor of the largestneighbor which was active before and initialise
29578 // the largetsNeighbor before the linking
29579
29580 // find a sourringding cell of the largestNeighbor
29581 // which was active before and initialise the largestNeighbor with its values
29582
29583
29584 // if ( a_isHalo( cellId ) && a_isHalo(largestNeighbor) ) return -1;
29585
29586 // return if the largestNeighbor is on the secondHalo-layer
29587 // and thus might not find a masterId as it might be on a different rank!
29588 if(a_isHalo(largestNeighbor) && a_hasProperty(largestNeighbor, SolverCell::IsNotGradient)) {
29589 return -1;
29590 }
29591
29592 maxVol = F0;
29593 for(MInt dir = 0; dir < m_noDirs; dir++) {
29594 if(!checkNeighborActive(largestNeighbor, dir) || a_hasNeighbor(largestNeighbor, dir) == 0) continue;
29595 MInt nghbrId = c_neighborId(largestNeighbor, dir);
29596 if(nghbrId < 0) continue;
29597 if(a_hasProperty(nghbrId, SolverCell::WasInactive)) continue;
29598 if(a_cellVolume(nghbrId) > maxVol) {
29599 masterId = nghbrId;
29600 maxVol = a_cellVolume(nghbrId);
29601 }
29602 }
29603
29604 if(masterId > -1) {
29605 for(MInt v = 0; v < m_noCVars; v++) {
29606 a_variable(largestNeighbor, v) = a_variable(masterId, v);
29607 a_oldVariable(largestNeighbor, v) = a_oldVariable(masterId, v);
29608 }
29609 for(MInt v = 0; v < m_noPVars; v++) {
29610 a_pvariable(largestNeighbor, v) = a_pvariable(masterId, v);
29611 }
29612 for(MInt v = 0; v < m_noFVars; v++) {
29613 a_rightHandSide(largestNeighbor, v) = F0;
29614 m_rhs0[largestNeighbor][v] = F0;
29615 }
29616 } else {
29617 // the largest neighbor does not have an neighbor who was active before and
29618 // can thus not be initialised!
29619 //=> new search for a different neighbor!
29620 // a) initialise neighbor with infinity variables
29621 // b) retry neighbor search from cellId to find any neighboring cell which
29622 // has an active neighbor!
29623 cerr << a_isHalo(largestNeighbor) << " " << a_isHalo(cellId) << endl;
29624 mTerm(1, AT_, "Even the largest neighbor is inactive!");
29625 }
29626 }
29627
29628
29629 if(a_isHalo(largestNeighbor)) {
29630 cerr << "Caution changing cell-property of a Halo-Cell! " << endl;
29631 // mark this cell and change the window-Cell accordingly!
29632 }
29633
29634 a_hasProperty(largestNeighbor, SolverCell::WasInactive) = false;
29635 m_oldBndryCells.insert(make_pair(largestNeighbor, F0));
29636
29637
29638 return largestNeighbor;
29639}
29640
29641
29647template <MInt nDim, class SysEqn>
29649 TRACE();
29650
29651#if defined _MB_DEBUG_ || !defined NDEBUG
29652 exchangeGapInfo();
29653 checkHaloCells(2);
29654#endif
29655
29656 if(m_gapCellExchangeInit) return;
29657 m_gapCellExchangeInit = true;
29658
29659 if(noNeighborDomains() == 0) return;
29660
29661 for(MInt i = 0; i < noNeighborDomains(); i++) {
29662 m_gapWindowCells[i].clear();
29663 m_gapHaloCells[i].clear();
29664 }
29665
29666 ScratchSpace<MInt> isGap(a_noCells(), AT_, "isGap");
29667 isGap.fill(0);
29668
29669 // 1) setup Gap-exchange:
29670 // for all Gap-Cells which are/were gapCells
29671
29672 // a) set noExchangeWindowCells and exchangeWindowCells
29673 for(MInt i = 0; i < noNeighborDomains(); i++) {
29674 ASSERT(m_gapHaloCells[i].size() == 0, "");
29675 for(MInt j = 0; j < noHaloCells(i); j++) {
29676 MInt cellId = haloCellId(i, j);
29677 if(a_wasGapCell(cellId) || a_isGapCell(cellId)) {
29678 m_gapHaloCells[i].push_back(cellId);
29679 isGap(cellId) = 1;
29680 }
29681 }
29682 }
29683
29684 MUint recvSize = maia::mpi::getBufferSize(grid().windowCells());
29685 ScratchSpace<MInt> recvBuffer(mMax(1u, recvSize), AT_, "recvBuffer");
29686 maia::mpi::reverseExchangeData(grid().neighborDomains(), grid().haloCells(), grid().windowCells(), mpiComm(),
29687 &isGap[0], &recvBuffer[0]);
29688
29689
29690 recvSize = 0;
29691 for(MInt i = 0; i < noNeighborDomains(); i++) {
29692 ASSERT(m_gapWindowCells[i].size() == 0, "");
29693 for(MInt j = 0; j < noWindowCells(i); j++) {
29694 MInt cellId = windowCellId(i, j);
29695 if(recvBuffer[recvSize]) {
29696 ASSERT(a_isGapCell(cellId) || a_wasGapCell(cellId), "");
29697 m_gapWindowCells[i].push_back(cellId);
29698 }
29699 recvSize++;
29700 }
29701 }
29702
29703// verify exchange:
29704#if defined _MB_DEBUG_ || !defined NDEBUG
29705
29706 MPI_Status statusMpi;
29707 ScratchSpace<MInt> check(a_noCells(), AT_, "isOnMaxLevel");
29708 check.fill(0);
29709
29710 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
29711 check[cellId] = 1;
29712 if(a_isGapCell(cellId)) check[cellId] = 2;
29713 if(a_wasGapCell(cellId)) check[cellId] = 3;
29714 if(a_isGapCell(cellId) && a_wasGapCell(cellId)) check[cellId] = 4;
29715 }
29716
29717 // gather
29718 for(MInt i = 0; i < noNeighborDomains(); i++) {
29719 if(m_gapWindowCells[i].empty()) continue;
29720 MInt sendBufferCounter = 0;
29721 for(MInt j = 0; j < (signed)m_gapWindowCells[i].size(); j++) {
29722 MInt cellId = m_gapWindowCells[i][j];
29723 m_sendBuffers[i][sendBufferCounter] = (MFloat)check[cellId];
29724 sendBufferCounter++;
29725 }
29726 }
29727
29728
29729 // send
29730 for(MInt i = 0; i < noNeighborDomains(); i++) {
29731 if(m_gapWindowCells[i].empty()) continue;
29732 MInt bufSize = m_gapWindowCells[i].size();
29733 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
29734 "m_sendBuffers[i]");
29735 }
29736
29737 // receive
29738 for(MInt i = 0; i < noNeighborDomains(); i++) {
29739 if(m_gapHaloCells[i].empty()) continue;
29740 MInt bufSize = m_gapHaloCells[i].size();
29741 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &statusMpi, AT_,
29742 "m_receiveBuffers[i]");
29743 }
29744 for(MInt i = 0; i < noNeighborDomains(); i++) {
29745 MPI_Wait(&g_mpiRequestMb[i], &statusMpi, AT_);
29746 }
29747
29748 // scatter
29749 for(MInt i = 0; i < noNeighborDomains(); i++) {
29750 if(m_gapHaloCells[i].empty()) continue;
29751 MInt receiveBufferCounter = 0;
29752 for(MInt j = 0; j < (signed)m_gapHaloCells[i].size(); j++) {
29753 MInt cellId = m_gapHaloCells[i][j];
29754 check[cellId] = (MInt)m_receiveBuffers[i][receiveBufferCounter];
29755 receiveBufferCounter++;
29756 }
29757 }
29758
29759 for(MInt cellId = noInternalCells(); cellId < a_noCells(); cellId++) {
29760 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) continue;
29761 if(a_isGapCell(cellId) && !a_wasGapCell(cellId))
29762 ASSERT(check[cellId] == 2, "");
29763 else if(a_wasGapCell(cellId) && !a_isGapCell(cellId))
29764 ASSERT(check[cellId] == 3, "");
29765 else if(a_isGapCell(cellId) && a_wasGapCell(cellId))
29766 ASSERT(check[cellId] == 4, "");
29767 else
29768 ASSERT(check[cellId] == 0, "");
29769 }
29770
29771
29772#endif
29773}
29774
29775
29785template <MInt nDim, class SysEqn>
29787 TRACE();
29788
29789 ASSERT(m_gapCellExchangeInit, "");
29790 if(noNeighborDomains() == 0) return;
29791
29792 MPI_Status statusMpi;
29793
29794 if(mode == 0) { // exchange of pvariables only
29795
29796 // gather
29797 for(MInt i = 0; i < noNeighborDomains(); i++) {
29798 if(m_gapWindowCells[i].empty()) continue;
29799 MInt sendBufferCounter = 0;
29800 for(MInt j = 0; j < (signed)m_gapWindowCells[i].size(); j++) {
29801 MInt cellId = m_gapWindowCells[i][j];
29802 memcpy((void*)&m_sendBuffers[i][sendBufferCounter], (void*)&a_pvariable(cellId, 0),
29803 m_dataBlockSize * sizeof(MFloat));
29804 sendBufferCounter += m_dataBlockSize;
29805 }
29806 }
29807
29808 // send
29809 for(MInt i = 0; i < noNeighborDomains(); i++) {
29810 if(m_gapWindowCells[i].empty()) continue;
29811 MInt bufSize = m_gapWindowCells[i].size() * m_dataBlockSize;
29812 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
29813 "m_sendBuffers[i]");
29814 }
29815
29816 // receive
29817 for(MInt i = 0; i < noNeighborDomains(); i++) {
29818 if(m_gapHaloCells[i].empty()) continue;
29819 MInt bufSize = m_gapHaloCells[i].size() * m_dataBlockSize;
29820 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &statusMpi, AT_,
29821 "m_receiveBuffers[i]");
29822 }
29823 for(MInt i = 0; i < noNeighborDomains(); i++) {
29824 MPI_Wait(&g_mpiRequestMb[i], &statusMpi, AT_);
29825 }
29826
29827 // scatter
29828 for(MInt i = 0; i < noNeighborDomains(); i++) {
29829 if(m_gapHaloCells[i].empty()) continue;
29830 MInt receiveBufferCounter = 0;
29831 for(MInt j = 0; j < (signed)m_gapHaloCells[i].size(); j++) {
29832 MInt cellId = m_gapHaloCells[i][j];
29833 memcpy((void*)&a_pvariable(cellId, 0), (void*)&m_receiveBuffers[i][receiveBufferCounter],
29834 m_dataBlockSize * sizeof(MFloat));
29835 receiveBufferCounter += m_dataBlockSize;
29836 }
29837 }
29838
29839 } else { // exchange wasInactive, call gapCellExchange(0), oldVariables and status
29840
29841 // exchange wasInactive
29842 {
29843 MInt reverseExchange = 0;
29844
29846 // NOTE: if the halo-Cell has status -99
29847 // (meaning that the halo-Cell is the only active neighbor for a gapCell on a rank)
29848 // then a reverse exchange is triggered
29849 // and the according-window-Cell is updated based on the haloCell state!
29850
29851 // gather
29852 for(MInt i = 0; i < noNeighborDomains(); i++) {
29853 if(m_gapWindowCells[i].empty()) continue;
29854 MInt sendBufferCounter = 0;
29855 for(MInt j = 0; j < (signed)m_gapWindowCells[i].size(); j++) {
29856 MInt cellId = m_gapWindowCells[i][j];
29857 m_sendBuffers[i][sendBufferCounter] = -F1;
29858 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
29859 m_sendBuffers[i][sendBufferCounter] = F1;
29860 }
29861 sendBufferCounter++;
29862 }
29863 }
29864
29865
29866 // send
29867 for(MInt i = 0; i < noNeighborDomains(); i++) {
29868 if(m_gapWindowCells[i].empty()) continue;
29869 MInt bufSize = m_gapWindowCells[i].size();
29870 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
29871 "m_sendBuffers[i]");
29872 }
29873
29874 // receive
29875 for(MInt i = 0; i < noNeighborDomains(); i++) {
29876 if(m_gapHaloCells[i].empty()) continue;
29877 MInt bufSize = m_gapHaloCells[i].size();
29878 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &statusMpi, AT_,
29879 "m_receiveBuffers[i]");
29880 }
29881 for(MInt i = 0; i < noNeighborDomains(); i++) {
29882 MPI_Wait(&g_mpiRequestMb[i], &statusMpi, AT_);
29883 }
29884
29885 // scatter
29886 for(MInt i = 0; i < noNeighborDomains(); i++) {
29887 if(m_gapHaloCells[i].empty()) continue;
29888 MInt receiveBufferCounter = 0;
29889 for(MInt j = 0; j < (signed)m_gapHaloCells[i].size(); j++) {
29890 const MInt cellId = m_gapHaloCells[i][j];
29891 const MInt status = m_gapCells[m_gapCellId[cellId]].status;
29892 if(status == -99) {
29893 reverseExchange = 1;
29894 receiveBufferCounter++;
29895 continue;
29896 }
29897 if(m_receiveBuffers[i][receiveBufferCounter] > 0) {
29898 a_hasProperty(cellId, SolverCell::WasInactive) = true;
29899 } else {
29900 a_hasProperty(cellId, SolverCell::WasInactive) = false;
29901 }
29902 receiveBufferCounter++;
29903 }
29904 }
29905
29906 MPI_Allreduce(MPI_IN_PLACE, &reverseExchange, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
29907 "reverseExchange");
29908
29909 if(reverseExchange > 0) {
29910 // reverse exchange on grid window+halo-cells
29911
29912 vector<MInt> updatedWindowCells;
29913
29914 // gather
29915 for(MInt i = 0; i < noNeighborDomains(); i++) {
29916 if(m_gapHaloCells[i].empty()) continue;
29917 MInt sendBufferCounter = 0;
29918 for(MInt j = 0; j < (signed)m_gapHaloCells[i].size(); j++) {
29919 MInt cellId = m_gapHaloCells[i][j];
29920 m_sendBuffers[i][sendBufferCounter] = -1.0;
29921 if(m_gapCells[m_gapCellId[cellId]].status == -99) {
29922 ASSERT(a_hasProperty(cellId, SolverCell::WasInactive) == false, "");
29923 m_sendBuffers[i][sendBufferCounter] = 2.0;
29924 }
29925 sendBufferCounter++;
29926 }
29927 }
29928
29929 // send
29930 for(MInt i = 0; i < noNeighborDomains(); i++) {
29931 if(m_gapHaloCells[i].empty()) continue;
29932 MInt bufSize = m_gapHaloCells[i].size();
29933 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
29934 "m_sendBuffers[i]");
29935 }
29936
29937 // receive
29938 for(MInt i = 0; i < noNeighborDomains(); i++) {
29939 if(m_gapWindowCells[i].empty()) continue;
29940 MInt bufSize = m_gapWindowCells[i].size();
29941 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &statusMpi, AT_,
29942 "m_receiveBuffers[i]");
29943 }
29944 for(MInt i = 0; i < noNeighborDomains(); i++) {
29945 MPI_Wait(&g_mpiRequestMb[i], &statusMpi, AT_);
29946 }
29947
29948 // scatter
29949 for(MInt i = 0; i < noNeighborDomains(); i++) {
29950 if(m_gapWindowCells[i].empty()) continue;
29951 MInt receiveBufferCounter = 0;
29952 for(MInt j = 0; j < (signed)m_gapWindowCells[i].size(); j++) {
29953 MInt cellId = m_gapWindowCells[i][j];
29954 if(m_receiveBuffers[i][receiveBufferCounter] > 1) {
29955 updatedWindowCells.push_back(cellId);
29956 }
29957 receiveBufferCounter++;
29958 }
29959 }
29960
29961 // update cell-variables in the window-Cell:
29962 for(MUint i = 0; i < updatedWindowCells.size(); i++) {
29963 MInt cellId = updatedWindowCells[i];
29964 cerr << "Updating Window-Cell " << c_globalId(cellId) << endl;
29965 MInt masterId = -1;
29966 MFloat maxVol = F0;
29967 const MInt rootId = cellId;
29968 for(MInt dir = 0; dir < m_noDirs; dir++) {
29969 if(!checkNeighborActive(rootId, dir) || a_hasNeighbor(rootId, dir) == 0) continue;
29970 const MInt nghbrId = c_neighborId(rootId, dir);
29971 if(nghbrId < 0) continue;
29972 if(a_hasProperty(nghbrId, SolverCell::WasInactive)) continue;
29973 if(a_hasProperty(nghbrId, SolverCell::IsSplitCell)) continue;
29974 if(a_hasProperty(nghbrId, SolverCell::IsSplitChild)) continue;
29975 if(a_cellVolume(nghbrId) > maxVol) {
29976 masterId = nghbrId;
29977 maxVol = a_cellVolume(nghbrId);
29978 }
29979 }
29980 if(masterId > -1) {
29981 // update variables only if the cell has a valid master!
29982 // for narror gaps it is possible, that cellId does not have
29983 // a fully emerging neighbor!
29984 for(MInt v = 0; v < m_noCVars; v++) {
29985 a_variable(cellId, v) = a_variable(masterId, v);
29986 a_oldVariable(cellId, v) = a_oldVariable(masterId, v);
29987 }
29988 for(MInt v = 0; v < m_noPVars; v++) {
29989 a_pvariable(cellId, v) = a_pvariable(masterId, v);
29990 }
29991 }
29992 for(MInt v = 0; v < m_noFVars; v++) {
29993 a_rightHandSide(cellId, v) = F0;
29994 m_rhs0[cellId][v] = F0;
29995 }
29996 a_hasProperty(cellId, SolverCell::WasInactive) = false;
29997 MInt gapCellId = m_gapCellId[cellId];
29998 MInt region = m_gapCells[gapCellId].region;
29999 ASSERT(region > -1 && region < m_noGapRegions, " ");
30000 if(m_gapState[region] == 3) {
30001 m_gapCells[gapCellId].status = 17;
30002 } else {
30003 m_gapCells[gapCellId].status = 28;
30004 }
30005 }
30006
30007 // re-reverse exchange
30008 // now, that a window-Cell has been updated,
30009 // halo-Cells on other ranks need to be updated as well!
30010
30011 // gather
30012 for(MInt i = 0; i < noNeighborDomains(); i++) {
30013 if(m_gapWindowCells[i].empty()) continue;
30014 MInt sendBufferCounter = 0;
30015 for(MInt j = 0; j < (signed)m_gapWindowCells[i].size(); j++) {
30016 MInt cellId = m_gapWindowCells[i][j];
30017 m_sendBuffers[i][sendBufferCounter] = -F1;
30018 if(a_hasProperty(cellId, SolverCell::WasInactive)) {
30019 m_sendBuffers[i][sendBufferCounter] = F1;
30020 }
30021 sendBufferCounter++;
30022 }
30023 }
30024
30025
30026 // send
30027 for(MInt i = 0; i < noNeighborDomains(); i++) {
30028 if(m_gapWindowCells[i].empty()) continue;
30029 MInt bufSize = m_gapWindowCells[i].size();
30030 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
30031 "m_sendBuffers[i]");
30032 }
30033
30034 // receive
30035 for(MInt i = 0; i < noNeighborDomains(); i++) {
30036 if(m_gapHaloCells[i].empty()) continue;
30037 MInt bufSize = m_gapHaloCells[i].size();
30038 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &statusMpi, AT_,
30039 "m_receiveBuffers[i]");
30040 }
30041 for(MInt i = 0; i < noNeighborDomains(); i++) {
30042 MPI_Wait(&g_mpiRequestMb[i], &statusMpi, AT_);
30043 }
30044
30045 // scatter
30046 for(MInt i = 0; i < noNeighborDomains(); i++) {
30047 if(m_gapHaloCells[i].empty()) continue;
30048 MInt receiveBufferCounter = 0;
30049 for(MInt j = 0; j < (signed)m_gapHaloCells[i].size(); j++) {
30050 MInt cellId = m_gapHaloCells[i][j];
30051 if(m_receiveBuffers[i][receiveBufferCounter] > 0) {
30052 a_hasProperty(cellId, SolverCell::WasInactive) = true;
30053 } else {
30054 a_hasProperty(cellId, SolverCell::WasInactive) = false;
30055 }
30056 receiveBufferCounter++;
30057 }
30058 }
30059 }
30060
30061 } // exchange of wasInactive
30062
30063 // exchange of pVariables
30064 gapCellExchange(0);
30065
30066 // exchange of oldVariables
30067
30068 // gather
30069 for(MInt i = 0; i < noNeighborDomains(); i++) {
30070 if(m_gapWindowCells[i].empty()) continue;
30071 MInt sendBufferCounter = 0;
30072 for(MInt j = 0; j < (signed)m_gapWindowCells[i].size(); j++) {
30073 MInt cellId = m_gapWindowCells[i][j];
30074 memcpy((void*)&m_sendBuffers[i][sendBufferCounter], (void*)&a_oldVariable(cellId, 0),
30075 m_dataBlockSize * sizeof(MFloat));
30076 sendBufferCounter += m_dataBlockSize;
30077 }
30078 }
30079
30080 // send
30081 for(MInt i = 0; i < noNeighborDomains(); i++) {
30082 if(m_gapWindowCells[i].empty()) continue;
30083 MInt bufSize = m_gapWindowCells[i].size() * m_dataBlockSize;
30084 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
30085 "m_sendBuffers[i]");
30086 }
30087
30088 // receive
30089 for(MInt i = 0; i < noNeighborDomains(); i++) {
30090 if(m_gapHaloCells[i].empty()) continue;
30091 MInt bufSize = m_gapHaloCells[i].size() * m_dataBlockSize;
30092 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &statusMpi, AT_,
30093 "m_receiveBuffers[i]");
30094 }
30095 for(MInt i = 0; i < noNeighborDomains(); i++) {
30096 MPI_Wait(&g_mpiRequestMb[i], &statusMpi, AT_);
30097 }
30098
30099 // scatter
30100 for(MInt i = 0; i < noNeighborDomains(); i++) {
30101 if(m_gapHaloCells[i].empty()) continue;
30102 MInt receiveBufferCounter = 0;
30103 for(MInt j = 0; j < (signed)m_gapHaloCells[i].size(); j++) {
30104 MInt cellId = m_gapHaloCells[i][j];
30105 memcpy((void*)&a_oldVariable(cellId, 0), (void*)&m_receiveBuffers[i][receiveBufferCounter],
30106 m_dataBlockSize * sizeof(MFloat));
30107 receiveBufferCounter += m_dataBlockSize;
30108 }
30109 }
30110
30111 // exchange gap-status:
30112
30113 // gather
30114 for(MInt i = 0; i < noNeighborDomains(); i++) {
30115 if(m_gapWindowCells[i].empty()) continue;
30116 MInt sendBufferCounter = 0;
30117 for(MInt j = 0; j < (signed)m_gapWindowCells[i].size(); j++) {
30118 MInt cellId = m_gapWindowCells[i][j];
30119 MInt gapCellId = m_gapCellId[cellId];
30120 m_sendBuffers[i][sendBufferCounter] = (MFloat)m_gapCells[gapCellId].status;
30121 sendBufferCounter++;
30122 }
30123 }
30124
30125
30126 // send
30127 for(MInt i = 0; i < noNeighborDomains(); i++) {
30128 if(m_gapWindowCells[i].empty()) continue;
30129 MInt bufSize = m_gapWindowCells[i].size();
30130 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &g_mpiRequestMb[i], AT_,
30131 "m_sendBuffers[i]");
30132 }
30133
30134 // receive
30135 for(MInt i = 0; i < noNeighborDomains(); i++) {
30136 if(m_gapHaloCells[i].empty()) continue;
30137 MInt bufSize = m_gapHaloCells[i].size();
30138 MPI_Recv(m_receiveBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &statusMpi, AT_,
30139 "m_receiveBuffers[i]");
30140 }
30141 for(MInt i = 0; i < noNeighborDomains(); i++) {
30142 MPI_Wait(&g_mpiRequestMb[i], &statusMpi, AT_);
30143 }
30144
30145 // scatter
30146 for(MInt i = 0; i < noNeighborDomains(); i++) {
30147 if(m_gapHaloCells[i].empty()) continue;
30148 MInt receiveBufferCounter = 0;
30149 for(MInt j = 0; j < (signed)m_gapHaloCells[i].size(); j++) {
30150 MInt cellId = m_gapHaloCells[i][j];
30151 MInt gapCellId = m_gapCellId[cellId];
30152 m_gapCells[gapCellId].status = (MInt)m_receiveBuffers[i][receiveBufferCounter];
30153 receiveBufferCounter++;
30154 }
30155 }
30156 }
30157}
30158
30159
30165template <MInt nDim, class SysEqn>
30167 TRACE();
30168
30169 NEW_TIMER_GROUP_STATIC(tg_solutionStep, "solution step");
30170 NEW_TIMER_STATIC(t_solutionStep, "time integration", tg_solutionStep);
30171 NEW_SUB_TIMER_STATIC(t_timeIntegration, "time integration", t_solutionStep);
30172 NEW_SUB_TIMER_STATIC(t_lhs, "lhs", t_timeIntegration);
30173 NEW_SUB_TIMER_STATIC(t_lhsBnd, "lhsBnd", t_timeIntegration);
30174 NEW_SUB_TIMER_STATIC(t_rhs, "rhs", t_timeIntegration);
30175 NEW_SUB_TIMER_STATIC(t_rhsBnd, "rhsBnd", t_timeIntegration);
30176
30177 RECORD_TIMER_START(t_solutionStep);
30178 RECORD_TIMER_START(t_timeIntegration);
30179
30180 // finish previous RK step for inter-leafed non-blocking
30181 if(g_splitMpiComm && m_splitMpiCommRecv) {
30182 RECORD_TIMER_START(t_lhsBnd);
30183 this->lhsBndFinish();
30184 RECORD_TIMER_STOP(t_lhsBnd);
30185
30186 RECORD_TIMER_START(t_rhs);
30187 this->rhs();
30188 RECORD_TIMER_STOP(t_rhs);
30189
30190 RECORD_TIMER_START(t_rhsBnd);
30191 this->rhsBnd();
30192 RECORD_TIMER_STOP(t_rhsBnd);
30193 }
30194 // Receive data in the next substep
30195 m_splitMpiCommRecv = true;
30196
30199 RECORD_TIMER_START(t_lhs);
30200 MBool timeStepCompleted = this->solverStep();
30201 RECORD_TIMER_STOP(t_lhs);
30202
30204 RECORD_TIMER_START(t_lhsBnd);
30205 this->lhsBnd();
30206 RECORD_TIMER_STOP(t_lhsBnd);
30207
30208 if(!g_splitMpiComm) {
30210 RECORD_TIMER_START(t_rhs);
30211 this->rhs();
30212 RECORD_TIMER_STOP(t_rhs);
30213
30215 RECORD_TIMER_START(t_rhsBnd);
30216 this->rhsBnd();
30217 RECORD_TIMER_STOP(t_rhsBnd);
30218 }
30219
30220 RECORD_TIMER_STOP(t_timeIntegration);
30221 RECORD_TIMER_STOP(t_solutionStep);
30222
30223 return timeStepCompleted;
30224}
30225
30226
30231template <MInt nDim, class SysEqn>
30233 TRACE();
30234
30235 RECORD_TIMER_START(m_timers[Timers::PreTime]);
30236
30237 if(!grid().wasAdapted()) {
30238 // If the mesh was adaped,
30239 // these calls have already been made in prepareAdaptation
30240 advanceTimeStep();
30241
30242 if(m_constructGField) {
30243 constructGFieldPredictor();
30244 } else if(!m_LsMovement) {
30245 updateBodyProperties();
30246 }
30247 }
30248
30249 // stop timer here, they are re-started in preSolutionStep for iterative runs
30250 RECORD_TIMER_STOP(m_timers[Timers::PreTime]);
30251 if(grid().wasAdapted()) {
30252 if(!isMultilevel() || isMultilevelPrimary()) {
30253 preSolutionStep(0);
30254 }
30255 } else {
30256 preSolutionStep();
30257 }
30258 RECORD_TIMER_START(m_timers[Timers::PreTime]);
30259
30260 if(m_localTS) {
30261 const MInt interval = !m_multilevel ? 500 : 100;
30262 if(globalTimeStep == (m_restartTimeStep + 1) || grid().wasAdapted() || globalTimeStep % interval == 0) {
30263 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30264 if(!m_fvBndryCnd->m_smallCellRHSCorrection) {
30265 // Q-SCC requires the same time-step in all neighboring small cells!
30266 a_localTimeStep(cellId) = timeStep() * IPOW2(maxLevel() - a_level(cellId));
30267 } else {
30268 a_localTimeStep(cellId) = computeTimeStepEulerDirectional(cellId);
30269 }
30270 }
30271 }
30272 }
30273
30274 // TODO labels: FVMB This looks like something that should have been done in the postAdaptation/Balance functions...
30275 if(grid().wasAdapted() || grid().wasBalanced()) {
30276 initCutOffBoundaryCondition();
30277 }
30278
30279 constexpr MBool dbg = false;
30280 if constexpr(dbg) {
30281 if(globalTimeStep == (m_restartTimeStep + 1)) {
30282 // count how many cells have a certain volume
30283 const MInt noVolSteps = 20;
30284 ScratchSpace<MInt> volumes(noVolSteps, AT_, "volumes");
30285 volumes.fill(0);
30286 const MFloat deltaVol = F1 / noVolSteps;
30287
30288 // write cell-volume output
30289 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30290 if(a_isHalo(cellId)) continue;
30291 if(a_isBndryGhostCell(cellId)) continue;
30292 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
30293 if(!a_isBndryCell(cellId)) continue;
30294
30295 const MFloat vFrac = a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId));
30296 const MInt pos = floor(vFrac / deltaVol);
30297 /* if(pos > noVolSteps - 1) continue; */
30298 volumes(pos)++;
30299 }
30300
30301 // Add from different ranks
30302 MPI_Allreduce(MPI_IN_PLACE, &volumes(0), noVolSteps, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "volumes");
30303
30304 // Write the file
30305 if(domainId() == 0) {
30306 FILE* datei;
30307 struct stat buffer;
30308 std::string name = "Volumes_" + to_string(solverId());
30309 const char* cstr = name.c_str();
30310 if(stat(cstr, &buffer) == 0) {
30311 rename(cstr, "Volumes_BAK");
30312 }
30313 datei = fopen(cstr, "w");
30314 fprintf(datei, "%s", "# 1:volLower 2:volUpper 3:count \n");
30315 for(MInt i = 0; i < noVolSteps; i++) {
30316 const MFloat volLimit1 = i * deltaVol;
30317 const MFloat volLimit2 = i * deltaVol + deltaVol;
30318 fprintf(datei, "%.8g", volLimit1);
30319 fprintf(datei, " %.8g", volLimit2);
30320 fprintf(datei, " %d", volumes(i));
30321 fprintf(datei, "\n");
30322 }
30323 fclose(datei);
30324 }
30325 }
30326 }
30327
30328 m_splitMpiCommRecv = false;
30329
30331
30332 RECORD_TIMER_STOP(m_timers[Timers::PreTime]);
30333}
30334
30335
30340template <MInt nDim, class SysEqn>
30342 TRACE();
30343
30344 RECORD_TIMER_START(m_timers[Timers::PostTime]);
30345
30346 // finish last RK-step for inter-leaved non-blocking
30347 if(g_splitMpiComm && m_splitMpiCommRecv) {
30348 this->lhsBndFinish();
30349 m_splitMpiCommRecv = false;
30350
30351 this->rhs();
30352
30353 this->rhsBnd();
30354 }
30355
30356
30357 // NOTE: meaning base or instrastep execution recipe!
30358 if(m_maxIterations == 1) {
30359 RECORD_TIMER_STOP(m_timers[Timers::PostTime]);
30360 postSolutionStep();
30361 RECORD_TIMER_START(m_timers[Timers::PostTime]);
30362 }
30363
30364 m_forceAdaptation = adaptationTrigger();
30365
30366
30367 if(isMultilevelLowestSecondary()) {
30368 prepareNextTimeStep();
30369 }
30370
30371 RECORD_TIMER_STOP(m_timers[Timers::PostTime]);
30372}
30373
30374
30379template <MInt nDim, class SysEqn>
30381 TRACE();
30382
30383 ASSERT(m_constructGField, "Wrong function to call for m_constructGField = false!");
30384
30385 m_complexBoundary = Context::getSolverProperty<MBool>("complexBoundaryForMb", m_solverId, AT_, &m_complexBoundary);
30386
30387 m_buildCollectedLevelSetFunction = Context::getSolverProperty<MBool>("buildCollectedLevelSetFunction", m_solverId,
30388 AT_, &m_buildCollectedLevelSetFunction);
30389
30390 // necessary Dat from the fvmb-solver:
30391
30392 MInt noPeriodicDirs = 0;
30393 for(MInt dir = 0; dir < nDim; dir++) {
30394 if(grid().periodicCartesianDir(dir)) noPeriodicDirs++;
30395 }
30396
30397 if(m_complexBoundary) {
30398 mAlloc(m_bodyToSetTable, m_noEmbeddedBodies, "m_bodyToSetTable", 0, AT_);
30399 mAlloc(m_noBodiesInSet, m_noLevelSetsUsedForMb, "m_noBodiesInSet", 0, AT_);
30400 mAlloc(m_setToBodiesTable, m_noLevelSetsUsedForMb, m_noEmbeddedBodies, "m_setToBodiesTable", 0, AT_);
30401
30402 if(!m_buildCollectedLevelSetFunction) {
30403 m_noSets = 1;
30404 m_startSet = 0;
30405 for(MInt i = 0; i < m_noEmbeddedBodies; i++) {
30406 m_bodyToSetTable[i] = 0;
30407 m_setToBodiesTable[0][m_noBodiesInSet[0]] = i;
30408 m_noBodiesInSet[0]++;
30409 }
30410 } else if(m_buildCollectedLevelSetFunction) {
30411 m_startSet = 1;
30412 m_noSets = mMin(m_noLevelSetsUsedForMb, m_noEmbeddedBodies + m_startSet);
30413 if(m_noSets > m_noLevelSetsUsedForMb)
30414 mTerm(1, AT_, "Too many bodies for mode 1, m_noSets would be higher than m_noLevelSetsUsedForMb!");
30415 for(MInt i = 0; i < m_noEmbeddedBodies; i++) {
30416 MInt id = m_startSet + i % (m_noLevelSetsUsedForMb - 1);
30417 m_bodyToSetTable[i] = id;
30418 m_setToBodiesTable[id][m_noBodiesInSet[id]] = i;
30419 m_noBodiesInSet[id]++;
30420 }
30421 m_noBodiesInSet[0] = 0;
30422 for(MInt i = 0; i < m_noEmbeddedBodies; i++) {
30423 m_setToBodiesTable[0][m_noBodiesInSet[0]] = i;
30424 m_noBodiesInSet[0]++;
30425 }
30426 }
30427
30428 if((m_maxNoEmbeddedBodiesPeriodic > m_noEmbeddedBodies) /*|| ( m_noBodiesInSet == nullptr )*/) {
30429 if(!m_buildCollectedLevelSetFunction) mTerm(1, AT_, "This case is unknown.");
30430 mDeallocate(m_bodyToSetTable);
30431 mDeallocate(m_noBodiesInSet);
30432 mDeallocate(m_setToBodiesTable);
30433 mAlloc(m_bodyToSetTable, m_maxNoEmbeddedBodiesPeriodic, "m_bodyToSetTable", 0, AT_);
30434 mAlloc(m_noBodiesInSet, m_noLevelSetsUsedForMb, "m_noBodiesInSet", 0, AT_);
30435 mAlloc(m_setToBodiesTable, m_noLevelSetsUsedForMb, m_maxNoEmbeddedBodiesPeriodic, "m_setToBodiesTable", 0, AT_);
30436
30437 for(MInt i = 0; i < m_noLevelSetsUsedForMb; i++) {
30438 for(MInt j = 0; j < m_maxNoEmbeddedBodiesPeriodic; j++)
30439 m_setToBodiesTable[i][j] = 0;
30440 m_noBodiesInSet[i] = 0;
30441 }
30442 m_noBodiesInSet[0] = 0;
30443 for(MInt i = 0; i < m_noEmbeddedBodies; i++) {
30444 m_setToBodiesTable[0][m_noBodiesInSet[0]] = i;
30445 m_bodyToSetTable[i] = 0;
30446 m_noBodiesInSet[0]++;
30447 }
30448 m_startSet = 1;
30449 m_noSets = mMin(m_noLevelSetsUsedForMb, m_noEmbeddedBodies + m_startSet);
30450 if(m_noSets > m_noLevelSetsUsedForMb)
30451 mTerm(1, AT_, "Too many bodies for mode 0, m_noSets would be higher than m_noLevelSetsUsedForMb!");
30452 for(MInt i = 0; i < m_noLevelSetsUsedForMb; i++) {
30453 for(MInt j = 0; j < m_maxNoEmbeddedBodiesPeriodic; j++)
30454 m_setToBodiesTable[i][j] = 0;
30455 m_noBodiesInSet[i] = 0;
30456 }
30457 for(MInt i = 0; i < m_noEmbeddedBodies; i++) {
30458 MInt id = m_startSet + i % (m_noLevelSetsUsedForMb - 1);
30459 m_bodyToSetTable[i] = id;
30460 m_setToBodiesTable[id][m_noBodiesInSet[id]] = i;
30461 m_noBodiesInSet[id]++;
30462 }
30463 m_noBodiesInSet[0] = 0;
30464 for(MInt i = 0; i < m_noEmbeddedBodies; i++) {
30465 m_setToBodiesTable[0][m_noBodiesInSet[0]] = i;
30466 m_noBodiesInSet[0]++;
30467 }
30468 }
30469 } else {
30470 if(m_bodyToSetTable == nullptr) mAlloc(m_bodyToSetTable, m_maxNoEmbeddedBodiesPeriodic, "m_bodyToSetTable", 0, AT_);
30471 if(m_noBodiesInSet == nullptr) mAlloc(m_noBodiesInSet, m_noLevelSetsUsedForMb, "m_noBodiesInSet", 0, AT_);
30472 if(m_setToBodiesTable == nullptr)
30473 mAlloc(m_setToBodiesTable, m_noLevelSetsUsedForMb, m_maxNoEmbeddedBodiesPeriodic, "m_noBodiesInSet", 0, AT_);
30474 m_noSets = 1;
30475 m_startSet = 0;
30476 for(MInt i = 0; i < m_noLevelSetsUsedForMb; i++) {
30477 for(MInt j = 0; j < m_maxNoEmbeddedBodiesPeriodic; j++)
30478 m_setToBodiesTable[i][j] = 0;
30479 m_noBodiesInSet[i] = 0;
30480 }
30481 m_noBodiesInSet[0] = 0;
30482 for(MInt i = 0; i < m_noEmbeddedBodies; i++) {
30483 m_setToBodiesTable[0][m_noBodiesInSet[0]] = i;
30484 m_bodyToSetTable[i] = 0;
30485 m_noBodiesInSet[0]++;
30486 }
30487 }
30488
30489 if(m_noSets > 0 && domainId() == 0) {
30490 m_log << " m_noSets: " << m_noSets << endl;
30491 m_log << " start set: " << m_startSet << endl;
30492 m_log << " m_bodyToSetTable: ";
30493 for(MInt i = 0; i < mMin(m_noEmbeddedBodies, 10); i++)
30494 m_log << " " << m_bodyToSetTable[i];
30495 m_log << endl;
30496 m_log << " m_noBodiesInSet: ";
30497 for(MInt i = 0; i < m_noLevelSetsUsedForMb; i++)
30498 m_log << " " << m_noBodiesInSet[i];
30499 m_log << endl;
30500 m_log << " m_setToBodiesTable: ";
30501 for(MInt i = 0; i < m_noLevelSetsUsedForMb; i++) {
30502 m_log << " s" << i << ": ";
30503 for(MInt j = 0; j < m_noBodiesInSet[i]; j++)
30504 m_log << " " << m_setToBodiesTable[i][j];
30505 }
30506 m_log << endl;
30507 }
30508}
30509
30510
30514template <MInt nDim, class SysEqn>
30516 TRACE();
30517
30518 m_geometryIntersection->m_noEmbeddedBodies = m_noEmbeddedBodies;
30519 m_geometryIntersection->m_noLevelSetsUsedForMb = m_noLevelSetsUsedForMb;
30520 m_geometryIntersection->m_bodyToSetTable = m_bodyToSetTable;
30521 m_geometryIntersection->m_setToBodiesTable = m_setToBodiesTable;
30522 m_geometryIntersection->m_noBodiesInSet = m_noBodiesInSet;
30523}
30524
30525
30529template <MInt nDim, class SysEqn>
30531 TRACE();
30532
30533 advanceSolution();
30534 advanceBodies();
30535}
30536
30537
30547template <MInt nDim, class SysEqn>
30549 TRACE();
30550
30551 NEW_TIMER_GROUP(t_initTimer, "initSolutionStep");
30552 NEW_TIMER(t_timertotal, "initSolutionStep", t_initTimer);
30553 NEW_SUB_TIMER(t_init, "init", t_timertotal);
30554 NEW_SUB_TIMER(t_createBnd, "createBoundaryCells", t_timertotal);
30555 NEW_SUB_TIMER(t_initBnd, "initBoundaryCells", t_timertotal);
30556 NEW_SUB_TIMER(t_stencil, "buildStencil", t_timertotal);
30557 NEW_SUB_TIMER(t_surfaces, "createSurfaces", t_timertotal);
30558 NEW_SUB_TIMER(t_initSurfaces, "initSurfaces", t_timertotal);
30559 NEW_SUB_TIMER(t_finalize, "finalize", t_timertotal);
30560 RECORD_TIMER_START(t_timertotal);
30561 RECORD_TIMER_START(t_init);
30562
30563 grid().updateGridInfo();
30564 if(m_fvBndryCnd->m_cellCoordinatesCorrected) m_fvBndryCnd->recorrectCellCoordinates();
30565
30566 MBool& frstrn = m_static_initSolutionStep_frstrn;
30567 if(mode == -1) {
30568 // should only be called once!
30569 ASSERT(frstrn, "");
30570 ASSERT(!m_onlineRestart, "");
30571 } else if(mode == 1) {
30572 ASSERT(m_onlineRestart, "");
30573 } else {
30574 ASSERT(!m_onlineRestart, "");
30575 }
30576 frstrn = false;
30577
30578 if(!m_restart && mode < 1) {
30579 if(m_constructGField && m_bodyTypeMb) {
30580 constructGField();
30581 }
30582 m_bndryGhostCellsOffset = a_noCells();
30583 }
30584
30585 exchangeLevelSetData();
30586 setCellProperties();
30587
30588 RECORD_TIMER_STOP(t_init);
30589 RECORD_TIMER_START(t_createBnd);
30590
30591 setLevelSetMbCellProperties();
30592
30593 IF_CONSTEXPR(nDim == 3) {
30594 if(m_noPointParticles > 0) {
30595 initBodyProperties();
30596 }
30597 }
30598
30599 // initialise cell-volume for all cells for firstRun
30600 // do not reset cellVolumes at balance, the volume has been exchanged!
30601 if(mode < 1) {
30602 computeCellVolumes();
30603 }
30604
30605 // generates the outer-boundary-Cells
30606 generateBndryCells();
30607 m_noOuterBndryCells = m_fvBndryCnd->m_bndryCells->size();
30608 IF_CONSTEXPR(nDim == 3) { checkCells(); }
30609
30610 for(MInt bndryId = 0; bndryId < m_noOuterBndryCells; bndryId++) {
30611 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
30612 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
30613 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
30614 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = a_cellVolume(cellId);
30615 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
30616 m_sweptVolume[bndryId] = F0;
30617 m_sweptVolumeDt1[bndryId] = F0;
30618 }
30619 // NOTE: m_cellVolumesDt1 is set correctly for all cells below!
30620
30621 if(m_restart) {
30622 if(m_dualTimeStepping) {
30623 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30624 for(MInt varId = 0; varId < CV->noVariables; varId++) {
30625 a_dt2Variable(cellId, varId) = a_variable(cellId, varId);
30626 a_dt1Variable(cellId, varId) = a_variable(cellId, varId);
30627 }
30628 }
30629 }
30630 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30631 for(MInt varId = 0; varId < CV->noVariables; varId++) {
30632 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
30633 }
30634 }
30635 }
30636
30637
30638 // shift cell center of boundary cells
30639 m_fvBndryCnd->correctCellCoordinates();
30640
30641 // MULTILEVEL
30642 // correct (xyz)cc and body surfaces of coarse boundary cells
30643 // requires that small and master cells are not yet merged!
30644 m_fvBndryCnd->correctCoarseBndryCells();
30645 m_fvBndryCnd->m_smallBndryCells->setSize(0);
30646
30647 RECORD_TIMER_STOP(t_createBnd);
30648 RECORD_TIMER_START(t_initBnd);
30649
30650 if(m_fvBndryCnd->m_cellMerging) {
30651 // detects small cells and identifies a master cell for each
30652 // merges master and small cell(s)
30653 m_fvBndryCnd->detectSmallBndryCells();
30654 m_log << "Connecting master and slave cells...";
30655 m_fvBndryCnd->mergeCells();
30656 m_log << "ok" << endl;
30657 } else {
30658 m_fvBndryCnd->setBCTypes();
30659 m_fvBndryCnd->setNearBoundaryRecNghbrs();
30660 m_fvBndryCnd->computeImagePointRecConst();
30661 if(m_fvBndryCnd->m_smallCellRHSCorrection) {
30662 m_fvBndryCnd->initSmallCellRHSCorrection();
30663 } else {
30664 m_fvBndryCnd->initSmallCellCorrection();
30665 }
30666 }
30667
30668
30669 // write out centerline data
30670 if(m_writeOutData) {
30671 cerr << "Writing out center line data" << endl;
30672 stringstream fileNameCL;
30673 fileNameCL << "centerlineData";
30674 fileNameCL << "_" << domainId();
30675 writeCenterLineVel((fileNameCL.str()).c_str());
30676 mTerm(0, AT_);
30677 }
30678
30679 RECORD_TIMER_STOP(t_initBnd);
30680
30681 RECORD_TIMER_START(t_surfaces);
30682 m_log << "create initial surfaces...";
30683 createInitialSrfcs();
30684 m_initialSurfacesOffset = a_noSurfaces();
30685 m_log << "ok" << endl;
30686 RECORD_TIMER_STOP(t_surfaces);
30687
30688 RECORD_TIMER_START(t_stencil);
30689 setOuterBoundaryGhostCells();
30690 setOuterBoundarySurfaces();
30691 m_noOuterBoundarySurfaces = m_fvBndryCnd->m_noBoundarySurfaces;
30692
30693 m_log << "Tagging cells needed for the surface flux computation...";
30694 tagCellsNeededForSurfaceFlux();
30695 m_log << "ok" << endl;
30696
30697 // TODO labels:FVMB Check if this is necessary in 2D; Testcases pass also if setUpwindCoefficient() is not
30698 // called here
30699
30700 IF_CONSTEXPR(nDim == 2) {
30701 m_log << "Setting upwind coefficient...";
30702 setUpwindCoefficient(); // overrides value of restoreSurfaces()
30703 m_log << "ok" << endl;
30704 }
30705
30706 m_log << "Computing plane vectors...";
30707 m_fvBndryCnd->computePlaneVectors();
30708 m_log << "ok" << endl;
30709
30710 setCellProperties();
30711 if(m_useCentralDifferencingSlopes) {
30712 determineStructuredCells();
30713 }
30714
30715 m_log << "Initializing the least-squares reconstruction...";
30716 // builds the least-squares stencil and computes the LS constants
30717 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30718 a_hasProperty(cellId, SolverCell::IsActive) = true;
30719 }
30720 if(m_fvBndryCnd->m_cellMerging) {
30721 // set the neighbor arrays m_storeNghbrIds, m_identNghbrIds
30722 findNghbrIds();
30723 buildLeastSquaresStencilSimple();
30724 mDeallocate(m_storeNghbrIds);
30725 mDeallocate(m_identNghbrIds);
30726 }
30727 m_log << "ok" << endl;
30728
30729 // used for solution output!
30730 IF_CONSTEXPR(nDim == 3) {
30731 if(m_extractedCells != nullptr) {
30732 delete m_extractedCells;
30733 m_extractedCells = nullptr;
30734 } else if(m_gridPoints != nullptr) {
30735 delete m_gridPoints;
30736 m_gridPoints = nullptr;
30737 }
30738 }
30739
30740 m_log << "Initializing the viscous flux computation...";
30741 initViscousFluxComputation();
30742 m_log << "ok" << endl;
30743
30744 // initialize the reconstruction scheme for the boundary and ghost cells
30745 if(m_fvBndryCnd->m_cellMerging) {
30746 m_log << "Initializing boundary conditions...";
30747 findNghbrIds();
30748 m_fvBndryCnd->initBndryCnds();
30749 mDeallocate(m_storeNghbrIds);
30750 mDeallocate(m_identNghbrIds);
30751 m_log << "ok" << endl;
30752 } else {
30753 m_fvBndryCnd->setBCTypes();
30754 }
30755
30756 // initCutOffBoundaryCondition();
30757
30758#ifndef NDEBUG
30759 // NOTE: at this point cellVolumeDt1 is not correct on halo-cells, but set correctly below!
30760 checkHaloCells(3);
30761#endif
30762
30763 m_log << "Computing reconstruction constants...";
30764 // Computes the reconstruction constants for each cell
30765 computeReconstructionConstants();
30766 m_log << "ok" << endl;
30767 RECORD_TIMER_STOP(t_stencil);
30768
30769 if(grid().azimuthalPeriodicity()) {
30770 initAzimuthalReconstruction();
30771 computeAzimuthalReconstructionConstants();
30772 MUint noWindows = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
30773 m_azimuthalWasNearBndryIds.clear();
30774 m_azimuthalWasNearBndryIds.assign(noWindows, -1);
30775 if(mode == 1) cutOffBoundaryCondition();
30776 }
30777 RECORD_TIMER_START(t_initSurfaces);
30778 initializeMaxLevelExchange();
30779
30780#if defined _MB_DEBUG_ || !defined NDEBUG
30781 // In debug mode exhange() calls maxResidual(), which fails if RHS
30782 // is not set to 0 during init call (contains nans otherwise)
30783 resetRHS();
30784#endif
30785
30786 if(grid().azimuthalPeriodicity()) {
30787 if(mode == 1) {
30788 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
30789 // computePV() is called during loadBalance but RHO is 0 for these cells therefore computePV() results in nans.
30790 for(MInt v = 0; v < PV->noVariables; v++) {
30791 if(!(a_pvariable(cellId, v) >= F0 || a_pvariable(cellId, v) < F0) || std::isnan(a_pvariable(cellId, v))) {
30792 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
30793 mTerm(1, "This should only occur for non-leaf cells!");
30794 }
30795 a_pvariable(cellId, v) = F0;
30796 }
30797 }
30798 }
30799 }
30800 exchangeAll(); // Just so that halo cells on lower levels do not contain nans.
30801 } else {
30802 exchange();
30803 }
30804
30805 computeCellSurfaceDistanceVectors();
30806
30807 // reset m_bndryCandidateIds
30808 m_bndryCandidateIds.clear();
30809 for(MInt i = 0; i < m_bndryGhostCellsOffset; i++) {
30810 m_bndryCandidateIds.push_back(-1);
30811 }
30812 m_bndryCandidates.clear();
30813 m_noBndryCandidates = 0;
30814
30815 MBool found = false;
30816 for(MInt bc = 0; bc < m_fvBndryCnd->m_noBndryCndIds; bc++) {
30817 if(m_fvBndryCnd->m_bndryCndIds[bc] == m_movingBndryCndId) found = true;
30818 }
30819 if(!found) {
30820 m_fvBndryCnd->m_bndryCndIds[m_fvBndryCnd->m_noBndryCndIds] = m_movingBndryCndId;
30821 m_fvBndryCnd->m_noBndryCndIds++;
30822 m_vtuGeometryOutput.insert(m_movingBndryCndId);
30823 m_log << "Added moving boundary condition " << m_movingBndryCndId << endl;
30824 }
30825 m_fvBndryCnd->createBndryCndHandler();
30826
30827 for(MInt i = 0; i < a_noCells(); i++) {
30828 a_hasProperty(i, SolverCell::NearWall) = false;
30829 }
30830
30831 // Is the following really necessary? Testcases seem to also work without
30832 IF_CONSTEXPR(nDim == 2) {
30833 m_fvBndryCnd->recorrectCellCoordinates();
30834 const MFloat signStencil[4][2] = {{-F1, -F1}, {F1, -F1}, {-F1, F1}, {F1, F1}};
30835 MFloat tmpPoint[nDim];
30836 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
30837 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
30838 for(MInt p = 0; p < m_noCellNodes; p++) {
30839 for(MInt i = 0; i < nDim; i++) {
30840 tmpPoint[i] = a_coordinate(cellId, i) + signStencil[p][i] * F1B2 * c_cellLengthAtLevel(a_level(cellId));
30841 }
30842 m_pointIsInside[bndryId][IDX_LSSETMB(p, 0)] = m_geometry->pointIsInside(tmpPoint);
30843 }
30844 }
30845 m_fvBndryCnd->rerecorrectCellCoordinates();
30846 }
30847
30848 MBool& firstRun = m_static_initSolutionStep_firstRun;
30849 if(m_restart) firstRun = true;
30850 if(firstRun) {
30851 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30852 m_cellVolumesDt1[cellId] = a_cellVolume(cellId);
30853 if(m_dualTimeStepping) m_cellVolumesDt2[cellId] = a_cellVolume(cellId);
30854 }
30855 firstRun = false;
30856 }
30857
30858 RECORD_TIMER_STOP(t_initSurfaces);
30859 RECORD_TIMER_START(t_finalize);
30860
30861#ifndef NDEBUG
30862 m_log << "_________________________________________________________________" << endl << endl;
30863 m_log << "Grid summary after clean initialization:" << endl;
30864 m_log << "_________________________________________________________________" << endl << endl;
30865 m_log << setfill(' ');
30866 m_log << "number of cells " << setw(7) << a_noCells() << endl;
30867 m_log << "number of surfaces " << setw(7) << a_noSurfaces() << endl;
30868 m_log << "number of small cells " << setw(7) << m_fvBndryCnd->m_smallBndryCells->size() << endl;
30869 m_log << "minimum grid level " << setw(7) << minLevel() << endl;
30870 m_log << "maximum grid level " << setw(7) << maxLevel() << endl << endl;
30871 m_log << "level | total no cells | no of leaf cells | ghost cells" << endl;
30872
30873 MInt total = 0, leaf = 0, ghost = 0;
30874 for(MInt level = maxLevel(); level >= minLevel(); level--) {
30875 total = 0;
30876 leaf = 0;
30877 ghost = 0;
30878 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30879 if(a_isBndryGhostCell(cellId)) {
30880 if(a_level(cellId) == level) {
30881 total++;
30882 leaf++;
30883 ghost++;
30884 }
30885 } else if(a_level(cellId) == level) {
30886 total++;
30887 if(c_isLeafCell(cellId)) {
30888 leaf++;
30889 }
30890 }
30891 }
30892 m_log << setfill(' ');
30893 m_log << setw(3) << level << " " << setw(12) << total << " " << setw(16) << leaf << " " << setw(14) << ghost
30894 << endl;
30895 }
30896
30897 // check domain boundaries
30898 MInt noCells = noInternalCells();
30899 MFloat cellLength = NAN;
30900 MFloat maxC[3] = {-10000.0, -10000.0, -10000.0};
30901 MFloat minC[3] = {10000.0, 10000.0, 10000.0};
30902 for(MInt c = 0; c < noCells; c++) {
30903 if(!a_hasProperty(c, SolverCell::IsOnCurrentMGLevel)) continue;
30904 if(a_isHalo(c)) continue;
30905 if(a_isPeriodic(c)) continue;
30906 cellLength = c_cellLengthAtCell(c);
30907 for(MInt i = 0; i < nDim; i++) {
30908 maxC[i] = mMax(maxC[i], a_coordinate(c, i) + F1B2 * cellLength);
30909 minC[i] = mMin(minC[i], a_coordinate(c, i) - F1B2 * cellLength);
30910 }
30911 }
30912 m_log << "_________________________________________________________________" << endl << endl;
30913
30914 m_log << "Physical domain boundaries: " << endl;
30915 m_log << "min (x,y" << (nDim == 3 ? ",z): (" : "): (") << minC[0] << "," << minC[1];
30916 IF_CONSTEXPR(nDim == 3) m_log << "," << minC[2];
30917 m_log << ")" << endl;
30918 m_log << "max (x,y" << (nDim == 3 ? ",z): (" : "): (") << maxC[0] << "," << maxC[1];
30919 IF_CONSTEXPR(nDim == 3) m_log << "," << maxC[2];
30920 m_log << ")" << endl;
30921
30922 m_log << "_________________________________________________________________" << endl << endl;
30923#endif
30924
30925 m_log << "Process " << domainId() << " finished FV-MB initialization at time step " << globalTimeStep << endl;
30926
30927 if(domainId() == 0 || domainId() == noDomains() - 1)
30928 cerr << "Process " << domainId() << " finished FV-MB initialization at time step " << globalTimeStep << endl;
30929
30930 m_log << endl << endl;
30931
30932 RECORD_TIMER_STOP(t_finalize);
30933 RECORD_TIMER_STOP(t_timertotal);
30934 DISPLAY_TIMER(t_timertotal);
30935}
30936
30937
30942template <MInt nDim, class SysEqn>
30944 TRACE();
30945
30946 const MInt noSrfcs = a_noSurfaces();
30947 const MInt surfaceVarMemory = m_surfaceVarMemory;
30948 const MInt slopeMemory = m_slopeMemory;
30949 auto* surfaceVar = (MFloat*)(&(a_surfaceVariable(0, 0, 0)));
30950 auto* cellSlopes = (MFloat*)(&(a_slope(0, 0, 0)));
30951 auto* dx = (MFloat*)(&(a_surfaceDeltaX(0, 0)));
30952
30953#ifdef _MB_DEBUG_
30954 MInt blk = -1;
30955 MInt sfc = 22564;
30956#endif
30957
30958 MInt va0 = surfaceVarMemory * noSrfcs;
30959 MInt va1 = va0 + m_noPVars;
30960 MInt i = 2 * nDim * noSrfcs;
30961 for(MInt srfcId = noSrfcs; srfcId--;) {
30962 va0 -= surfaceVarMemory;
30963 va1 -= surfaceVarMemory;
30964 i -= 2 * nDim;
30965
30966 {
30967 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
30968 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
30969
30970 MInt sl0 = nghbr0 * slopeMemory;
30971 MInt sl1 = nghbr1 * slopeMemory;
30972
30973 for(MInt varId = 0; varId < m_noPVars; varId++) {
30974//#define _MINMOD_LIMITER_
30975#ifdef _MINMOD_LIMITER_
30976 IF_CONSTEXPR(nDim == 2) {
30977 mTerm(1, "This part has never been used in 2D. If you know it is working properly remove this!");
30978 }
30979 MFloat vmin0 = 9999.9;
30980 MFloat vmax0 = -9999.9;
30981 MFloat vmin1 = 9999.9;
30982 MFloat vmax1 = -9999.9;
30983 MFloat phi0 = F1;
30984 MFloat phi1 = F1;
30985 if(a_surfaceBndryCndId(srfcId) < 0) {
30986 for(MInt dir = 0; dir < m_noDirs; dir++) {
30987 if(a_hasNeighbor(nghbr0, dir) > 0) {
30988 MInt nghbrId = c_neighborId(nghbr0, dir);
30989 if(!a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) continue;
30990
30991 vmax0 = mMax(vmax0, a_pvariable(nghbrId, varId));
30992 }
30993 if(a_hasNeighbor(nghbr1, dir) > 0) {
30994 MInt nghbrId = c_neighborId(nghbr1, dir);
30995 if(!a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) continue;
30996 vmin1 = mMin(vmin1, a_pvariable(nghbrId, varId));
30997 vmax1 = mMax(vmax1, a_pvariable(nghbrId, varId));
30998 }
30999 }
31000 for(MInt dir = 0; dir < m_noDirs; dir++) {
31001 if(a_hasNeighbor(nghbr0, dir) > 0) {
31002 MInt nghbrId = c_neighborId(nghbr0, dir);
31003 if(!a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) continue;
31004 MFloat dv = F0;
31005 for(MInt j = 0; j < nDim; j++) {
31006 dv += (a_coordinate(nghbrId, j) - a_coordinate(nghbr0, j)) * a_slope(nghbr0, varId, j);
31007 }
31008 if(a_pvariable(nghbr0, varId) + dv < vmin0 || a_pvariable(nghbr0, varId) + dv > vmax0) {
31009 phi0 = mMin(phi0, mMax(F0, (a_pvariable(nghbrId, varId) - a_pvariable(nghbr0, varId)) / dv));
31010 }
31011 }
31012 if(a_hasNeighbor(nghbr1, dir) > 0) {
31013 MInt nghbrId = c_neighborId(nghbr1, dir);
31014 if(!a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) continue;
31015 MFloat dv = F0;
31016 for(MInt j = 0; j < nDim; j++) {
31017 dv += (a_coordinate(nghbrId, j) - a_coordinate(nghbr1, j)) * a_slope(nghbr1, varId, j);
31018 }
31019 if(a_pvariable(nghbr1, varId) + dv < vmin1 || a_pvariable(nghbr1, varId) + dv > vmax1) {
31020 phi1 = mMin(phi1, mMax(F0, (a_pvariable(nghbrId, varId) - a_pvariable(nghbr1, varId)) / dv));
31021 }
31022 }
31023 }
31024 }
31025 surfaceVar[va0 + varId] = a_pvariable(nghbr0, varId);
31026 surfaceVar[va0 + varId] += phi0 * std::inner_product(&cellSlopes[sl0], &cellSlopes[sl0] + nDim, &dx[i], 0);
31027 surfaceVar[va1 + varId] = a_pvariable(nghbr1, varId);
31028 surfaceVar[va1 + varId] +=
31029 phi1 * std::inner_product(&cellSlopes[sl1], &cellSlopes[sl1] + nDim, &dx[i + nDim], 0);
31030
31031#else
31032 surfaceVar[va0 + varId] =
31033 std::inner_product(&cellSlopes[sl0], &cellSlopes[sl0] + nDim, &dx[i], a_pvariable(nghbr0, varId));
31034 surfaceVar[va1 + varId] =
31035 std::inner_product(&cellSlopes[sl1], &cellSlopes[sl1] + nDim, &dx[i + nDim], a_pvariable(nghbr1, varId));
31036#endif
31037
31038#ifdef _MB_DEBUG_
31039 if(blk > -1 && domainId() == blk && srfcId == sfc) {
31040 cerr << "svalues @" << globalTimeStep << "/" << m_RKStep << " /s " << srfcId << " /n " << nghbr0 << " "
31041 << nghbr1 << " /var " << varId << " " << surfaceVar[va0 + varId] << " " << surfaceVar[va1 + varId]
31042 << " /cvar " << a_pvariable(nghbr0, varId) << " " << a_pvariable(nghbr1, varId) << " /sl0 "
31043 << cellSlopes[sl0] << " " << cellSlopes[sl0 + 1] << " " << cellSlopes[sl0 + 2] << " /sl1 "
31044 << cellSlopes[sl1] << " " << cellSlopes[sl1 + 1] << " " << cellSlopes[sl1 + 2] << " /dx0 " << dx[i]
31045 << " " << dx[i + 1] << " " << dx[i + 2] << " /dx1 " << dx[i + 3] << " " << dx[i + 4] << " " << dx[i + 5]
31046 << endl;
31047 }
31048#endif
31049 sl0 += nDim;
31050 sl1 += nDim;
31051 }
31052
31053#ifdef _MB_DEBUG_
31054 if((surfaceVar[va0 + PV->P] < F0) || (surfaceVar[va1 + PV->P] < F0)) {
31055 m_log << globalTimeStep << "/" << m_RKStep << " negative pressure: " << srfcId << " " << nghbr0 << " " << nghbr1
31056 << " / " << surfaceVar[va0 + PV->P] << " " << surfaceVar[va1 + PV->P] << " " << a_pvariable(nghbr0, PV->P)
31057 << " " << a_pvariable(nghbr1, PV->P) << " / " << a_isHalo(nghbr0) << " " << a_isHalo(nghbr1) << " / "
31058 << a_level(nghbr0) << " " << a_level(nghbr1) << endl;
31059 const MInt offset0 = nDim * m_cells.noRecNghbrs() * nghbr0;
31060 for(MInt n = a_noReconstructionNeighbors(nghbr0); n--;) {
31061 m_log << srfcId << " recvals0: " << n << ":" << a_reconstructionNeighborId(nghbr0, n) << "("
31062 << m_reconstructionConstants[offset0 + n * nDim + 0] << "/"
31063 << m_reconstructionConstants[offset0 + n * nDim + 1] << "/"
31064 << m_reconstructionConstants[offset0 + n * nDim + 2] << "#"
31065 << a_pvariable(a_reconstructionNeighborId(nghbr0, n), PV->P) << "="
31066 << a_isHalo(a_reconstructionNeighborId(nghbr0, n)) << ") " << endl;
31067 }
31068 const MInt offset1 = nDim * m_cells.noRecNghbrs() * nghbr1;
31069 for(MInt n = a_noReconstructionNeighbors(nghbr1); n--;) {
31070 m_log << srfcId << " recvals1: " << n << ":" << a_reconstructionNeighborId(nghbr1, n) << "("
31071 << m_reconstructionConstants[offset1 + n * nDim + 0] << "/"
31072 << m_reconstructionConstants[offset1 + n * nDim + 1] << "/"
31073 << m_reconstructionConstants[offset1 + n * nDim + 2] << "#"
31074 << a_pvariable(a_reconstructionNeighborId(nghbr1, n), PV->P) << "="
31075 << a_isHalo(a_reconstructionNeighborId(nghbr1, n)) << ") " << endl;
31076 }
31077 }
31078#endif
31079 }
31080 }
31081
31082 IF_CONSTEXPR(nDim == 3) {
31083 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
31084 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
31085 for(MInt k = 0; k < nDim; k++) {
31086 MInt srfcId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[k];
31087 if(srfcId < 0) continue;
31088 for(MInt var = 0; var < m_noPVars; var++) {
31089 a_surfaceVariable(srfcId, 0, var) =
31090 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[var];
31091 a_surfaceVariable(srfcId, 1, var) =
31092 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[var];
31093 }
31094 }
31095 }
31096 }
31097 }
31098}
31099
31100
31105template <MInt nDim, class SysEqn>
31107 TRACE();
31108
31109 const MInt noSrfcs = a_noSurfaces();
31110 const MInt surfaceVarMemory = m_surfaceVarMemory;
31111 const MInt slopeMemory = m_slopeMemory;
31112 const MFloat eps = 1e-10 * m_rhoInfinity;
31113 auto* surfaceVar = (MFloat*)(&(a_surfaceVariable(0, 0, 0)));
31114 auto* cellSlopes = (MFloat*)(&(a_slope(0, 0, 0)));
31115 auto* dx = (MFloat*)(&(a_surfaceDeltaX(0, 0)));
31116
31117 ScratchSpace<MFloat> phi(m_noSlopes * a_noCells(), AT_, "phi");
31118 for(MInt cellId = a_noCells(); cellId--;) {
31119 for(MInt j = 0; j < m_noSlopes; j++) {
31120 phi.p[cellId * m_noSlopes + j] = F0;
31121 }
31122
31123 // if ( a_coordinate( cellId , 0) < m_bodyCenter[0] ) continue; //expansion smoothing for piston testcase
31124 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
31125 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
31126 if(a_bndryId(cellId) < -1) continue;
31127
31128 for(MInt j = 0; j < nDim; j++) {
31129 if((!checkNeighborActive(cellId, 2 * j) || a_hasNeighbor(cellId, 2 * j) == 0)
31130 || (!checkNeighborActive(cellId, 2 * j + 1) || a_hasNeighbor(cellId, 2 * j + 1) == 0))
31131 continue;
31132 MInt n0 = c_neighborId(cellId, 2 * j);
31133 MInt n1 = c_neighborId(cellId, 2 * j + 1);
31134 ASSERT(n0 > -1 && n1 > -1 && n0 < a_noCells() && n1 < a_noCells(), "");
31135 for(MInt v = 0; v < m_noPVars; v++) {
31136 MFloat f =
31137 (a_pvariable(n1, v) - a_pvariable(cellId, v)) / (a_pvariable(cellId, v) - a_pvariable(n0, v) + m_eps);
31138 phi.p[cellId * m_noSlopes + v * nDim + j] = mMax(F0, mMin(F1, f)); // minmod
31139 // phi.p[ cellId*m_noSlopes + v*nDim + j ] = mMax( F0, mMin( F2, f ) ); //Osher
31140 // phi.p[ cellId*m_noSlopes + v*nDim + j ] = mMax( F0, mMax( mMin( F2, f ), mMin( F1, F2*f ) ) );
31141 // //superbee phi.p[ cellId*m_noSlopes + v*nDim + j ] = ( POW2(f) + f ) / ( POW2(f) + F1 ); //vanAlbada phi.p[
31142 // cellId*m_noSlopes + v*nDim + j ] = ( fabs(f) + f ) / ( fabs(f) + F1 ); //vanLeer phi.p[ cellId*m_noSlopes +
31143 // v*nDim + j ] = mMax( F0, mMax( mMin( F1, f ), mMin( F1, F1*f ) ) ); //Sweby phi.p[
31144 // cellId*m_noSlopes + v*nDim + j ] = mMax( F0, mMax( mMin( 1.5*f, F1 ), mMin( f, 1.5 ) ) );
31145 // //Sweby@beta=1.5 phi.p[ cellId*m_noSlopes + v*nDim + j ] = mMax( F0, mMax( mMin( F2*f, F1 ),
31146 // mMin( f, F2 ) ) ); //Sweby@beta=2 phi.p[ cellId*m_noSlopes + v*nDim + j ]
31147 // = 1.5*(POW2(f)+f)/(POW2(f)+f+F1); //ospre phi.p[ cellId*m_noSlopes + v*nDim + j ] = mMax( F0, mMin(
31148 // mMin( F2*f, F2 ), 0.5*(F1+f) ) );
31149 // //monotonized central phi.p[ cellId*m_noSlopes + v*nDim + j ] = mMax( F0, mMin( mMin( F2*f,
31150 // 0.25+0.75*f
31151 // ), mMin( F2, 0.75+0.25*f ) ) ); //UMIST
31152
31153 // if ( a_coordinate( cellId , 0) < m_bodyCenter[0] ) phi.p[ cellId*m_noSlopes + v*nDim + j ] = F1;
31154 // if ( a_coordinate( cellId , 0) < m_bodyCenter[0] ) phi.p[ cellId*m_noSlopes + v*nDim + j ] = ( POW2(f) + f )
31155 // / ( POW2(f) + F1 ); //vanAlbada if ( j != 0 ) phi.p[ cellId*m_noSlopes + v*nDim + j ] = F0;
31156 }
31157 }
31158 }
31159 // if(globalTimeStep<20)phi.fill(F0);
31160 // phi.fill(F0);
31161
31162 MInt va0 = surfaceVarMemory * noSrfcs;
31163 MInt va1 = va0 + m_noPVars;
31164 MInt i = 2 * nDim * noSrfcs;
31165 for(MInt srfcId = noSrfcs; srfcId--;) {
31166 va0 -= surfaceVarMemory;
31167 va1 -= surfaceVarMemory;
31168 i -= 2 * nDim;
31169
31170 // if ( m_isActiveSurface[ srfcId ] ) {
31171 {
31172 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
31173 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
31174
31175 MInt sl0 = nghbr0 * slopeMemory;
31176 MInt sl1 = nghbr1 * slopeMemory;
31177
31178 for(MInt varId = 0; varId < m_noPVars; varId++) {
31179 surfaceVar[va0 + varId] = a_pvariable(nghbr0, varId);
31180 for(MInt dim = 0; dim < nDim; ++dim)
31181 surfaceVar[va0 + varId] +=
31182 phi.p[m_noSlopes * nghbr0 + nDim * varId + dim] * cellSlopes[sl0 + dim] * dx[i + dim];
31183
31184 surfaceVar[va1 + varId] = a_pvariable(nghbr1, varId);
31185 for(MInt dim = 0; dim < nDim; ++dim)
31186 surfaceVar[va1 + varId] +=
31187 phi.p[m_noSlopes * nghbr1 + nDim * varId + dim] * cellSlopes[sl1 + dim] * dx[i + nDim + dim];
31188
31189 sl0 += nDim;
31190 sl1 += nDim;
31191 }
31192 surfaceVar[va0 + PV->RHO] = mMax(eps, surfaceVar[va0 + PV->RHO]);
31193 surfaceVar[va1 + PV->RHO] = mMax(eps, surfaceVar[va1 + PV->RHO]);
31194 surfaceVar[va0 + PV->P] = mMax(eps, surfaceVar[va0 + PV->P]);
31195 surfaceVar[va1 + PV->P] = mMax(eps, surfaceVar[va1 + PV->P]);
31196 }
31197 }
31198}
31199
31200
31205template <MInt nDim, class SysEqn>
31207 TRACE();
31208
31209 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
31210 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
31211 for(MInt dir = 0; dir < m_noDirs; dir++) {
31212 MInt srfcId = m_cellSurfaceMapping[cellId][dir];
31213 if(srfcId > -1) {
31214 updateCellSurfaceDistanceVector(srfcId);
31215 }
31216 }
31217 }
31218}
31219
31220
31221//#define AUSMPWP
31222//#define AUSMPLUS
31223#define SUBSONIC
31224
31234template <MInt nDim, class SysEqn>
31236 TRACE();
31237
31238 const MUint noPVars = PV->noVariables;
31239 const MUint noFluxVars = FV->noVariables;
31240 const MUint surfaceVarMemory = 2 * noPVars;
31241
31242 MFloat* const RESTRICT fluxes = ALIGNED_MF(&a_surfaceFlux(0, 0));
31243 const MInt noSurfaces = a_noSurfaces();
31244 const MInt noData = m_surfaceVarMemory;
31245 auto* RESTRICT surfArea = &a_surfaceArea(0);
31246 auto* RESTRICT var = (MFloat*)(&(a_surfaceVariable(0, 0, 0)));
31247
31248 MFloat* const RESTRICT surfaceVars = ALIGNED_F(&a_surfaceVariable(0, 0, 0));
31249
31250
31251 // 1) surface variable correction/centralization
31252 if(m_centralizeSurfaceVariables > 0) {
31253 for(MInt srfcId = 0; srfcId < noSurfaces; srfcId++) {
31254 const MInt orientation = a_surfaceOrientation(srfcId);
31255 const MUint offset = srfcId * surfaceVarMemory;
31256 MFloat* const RESTRICT leftVars = ALIGNED_F(surfaceVars + offset);
31257 MFloat* const RESTRICT rightVars = ALIGNED_F(leftVars + noPVars);
31258
31259 MInt levelFac = -1;
31260 if(m_centralizeSurfaceVariables == 5) {
31261 const MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
31262 const MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
31263 const MInt level = mMax(a_level(nghbr0), a_level(nghbr1));
31264 levelFac = (MFloat)((maxRefinementLevel() - level) / (maxRefinementLevel() - maxUniformRefinementLevel()));
31265 }
31266 switch(m_centralizeSurfaceVariables) {
31267 case 1: {
31268 sysEqn().template centralizeSurfaceVariables<1>(leftVars, rightVars, orientation, levelFac);
31269 break;
31270 }
31271 case 2: {
31272 sysEqn().template centralizeSurfaceVariables<2>(leftVars, rightVars, orientation, levelFac);
31273 break;
31274 }
31275 case 3: {
31276 sysEqn().template centralizeSurfaceVariables<3>(leftVars, rightVars, orientation, levelFac);
31277 break;
31278 }
31279 case 4: {
31280 sysEqn().template centralizeSurfaceVariables<4>(leftVars, rightVars, orientation, levelFac);
31281 break;
31282 }
31283 case 5: {
31284 sysEqn().template centralizeSurfaceVariables<5>(leftVars, rightVars, orientation, levelFac);
31285 break;
31286 }
31287 default: {
31288 mTerm(1, AT_, "centralizeSurfaceVariables mode not implemented!");
31289 break;
31290 }
31291 }
31292 }
31293 }
31294
31295 // 2) surface flux computation
31296 this->m_static_computeSurfaceValuesLimitedSlopesMan_checkedBndryCndIds = true;
31297 this->m_static_computeSurfaceValuesLimitedSlopesMan_correctWallBndryFluxes = false;
31298
31299 // all surface variables updated, now lets compute the fluxes
31300 Base::Ausm();
31301
31302 // correct all wall boundary surfaces
31303 for(MInt bs = 0; bs < m_fvBndryCnd->m_noBoundarySurfaces; bs++) {
31304 MInt srfcId = m_fvBndryCnd->m_boundarySurfaces[bs];
31305 if(a_surfaceBndryCndId(srfcId) == 3003) {
31306 const MInt offset = noData * srfcId;
31307 const MInt orientation = a_surfaceOrientation(srfcId);
31308 const MFloat area = surfArea[srfcId];
31309 const MFloat* leftVars = var + offset;
31310 const MFloat* rightVars = leftVars + noPVars;
31311 const MUint fluxOffset = srfcId * noFluxVars;
31312 MFloat* const RESTRICT flux = fluxes + fluxOffset;
31313 sysEqn().AusmBndryCorrection(orientation, area, leftVars, rightVars, flux);
31314 }
31315 }
31316
31317 applyALECorrection();
31318}
31319
31320
31325template <MInt nDim, class SysEqn>
31327 MFloat xDiff = F0;
31328
31329 for(MInt i = 0; i < nDim; i++) {
31330 MFloat diff = a_surfaceCoordinate(srfcId1, i) - a_surfaceCoordinate(srfcId2, i);
31331 xDiff += (diff * diff);
31332 }
31333
31334 return sqrt(xDiff);
31335}
31336
31337
31342template <MInt nDim, class SysEqn>
31344 return fabs(a_surfaceArea(srfcId1) - a_surfaceArea(srfcId2));
31345}
31346
31347
31352template <MInt nDim, class SysEqn>
31355 std::vector<FvMbCartesianSolverXD<nDim, SysEqn>::CsgPolygon>* coplanarFront,
31356 std::vector<FvMbCartesianSolverXD<nDim, SysEqn>::CsgPolygon>* coplanarBack) const {
31357 ASSERT2(!(std::isnan(polygon->plane.normal.xx[0])), "");
31358
31359 (this->normal.dot((polygon->plane.normal)) > F0 ? coplanarFront : coplanarBack)->push_back(*polygon);
31360}
31361
31362
31367template <MInt nDim, class SysEqn>
31370 std::vector<FvMbCartesianSolverXD<nDim, SysEqn>::CsgPolygon>* coplanarFront,
31371 std::vector<FvMbCartesianSolverXD<nDim, SysEqn>::CsgPolygon>* coplanarBack,
31373 std::vector<FvMbCartesianSolverXD<nDim, SysEqn>::CsgPolygon>* back) const {
31374 const MInt COPLANAR = 0;
31375 const MInt FRONT = 1;
31376 const MInt BACK = 2;
31377 const MInt SPANNING = 3;
31378
31379 MInt polygonType = 0;
31380 std::vector<MInt> types;
31381
31382 // test normals for equivalence
31383 MBool normalsEqual = false;
31384 IF_CONSTEXPR(nDim == 3) {
31385 if(abs(abs(this->normal.xx[0]) - abs(polygon->plane.normal.xx[0])) < MFloatEps
31386 && abs(abs(this->normal.xx[1]) - abs(polygon->plane.normal.xx[1])) < MFloatEps
31387 && abs(abs(this->normal.xx[2]) - abs(polygon->plane.normal.xx[2])) < MFloatEps)
31388 normalsEqual = true;
31389 }
31390
31391 MBool coplanarVertex = false;
31392 for(MInt i = 0; (unsigned)i < polygon->vertices.size(); i++) {
31393 MFloat t = this->normal.dot((polygon->vertices[i].pos)) - this->w;
31394 MInt type = (t < -eps) ? BACK : (t > eps) ? FRONT : COPLANAR;
31395 polygonType |= type;
31396 types.push_back(type);
31397 IF_CONSTEXPR(nDim == 3) {
31398 if(type == 0) coplanarVertex = true;
31399 }
31400 }
31401 ASSERT2(!(std::isnan(polygon->plane.normal.xx[0])), "");
31402
31403 // Only in 3D the if-clause can result in true
31404 if(normalsEqual && coplanarVertex) polygonType = COPLANAR;
31405
31406 switch(polygonType) {
31407 case COPLANAR:
31408 (this->normal.dot((polygon->plane.normal)) > F0 ? coplanarFront : coplanarBack)->push_back(*polygon);
31409 break;
31410 case FRONT:
31411 front->push_back(*polygon);
31412 break;
31413 case BACK:
31414 back->push_back(*polygon);
31415 break;
31416 case SPANNING: {
31417 std::vector<CsgVertex> f;
31418 std::vector<CsgVertex> b;
31419 IF_CONSTEXPR(nDim == 2) {
31420 MInt i = 0;
31421 MInt j = 1;
31422 MInt ti = types[i], tj = types[j];
31423 CsgVertex vi = polygon->vertices[i];
31424 CsgVertex vj = polygon->vertices[j];
31425 if(ti != BACK) f.push_back(vi);
31426 if(ti != FRONT) b.push_back(ti != BACK ? vi.clone() : vi);
31427 if((ti | tj) == SPANNING) {
31428 MFloat t = (this->w - this->normal.dot((vi.pos))) / this->normal.dot(vj.pos.minus((vi.pos)));
31429 CsgVertex v = vi.interpolate(&vj, t);
31430 f.push_back(v);
31431 b.push_back(v.clone());
31432 }
31433 if(tj != BACK) f.push_back(vj);
31434 if(tj != FRONT) b.push_back(tj != BACK ? vj.clone() : vj);
31435 }
31436 else IF_CONSTEXPR(nDim == 3) {
31437 for(MInt i = 0; (unsigned)i < polygon->vertices.size(); i++) {
31438 MInt j = (i + 1) % polygon->vertices.size();
31439 MInt ti = types[i], tj = types[j];
31440 CsgVertex vi = polygon->vertices[i];
31441 CsgVertex vj = polygon->vertices[j];
31442 if(ti != BACK) f.push_back(vi);
31443 if(ti != FRONT) b.push_back(ti != BACK ? vi.clone() : vi);
31444 if((ti | tj) == SPANNING) {
31445 MFloat t = (this->w - this->normal.dot((vi.pos))) / this->normal.dot(vj.pos.minus((vi.pos)));
31446 CsgVertex v = vi.interpolate(&vj, t);
31447 f.push_back(v);
31448 b.push_back(v.clone());
31449 }
31450 }
31451 }
31452 if(f.size() >= nDim)
31453 front->push_back(
31454 CsgPolygon(f, polygon->setIndex, polygon->faceId, polygon->faceType, polygon->bodyId, polygon->plane));
31455 if(b.size() >= nDim)
31456 back->push_back(
31457 CsgPolygon(b, polygon->setIndex, polygon->faceId, polygon->faceType, polygon->bodyId, polygon->plane));
31458 } break;
31459 default:
31460 break;
31461 }
31462}
31463
31464
31469template <MInt nDim, class SysEqn>
31470void FvMbCartesianSolverXD<nDim, SysEqn>::CsgNode::build(std::vector<CsgPolygon> _polygons) {
31471 if(_polygons.empty()) return;
31472 MInt polygonStartIndex = nDim == 3 ? 0 : 1;
31473 if(!planeValid) {
31474 this->plane = _polygons[0].plane.clone();
31475 planeValid = true;
31476 IF_CONSTEXPR(nDim == 3) {
31477 this->polygons.push_back(_polygons[0]);
31478 polygonStartIndex = 1;
31479 }
31480 }
31481 std::vector<CsgPolygon> _front;
31482 std::vector<CsgPolygon> _back;
31483 IF_CONSTEXPR(nDim == 2) { this->plane.insertCoplanarPolygon(&_polygons[0], &this->polygons, &this->polygons); }
31484 for(MInt i = polygonStartIndex; (unsigned)i < _polygons.size(); i++) {
31485 this->plane.splitPolygon(&_polygons[i], &this->polygons, &this->polygons, &_front, &_back);
31486 }
31487 if(_front.size() != 0u) {
31488 if(!this->front) // check if nullptr
31489 this->front = new CsgNode();
31490 this->front->build(_front);
31491 }
31492 if(_back.size() != 0u) {
31493 if(!this->back) this->back = new CsgNode();
31494 this->back->build(_back);
31495 }
31496}
31497
31498
31504template <MInt nDim, class SysEqn>
31506 const MInt faceCornerMapping[6][4] = {{2, 6, 4, 0}, {1, 5, 7, 3}, {0, 4, 5, 1},
31507 {3, 7, 6, 2}, {2, 3, 1, 0}, {6, 7, 5, 4}};
31508
31509 MFloat A = m_candidateNodeValues[IDX_LSSETNODES(cndId, faceCornerMapping[face][0], set)];
31510 MFloat B = m_candidateNodeValues[IDX_LSSETNODES(cndId, faceCornerMapping[face][1], set)];
31511 MFloat C = m_candidateNodeValues[IDX_LSSETNODES(cndId, faceCornerMapping[face][2], set)];
31512 MFloat D = m_candidateNodeValues[IDX_LSSETNODES(cndId, faceCornerMapping[face][3], set)];
31513
31514 MFloat testSum = A * C - B * D;
31515 if(fabs(testSum) < m_eps) return true;
31516 return A * testSum >= F0; // A being negative inverts signs
31517}
31518
31519
31524template <MInt nDim, class SysEqn>
31525template <class _, std::enable_if_t<nDim == 2, _*>>
31527 const std::vector<polyVertex>* vertices, MInt A,
31528 MInt B, MFloat* P) {
31529 MFloat P1 = F0, Pa = F0, Pb = F0;
31530
31531 for(MInt i = 0; (unsigned)i < (*cutCell).faces_edges.size(); i++) {
31532 MInt edge = (*cutCell).faces_edges[i];
31533 MInt vertex0, vertex1;
31534 vertex0 = (*edges)[edge].vertices[0];
31535 vertex1 = (*edges)[edge].vertices[1];
31536 MFloat a0 = (*vertices)[vertex0].coordinates[A];
31537 MFloat b0 = (*vertices)[vertex0].coordinates[B];
31538 MFloat a1 = (*vertices)[vertex1].coordinates[A];
31539 MFloat b1 = (*vertices)[vertex1].coordinates[B];
31540 MFloat da = a1 - a0;
31541 MFloat db = b1 - b0;
31542 MFloat a0_2 = a0 * a0;
31543 MFloat b0_2 = b0 * b0;
31544
31545 MFloat C1 = a1 + a0;
31546 MFloat Ca = a1 * C1 + a0_2;
31547 MFloat Cb = b1 * (b1 + b0) + b0_2;
31548
31549 P1 += db * C1;
31550 Pa += db * Ca;
31551 Pb += da * Cb;
31552
31553 (*edges)[edge].center[A] = a0 + F1B2 * da;
31554 (*edges)[edge].center[B] = b0 + F1B2 * db;
31555 (*edges)[edge].area = sqrt(da * da + db * db);
31556 }
31557
31558 P[0] = P1 / 2.0;
31559 P[1] = Pa / 6.0;
31560 P[2] = Pb / -6.0;
31561}
31562
31563
31568template <MInt nDim, class SysEqn>
31569template <class _, std::enable_if_t<nDim == 2, _*>>
31570void FvMbCartesianSolverXD<nDim, SysEqn>::compFaceIntegrals(polyCutCell* cutCell, std::vector<polyEdge2D>* edges,
31571 const std::vector<polyVertex>* vertices, MInt A, MInt B) {
31572 MFloat P[3];
31573
31574 compProjectionIntegrals(cutCell, edges, vertices, A, B, P);
31575
31576 MFloat area = P[0];
31577 if(area > 1e3 * m_eps) {
31578 cutCell->volume = area;
31579 cutCell->center[A] = P[1] / area;
31580 cutCell->center[B] = P[2] / area;
31581 } else if(area > F0) {
31582 cutCell->volume = area;
31583 P[1] = F0;
31584 P[2] = F0;
31585 for(MInt i = 0; (unsigned)i < (*cutCell).faces_edges.size(); i++) {
31586 MInt edge = (*cutCell).faces_edges[i];
31587 MInt vertex0 = (*edges)[edge].vertices[0];
31588 P[1] += (*vertices)[vertex0].coordinates[0];
31589 P[2] += (*vertices)[vertex0].coordinates[1];
31590 }
31591 P[1] /= (*cutCell).faces_edges.size();
31592 P[2] /= (*cutCell).faces_edges.size();
31593 cutCell->center[A] = P[1];
31594 cutCell->center[B] = P[2];
31595 } else {
31596 cutCell->volume = F0;
31597 P[1] = F0;
31598 P[2] = F0;
31599 for(MInt i = 0; (unsigned)i < (*cutCell).faces_edges.size(); i++) {
31600 MInt edge = (*cutCell).faces_edges[i];
31601 MInt vertex0 = (*edges)[edge].vertices[0];
31602 P[1] += (*vertices)[vertex0].coordinates[0];
31603 P[2] += (*vertices)[vertex0].coordinates[1];
31604 }
31605 P[1] /= (*cutCell).faces_edges.size();
31606 P[2] /= (*cutCell).faces_edges.size();
31607 cutCell->center[A] = P[1];
31608 cutCell->center[B] = P[2];
31609 }
31610}
31611
31612
31617template <MInt nDim, class SysEqn>
31618template <class _, std::enable_if_t<nDim == 2, _*>>
31619void FvMbCartesianSolverXD<nDim, SysEqn>::compVolumeIntegrals(std::vector<polyCutCell>* cutCells,
31620 std::vector<polyEdge2D>* edges,
31621 const std::vector<polyVertex>* vertices) {
31622 MInt A = 0, B = 1;
31623
31624 for(MInt cC = 0; (unsigned)cC < cutCells->size(); cC++) {
31625 polyCutCell* cutCell = &(*cutCells)[cC];
31626
31627 compFaceIntegrals(cutCell, edges, vertices, A, B);
31628 }
31629}
31630
31631
31636template <MInt nDim, class SysEqn>
31637template <class _, std::enable_if_t<nDim == 3, _*>>
31639 const MInt noCells = m_fvBndryCnd->m_bndryCells->size();
31640
31641 for(MInt bndryId = m_noOuterBndryCells; bndryId < noCells; bndryId++) {
31642 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
31643 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId < 0) {
31644 mTerm(1, AT_, "error in createCutFaceMb(): m_bndryCndId not set: " + to_string(bndryId));
31645 }
31646 MFloat test = F0;
31647 for(MInt i = 0; i < nDim; i++) {
31648 test += POW2(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i]);
31649 }
31650 if(fabs(test - F1) > 0.1) {
31651 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
31652#ifdef _MB_DEBUG_
31653 cerr << domainId() << ": bad normal vector corrected, n^2=" << test << ", timestep= " << globalTimeStep
31654 << ", cell " << cellId << " " << bndryId << " " << srfc << " " << c_globalId(cellId)
31655 << " /p15=" << a_isHalo(cellId) << " /n "
31656 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0] << " "
31657 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1] << " "
31658 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2] << " /a "
31659 << m_fvBndryCnd->m_bndryCell[bndryId].m_srfcs[srfc]->m_area << " /v "
31660 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume / grid().gridCellVolume(a_level(cellId)) << " /c "
31661 << m_bndryCells->a[bndryId].m_coordinates[0] << " " << m_bndryCells->a[bndryId].m_coordinates[1] << " "
31662 << m_bndryCells->a[bndryId].m_coordinates[2] << " /s "
31663 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[0] << " "
31664 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[1] << " "
31665 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_coordinates[2] << endl;
31666#endif
31667 MFloat nablaPhi[3] = {F1, F1, F1};
31668 MFloat nablaAbs = F0;
31669 for(MInt i = 0; i < nDim; i++) {
31670 MInt n0 = (a_hasNeighbor(cellId, 2 * i) > 0) ? c_neighborId(cellId, 2 * i) : cellId;
31671 MInt n1 = (a_hasNeighbor(cellId, 2 * i + 1) > 0) ? c_neighborId(cellId, 2 * i + 1) : cellId;
31672 if(n0 != n1) {
31673 nablaPhi[i] = (a_levelSetValuesMb(n1, 0) - a_levelSetValuesMb(n0, 0))
31674 / mMax(1e-14, a_coordinate(n1, i) - a_coordinate(n0, i));
31675 }
31676 nablaAbs += POW2(nablaPhi[i]);
31677 }
31678 nablaAbs = sqrt(nablaAbs);
31679 for(MInt i = 0; i < nDim; i++) {
31680 nablaPhi[i] /= nablaAbs;
31681 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i] = nablaPhi[i];
31682 }
31683#ifdef _MB_DEBUG_
31684 cerr << domainId() << ": corrected " << POW2(nablaAbs) << " /n "
31685 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[0] << " "
31686 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[1] << " "
31687 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[2] << endl;
31688 // m_fvBndryCnd->writeStlFileOfCell(cellId,("out/cell_"+to_string(c_globalId(cellId))+"_"+to_string(globalTimeStep)+".stl").c_str());
31689#endif
31690 } else {
31691 test = sqrt(test);
31692 for(MInt i = 0; i < nDim; i++) {
31693 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i] /= test;
31694 }
31695 }
31696 }
31697 }
31698}
31699
31700
31706template <MInt nDim, class SysEqn>
31707template <class _, std::enable_if_t<nDim == 2, _*>>
31708void FvMbCartesianSolverXD<nDim, SysEqn>::writeVtkXmlOutput(const MString& fileName, MBool debugOutput) {
31709 TRACE();
31710
31711 if(m_complexBoundary) return writeVtkXmlOutput_MGC(fileName);
31712
31713 ASSERT(debugOutput || true, "");
31714
31715 MInt noCells = 1;
31716 MInt noPoints = 1;
31717
31730 MBool writePointData = false;
31731 writePointData = Context::getSolverProperty<MBool>("writePointData", solverId(), AT_, &writePointData);
31732
31733#ifdef _MB_DEBUG_
31734 MBool sensorOutput = m_adaptation;
31735#endif
31736 MBool QThresholdOutput = true;
31737 MBool entropyChangeOutput = true;
31738
31739
31740 const MInt baseCellType = 8;
31741 const MInt polyCellType = 7;
31742
31743 MInt cellId, ghostCellId, counter;
31744
31745
31746 const string dataType64 = "Float64";
31747#ifdef DOUBLE_PRECISION_OUTPUT
31748 const string dataType = "Float64";
31749#else
31750 const string dataType = "Float32";
31751#endif
31752 const string iDataType = "Int32";
31753 const string uIDataType = "UInt32";
31754 const string uI8DataType = "UInt8";
31755 const string uI16DataType = "UInt16";
31756
31757 MUint uinumber;
31758#ifdef DOUBLE_PRECISION_OUTPUT
31759 MFloat fnumber;
31760 typedef MFloat flt;
31761#else
31762 using flt = float;
31763#endif
31764
31765 if(noDomains() == 1) {
31766 cerr << "extracted";
31767 cerr << "(" << m_extractedCells->size() << ")...";
31768 }
31769
31770 noPoints = m_gridPoints->size();
31771 MInt noExtractedCells = m_extractedCells->size();
31772 noCells = noExtractedCells;
31773
31774 // 4 node ids for each direction
31775 const MInt ltable[4][3] = {{2, 3}, {0, 2}, {1, 0}, {3, 1}};
31776 const MInt pointOrder[4] = {0, 1, 3, 2};
31777 const MInt dirOrder[4] = {2, 1, 3, 0};
31778 const MInt reverseDir[4] = {1, 0, 3, 2};
31779
31780 MInt centerId;
31781
31782 ScratchSpace<MInt> cellTypes(noExtractedCells, AT_, "cellTypes");
31783 ScratchSpace<MInt> polyIds(noExtractedCells, AT_, "polyIds");
31784 ScratchSpace<MInt> reverseMapping(a_noCells(), AT_, "reverseMapping");
31785 ScratchSpace<MInt> cutPointIds(m_noDirs * m_fvBndryCnd->m_bndryCells->size(), AT_, "cutPointIds");
31786
31787 MInt noPolyCells;
31788
31789 // integrity check 1
31790 for(MInt c = 0; c < noExtractedCells; c++) {
31791 cellId = m_extractedCells->a[c].m_cellId;
31792 for(MInt k = 0; k < m_noCellNodes; k++) {
31793 MInt pid = m_extractedCells->a[c].m_pointIds[k];
31794 if(pid < 0 || pid >= noPoints) {
31795 mTerm(1, AT_,
31796 "Error A in FvMbSolver2D::writeVtkXmlOutput(..). Quit. " + to_string(cellId) + " " + to_string(k) + " "
31797 + to_string(pid));
31798 }
31799 }
31800 }
31801
31802 for(MInt i = 0; i < m_noDirs * m_fvBndryCnd->m_bndryCells->size(); i++) {
31803 cutPointIds.p[i] = -1;
31804 }
31805
31806 if(noDomains() == 1) {
31807 cerr << "prepare...";
31808 }
31809 for(MInt c = 0; c < a_noCells(); c++) {
31810 reverseMapping.p[c] = -1;
31811 }
31812 for(MInt c = 0; c < noExtractedCells; c++) {
31813 reverseMapping.p[m_extractedCells->a[c].m_cellId] = c;
31814 }
31815
31816 MBool isPolyCell;
31817 noPolyCells = 0;
31818
31819 for(MInt c = 0; c < noExtractedCells; c++) {
31820 cellId = m_extractedCells->a[c].m_cellId;
31821 cellTypes.p[c] = baseCellType;
31822 polyIds.p[c] = -1;
31823 isPolyCell = false;
31824 if(a_bndryId(cellId) > -1) {
31825 isPolyCell = true;
31826 } else {
31827 for(MInt i = 0; i < m_noDirs; i++) {
31828 if(a_hasNeighbor(cellId, i) > 0) {
31829 if(c_noChildren(c_neighborId(cellId, i)) > 0) {
31830 isPolyCell = true;
31831 MInt nghbrId = c_neighborId(cellId, i);
31832 if(nghbrId < 0) continue;
31833 for(MInt j = 0; j < m_noCellNodes; j++) {
31834 MInt childId = c_childId(nghbrId, j);
31835 if(reverseMapping.p[childId] < 0) {
31836 isPolyCell = false;
31837 }
31838 }
31839 }
31840 }
31841 }
31842 }
31843 if(isPolyCell) {
31844 cellTypes.p[c] = polyCellType;
31845 polyIds.p[c] = noPolyCells;
31846 noPolyCells++;
31847 }
31848 }
31849
31850 MBool isPolyFace;
31851 MInt eCell, nghbrId;
31852 const MInt maxNoExtraPoints = 8;
31853 const MInt maxNoPolyCells = noPolyCells;
31854 ScratchSpace<MInt> polyCellLink(maxNoPolyCells, AT_, "polyCellLink");
31855 ScratchSpace<MInt> extraPoints(maxNoPolyCells * maxNoExtraPoints, AT_, "extraPoints");
31856 ScratchSpace<MInt> noExtraPoints(maxNoPolyCells, AT_, "noExtraPoints");
31857 ScratchSpace<MInt> noInternalPoints(maxNoPolyCells, AT_, "noInternalPoints");
31858 MInt offset, pointCount;
31859
31860 for(MInt c = 0; c < noExtractedCells; c++) {
31861 if(cellTypes.p[c] == polyCellType) {
31862 polyCellLink.p[polyIds.p[c]] = c;
31863 }
31864 }
31865
31866 const MInt noInternalGridPoints = m_gridPoints->size();
31867
31868 for(MInt pc = 0; pc < noPolyCells; pc++) {
31869 eCell = polyCellLink.p[pc];
31870 cellId = m_extractedCells->a[eCell].m_cellId;
31871 noInternalPoints.p[pc] = m_noCellNodes;
31872 noExtraPoints.p[pc] = 0;
31873
31874 // a) cut cells at the boundary
31875 if(a_bndryId(cellId) > -1) {
31876 MInt bndryId = a_bndryId(cellId);
31877
31878 noInternalPoints.p[pc] = 0;
31879
31880 for(MInt i = 0; i < m_noDirs; i++) {
31881 MInt p = pointOrder[i];
31882 MInt dir = dirOrder[i];
31883
31884 // 0. determine internal vertices
31885 if(!m_pointIsInside[bndryId][IDX_LSSETMB(p, 0)]) {
31886 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = m_extractedCells->a[eCell].m_pointIds[p];
31887 noExtraPoints.p[pc]++;
31888 }
31889
31890 // 1. add cut points
31891 for(MInt cp = 0; cp < m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
31892 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cp] == dir) {
31893 MInt gridPointId = -1;
31894 if(a_hasNeighbor(cellId, dir) > 0) {
31895 if(a_bndryId(c_neighborId(cellId, dir)) > -1) {
31896 gridPointId = cutPointIds.p[m_noDirs * a_bndryId(c_neighborId(cellId, dir)) + reverseDir[dir]];
31897 if(gridPointId > -1) {
31898 m_gridPoints->a[gridPointId].m_cellIds[m_gridPoints->a[gridPointId].m_noAdjacentCells] = cellId;
31899 m_gridPoints->a[gridPointId].m_noAdjacentCells++;
31900 }
31901 }
31902 }
31903 if(gridPointId >= noPoints) {
31904 mTerm(1, AT_, "Error 0 in FvMbSolver3D::writeVtkXmlOutput(..). Quit.");
31905 }
31906 if(gridPointId < 0) {
31907 gridPointId = m_gridPoints->size();
31909 noPoints++;
31910 m_gridPoints->a[gridPointId].m_noAdjacentCells = 1;
31911 m_gridPoints->a[gridPointId].m_cellIds[0] = cellId;
31912 for(MInt j = 0; j < nDim; j++) {
31913 m_gridPoints->a[gridPointId].m_coordinates[j] =
31914 m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_cutCoordinates[cp][j];
31915 }
31916 }
31917 cutPointIds.p[m_noDirs * bndryId + dir] = gridPointId;
31918
31919 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = gridPointId;
31920 noExtraPoints.p[pc]++;
31921 }
31922 }
31923 }
31924 }
31925 // b) cells at fine/coarse mesh interfaces
31926 else {
31927 noInternalPoints.p[pc] = 0;
31928
31929 for(MInt i = 0; i < m_noDirs; i++) {
31930 MInt p = pointOrder[i];
31931 MInt dir = dirOrder[i];
31932
31933 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = m_extractedCells->a[eCell].m_pointIds[p];
31934 noExtraPoints.p[pc]++;
31935
31936 isPolyFace = false;
31937 if(a_hasNeighbor(cellId, dir) > 0) {
31938 nghbrId = c_neighborId(cellId, dir);
31939 if(c_noChildren(nghbrId) > 0) {
31940 isPolyFace = true;
31941 for(MInt child = 0; child < m_noCellNodes; child++) {
31942 if(!childCode[dir][child]) continue;
31943 MInt childId = c_childId(nghbrId, child);
31944 if(childId < 0) {
31945 isPolyFace = false;
31946 }
31947 if(reverseMapping.p[childId] < 0) {
31948 isPolyFace = false;
31949 }
31950 }
31951 }
31952 }
31953
31954 if(isPolyFace) {
31955 // store four faces (polygon numbering!)
31956 nghbrId = reverseMapping.p[c_childId(c_neighborId(cellId, dir), ltable[i][0])];
31957 if(nghbrId < 0) {
31958 cerr << "=== VTK XML ERROR LOG === " << domainId() << endl;
31959 cerr << endl
31960 << cellId << " " << a_bndryId(cellId) << " " << c_childId(c_neighborId(cellId, dir), ltable[i][0])
31961 << endl;
31962 cerr << endl << a_noCells() << " " << a_noCells() << " " << dir << " " << ltable[i][0] << endl;
31963 cerr << a_levelSetValuesMb(cellId, 0) << " " << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
31964 cerr << "props: " << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " " << a_isHalo(cellId) << " "
31965 << a_hasProperty(cellId, SolverCell::IsNotGradient) << " "
31966 << a_hasProperty(c_neighborId(cellId, dir), SolverCell::IsOnCurrentMGLevel) << " "
31967 << a_hasProperty(c_childId(c_neighborId(cellId, dir), ltable[i][0]), SolverCell::IsOnCurrentMGLevel)
31968 << endl;
31969 cerr << endl
31970 << cellId << " " << c_neighborId(cellId, dir) << " "
31971 << c_childId(c_neighborId(cellId, dir), ltable[i][0]) << " / " << a_level(cellId) << " "
31972 << a_level(c_neighborId(cellId, dir)) << " "
31973 << a_level(c_childId(c_neighborId(cellId, dir), ltable[i][0])) << " / " << c_noChildren(cellId) << " "
31974 << c_noChildren(c_neighborId(cellId, dir)) << " "
31975 << c_noChildren(c_childId(c_neighborId(cellId, dir), ltable[i][0])) << endl;
31976 cerr << c_childId(c_neighborId(cellId, dir), 0) << " " << c_childId(c_neighborId(cellId, dir), 1) << " "
31977 << c_childId(c_neighborId(cellId, dir), 2) << " " << c_childId(c_neighborId(cellId, dir), 3) << endl;
31978 cerr << a_coordinate(c_neighborId(cellId, dir), 0) << " " << a_coordinate(c_neighborId(cellId, dir), 1)
31979 << endl;
31980 for(MInt j = 0; j < m_noCellNodes; j++) {
31981 cerr << a_hasProperty(c_childId(c_neighborId(cellId, dir), j), SolverCell::IsInactive) << " ";
31982 }
31983 cerr << endl;
31984 for(MInt j = 0; j < m_noCellNodes; j++) {
31985 cerr << a_hasProperty(c_childId(c_neighborId(cellId, dir), j), SolverCell::IsOnCurrentMGLevel) << " ";
31986 }
31987 cerr << endl;
31988 mTerm(1, AT_, "Error 1 in FvMbSolver2D::writeVtkXmlOutput(..). Quit.");
31989 }
31990 centerId = m_extractedCells->a[nghbrId].m_pointIds[ltable[i][1]];
31991 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = centerId;
31992 noExtraPoints.p[pc]++;
31993
31994 if(m_gridPoints->a[centerId].m_noAdjacentCells < m_noCellNodes) {
31995 m_gridPoints->a[centerId].m_cellIds[m_gridPoints->a[centerId].m_noAdjacentCells] = cellId;
31996 m_gridPoints->a[centerId].m_noAdjacentCells++;
31997 } else {
31998 cerr << endl << cellId << " / ";
31999 for(MInt c = 0; c < m_gridPoints->a[centerId].m_noAdjacentCells; c++)
32000 cerr << m_gridPoints->a[centerId].m_cellIds[c] << " ";
32001 cerr << endl;
32002 mTerm(1, AT_, "Error 2 in FvMbSolver2D::writeVtkXmlOutput(..). Quit.");
32003 }
32004 }
32005 }
32006 }
32007 }
32008
32009 pointCount = 0;
32010 for(MInt c = 0; c < noExtractedCells; c++) {
32011 MInt pc = polyIds.p[c];
32012 if(pc > -1) {
32013 pointCount += noInternalPoints.p[pc];
32014 pointCount += noExtraPoints.p[pc];
32015 } else {
32016 pointCount += m_noCellNodes;
32017 }
32018 }
32019
32020 MInt qDataSize = 2;
32021 if(QThresholdOutput) qDataSize++;
32022 ScratchSpace<MFloat> qData(qDataSize, a_noCells(), AT_, "qData");
32023 MFloat gradU[2][2];
32024 for(MInt c = 0; c < noExtractedCells; c++) {
32025 cellId = m_extractedCells->a[c].m_cellId;
32026
32027 for(MInt i = 0; i < nDim; i++) {
32028 for(MInt j = 0; j < nDim; j++) {
32029 gradU[i][j] = a_slope(cellId, PV->VV[i], j) * m_referenceLength / m_UInfinity;
32030 }
32031 }
32032 MFloat omega = F1B2 * (gradU[1][0] - gradU[0][1]);
32033 MFloat omega2 = POW2(omega);
32034 MFloat S2 = 0;
32035 for(MInt i = 0; i < nDim; i++) {
32036 for(MInt j = 0; j < nDim; j++) {
32037 S2 += POW2(F1B2 * (gradU[i][j] + gradU[j][i]));
32038 }
32039 }
32040 MFloat Q = F1B2 * (omega2 / S2 - F1);
32041 qData(0, cellId) = Q;
32042 qData(1, cellId) = omega;
32043 if(QThresholdOutput) qData(2, cellId) = F1B2 * ((omega2 / mMax(m_eps, S2)) - F1);
32044 }
32045
32046
32047 // GATHER
32048 if(noDomains() == 1) {
32049 cerr << "gather...";
32050 }
32051
32052 // points
32053 ScratchSpace<flt> points(3 * noPoints, AT_, "points");
32054 for(MInt p = 0; p < noPoints; p++) {
32055 for(MInt i = 0; i < nDim; i++) {
32056 points.p[3 * p + i] = (flt)m_gridPoints->a[p].m_coordinates[i];
32057 }
32058 points.p[3 * p + 2] = (flt)F0;
32059 }
32060
32061 // connectivity
32062 ScratchSpace<MUint> connectivity(pointCount, AT_, "connectivity");
32063 counter = 0;
32064 for(MInt c = 0; c < noExtractedCells; c++) {
32065 MInt pc = polyIds.p[c];
32066 if(pc > -1) {
32067 for(MInt p = 0; p < noExtraPoints.p[pc]; p++) {
32068 connectivity.p[counter] = (MUint)extraPoints.p[pc * maxNoExtraPoints + p];
32069 counter++;
32070 }
32071 } else {
32072 for(MInt p = 0; p < m_noCellNodes; p++) {
32073 connectivity.p[counter] = (MUint)m_extractedCells->a[c].m_pointIds[p];
32074 counter++;
32075 }
32076 }
32077 }
32078 if(counter != pointCount) {
32079 mTerm(1, AT_, "E1");
32080 }
32081
32082 // offsets
32083 ScratchSpace<MUint> offsets(noCells, AT_, "offsets");
32084 counter = 0;
32085 for(MInt c = 0; c < noExtractedCells; c++) {
32086 MInt pc = polyIds.p[c];
32087 if(pc > -1)
32088 counter += noInternalPoints.p[pc] + noExtraPoints.p[pc];
32089 else
32090 counter += m_noCellNodes;
32091
32092 offsets.p[c] = (MUint)counter;
32093 }
32094
32095 // types
32096 ScratchSpace<unsigned char> types(noCells, AT_, "types");
32097 for(MInt c = 0; c < noExtractedCells; c++) {
32098 types.p[c] = (unsigned char)cellTypes.p[c];
32099 }
32100
32101 // cellIds
32102 ScratchSpace<MInt> cellIds(noCells, AT_, "cellIds");
32103 for(MInt c = 0; c < noExtractedCells; c++) {
32104 cellIds.p[c] = m_extractedCells->a[c].m_cellId;
32105 }
32106
32107 // vtkGhostLevels
32108 const MInt noCh = (m_haloCellOutput) ? noCells : 1;
32109 ScratchSpace<unsigned char> vtkGhostLevels(noCh, AT_, "vtkGhostLevels");
32110 if(m_haloCellOutput) {
32111 for(MInt c = 0; c < noExtractedCells; c++) {
32112 vtkGhostLevels.p[c] = (unsigned char)0;
32113 if(a_isHalo(m_extractedCells->a[c].m_cellId)) vtkGhostLevels.p[c] = (unsigned char)1;
32114 if(a_hasProperty(m_extractedCells->a[c].m_cellId, SolverCell::IsNotGradient))
32115 vtkGhostLevels.p[c] = (unsigned char)2;
32116 }
32117 }
32118
32119#ifdef _MB_DEBUG_
32120
32121 // bndryIds
32122 ScratchSpace<MInt> bndryIds(noCells, AT_, "bndryIds");
32123 for(MInt c = 0; c < noExtractedCells; c++) {
32124 bndryIds.p[c] = a_bndryId(m_extractedCells->a[c].m_cellId);
32125 if(bndryIds.p[c] < 0 && a_hasProperty(m_extractedCells->a[c].m_cellId, SolverCell::IsInactive)) bndryIds.p[c] = -3;
32126 }
32127
32128 // drho_dt
32129 ScratchSpace<MFloat> drho_dt(noCells, AT_, "drho_dt");
32130 for(MInt c = 0; c < noExtractedCells; c++) {
32131 drho_dt.p[c] =
32132 a_FcellVolume(m_extractedCells->a[c].m_cellId) * a_rightHandSide(m_extractedCells->a[c].m_cellId, CV->RHO);
32133 }
32134
32135 // drhou_dt
32136 ScratchSpace<MFloat> drhou_dt(noCells, AT_, "drhou_dt");
32137 for(MInt c = 0; c < noExtractedCells; c++) {
32138 drhou_dt.p[c] = a_rightHandSide(m_extractedCells->a[c].m_cellId, CV->RHO_U);
32139 }
32140
32141 // levelSetFunction
32142 ScratchSpace<flt> levelSetFunction(noCells, AT_, "levelSetFunction");
32143 for(MInt c = 0; c < noExtractedCells; c++) {
32144 levelSetFunction.p[c] = (flt)a_levelSetValuesMb(m_extractedCells->a[c].m_cellId, 0);
32145 }
32146#endif
32147
32148 // additional cellData/pointData
32149 MInt asize = noCells;
32150 if(writePointData) {
32151 asize = noPoints;
32152 }
32153
32154 ScratchSpace<flt> pressure(asize, AT_, "pressure");
32155 ScratchSpace<flt> velocity(3 * asize, AT_, "velocity");
32156 ScratchSpace<flt> density(asize, AT_, "density");
32157 ScratchSpace<flt> vorticity(asize, AT_, "vorticity");
32158 ScratchSpace<flt> Qcriterion(asize, AT_, "Qcriterion");
32159 const MInt dSSize = entropyChangeOutput ? asize : 1;
32160 ScratchSpace<flt> dS(dSSize, AT_, "dS");
32161#ifdef _MB_DEBUG_
32162 ScratchSpace<flt> rhoE(asize, AT_, "rhoE");
32163 const MInt qtSize = QThresholdOutput ? asize : 1;
32164 ScratchSpace<flt> QThreshold(qtSize, AT_, "QThreshold");
32165#endif
32166
32167 MFloat tmp;
32168 MFloat weights[m_noCellNodes];
32169 if(writePointData) {
32170 for(MInt p = 0; p < noInternalGridPoints; p++) {
32171 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
32172 weights[n] = F0;
32173 }
32174 tmp = F0;
32175 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
32176 cellId = m_gridPoints->a[p].m_cellIds[n];
32177 if(a_bndryId(cellId) > -1) {
32178 weights[n] =
32179 F1
32180 / (sqrt(POW2(a_coordinate(cellId, 0) + m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_coordinates[0]
32181 - m_gridPoints->a[p].m_coordinates[0])
32182 + POW2(a_coordinate(cellId, 1) + m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_coordinates[1]
32183 - m_gridPoints->a[p].m_coordinates[1])));
32184 tmp += weights[n];
32185 } else {
32186 weights[n] = F1
32187 / (sqrt(POW2(a_coordinate(cellId, 0) - m_gridPoints->a[p].m_coordinates[0])
32188 + POW2(a_coordinate(cellId, 1) - m_gridPoints->a[p].m_coordinates[1])));
32189 tmp += weights[n];
32190 }
32191 }
32192 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
32193 weights[n] /= tmp;
32194 }
32195
32196 pressure.p[p] = (flt)F0;
32197 density.p[p] = (flt)F0;
32198 vorticity.p[p] = (flt)F0;
32199 Qcriterion.p[p] = (flt)F0;
32200 if(entropyChangeOutput) dS.p[p] = (flt)F0;
32201 for(MInt i = 0; i < nDim; i++) {
32202 velocity.p[3 * p + i] = (flt)F0;
32203 }
32204 velocity.p[3 * p + 2] = (flt)F0;
32205#ifdef _MB_DEBUG_
32206 rhoE.p[p] = (flt)F0;
32207 if(QThresholdOutput) QThreshold.p[p] = (flt)F0;
32208#endif
32209 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
32210 cellId = m_gridPoints->a[p].m_cellIds[n];
32211 pressure.p[p] += (flt)weights[n] * a_pvariable(cellId, PV->P);
32212 density.p[p] += (flt)weights[n] * a_pvariable(cellId, PV->RHO);
32213 // vorticity.p[ p ] += (flt)weights[ n ] * a_slope( cellId , 0 , 0 );
32214 vorticity.p[p] += (flt)weights[n] * qData(1, cellId);
32215 // Qcriterion.p[ p ] += (flt)weights[ n ] * a_slope( cellId , 2 , 0 );
32216 Qcriterion.p[p] += (flt)weights[n] * qData(0, cellId);
32217 if(entropyChangeOutput) dS.p[p] += (flt)weights[n] * (entropy(cellId) - m_SInfinity) / m_SInfinity;
32218 for(MInt i = 0; i < nDim; i++) {
32219 velocity.p[3 * p + i] += (flt)weights[n] * a_pvariable(cellId, PV->VV[i]);
32220 }
32221#ifdef _MB_DEBUG_
32222 rhoE.p[p] += (flt)weights[n] * a_variable(cellId, CV->RHO_E);
32223 if(QThresholdOutput) QThreshold.p[p] += (flt)weights[n] * qData(2, cellId);
32224#endif
32225 }
32226 }
32227 for(MInt p = noInternalGridPoints; p < noPoints; p++) {
32228 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
32229 weights[n] = F0;
32230 }
32231 tmp = F0;
32232 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
32233 cellId = m_gridPoints->a[p].m_cellIds[n];
32234 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
32235 if(a_bndryId(cellId) < 0) continue;
32236 weights[n] = F1
32237 / (sqrt(POW2(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_coordinates[0]
32238 - m_gridPoints->a[p].m_coordinates[0])
32239 + POW2(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_coordinates[1]
32240 - m_gridPoints->a[p].m_coordinates[1])));
32241 tmp += weights[n];
32242 }
32243 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
32244 weights[n] /= tmp;
32245 }
32246 pressure.p[p] = (flt)F0;
32247 density.p[p] = (flt)F0;
32248 vorticity.p[p] = (flt)F0;
32249 Qcriterion.p[p] = (flt)F0;
32250 if(entropyChangeOutput) dS.p[p] = (flt)F0;
32251 for(MInt i = 0; i < nDim; i++) {
32252 velocity.p[3 * p + i] = (flt)F0;
32253 }
32254 velocity.p[3 * p + 2] = F0;
32255#ifdef _MB_DEBUG_
32256 rhoE.p[p] = (flt)F0;
32257 if(QThresholdOutput) QThreshold.p[p] = (flt)F0;
32258#endif
32259 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
32260 cellId = m_gridPoints->a[p].m_cellIds[n];
32261 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
32262 if(a_bndryId(cellId) < 0) continue;
32263 ghostCellId = m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcVariables[0]->m_ghostCellId;
32264 if(a_bndryId(cellId) < m_noOuterBndryCells) {
32265 MFloat pb = F1B2 * (a_pvariable(cellId, PV->P) + a_pvariable(ghostCellId, PV->P));
32266 MFloat rhob = F1B2 * (a_pvariable(cellId, PV->RHO) + a_pvariable(ghostCellId, PV->RHO));
32267 pressure.p[p] += (flt)weights[n] * pb;
32268 density.p[p] += (flt)weights[n] * rhob;
32269 vorticity.p[p] += (flt)weights[n] * qData(1, cellId); // a_slope( cellId , 0 , 0 );
32270 Qcriterion.p[p] += (flt)weights[n] * qData(0, cellId); // a_slope( cellId , 2 , 0 );
32271 MFloat SG = sysEqn().entropy(pb, rhob);
32272 if(entropyChangeOutput) dS.p[p] += (flt)weights[n] * (SG - m_SInfinity) / m_SInfinity;
32273 for(MInt i = 0; i < nDim; i++) {
32274 velocity.p[3 * p + i] +=
32275 (flt)weights[n] * F1B2 * (a_pvariable(cellId, PV->VV[i]) + a_pvariable(ghostCellId, PV->VV[i]));
32276 }
32277#ifdef _MB_DEBUG_
32278 rhoE.p[p] += (flt)weights[n] * a_variable(cellId, CV->RHO_E);
32279 if(QThresholdOutput) QThreshold.p[p] += (flt)weights[n] * qData(2, cellId);
32280#endif
32281 } else {
32282 MInt bndryId = a_bndryId(cellId);
32283 pressure.p[p] += (flt)weights[n] * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->P];
32284 density.p[p] += (flt)weights[n] * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->RHO];
32285 vorticity.p[p] += (flt)weights[n] * qData(1, cellId); // a_slope( cellId , 0 , 0 );
32286 Qcriterion.p[p] += (flt)weights[n] * qData(0, cellId); // a_slope( cellId , 2 , 0 );
32287 MFloat SG = sysEqn().entropy(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->P],
32288 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->RHO]);
32289 if(entropyChangeOutput) dS.p[p] += (flt)weights[n] * (SG - m_SInfinity) / m_SInfinity;
32290 for(MInt i = 0; i < nDim; i++) {
32291 velocity.p[3 * p + i] +=
32292 (flt)weights[n] * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->VV[i]];
32293 }
32294#ifdef _MB_DEBUG_
32295 rhoE.p[p] += (flt)weights[n] * a_variable(cellId, CV->RHO_E);
32296 if(QThresholdOutput) QThreshold.p[p] += (flt)weights[n] * qData(2, cellId);
32297#endif
32298 }
32299 }
32300 }
32301 } else {
32302 for(MInt c = 0; c < noExtractedCells; c++) {
32303 cellId = m_extractedCells->a[c].m_cellId;
32304 pressure.p[c] = (flt)a_pvariable(cellId, PV->P);
32305 density.p[c] = (flt)a_pvariable(cellId, PV->RHO);
32306 vorticity.p[c] = (flt)qData(1, cellId); // a_slope( cellId , 0 , 0 ) ;
32307 Qcriterion.p[c] = (flt)qData(0, cellId); // a_slope( cellId , 2 , 0 ) ;
32308 if(entropyChangeOutput) dS.p[c] = (flt)(entropy(cellId) - m_SInfinity) / m_SInfinity;
32309 for(MInt i = 0; i < nDim; i++) {
32310 velocity.p[3 * c + i] = (flt)a_pvariable(cellId, PV->VV[i]);
32311 }
32312 velocity.p[3 * c + 2] = (flt)F0;
32313#ifdef _MB_DEBUG_
32314 rhoE.p[c] = (flt)a_variable(cellId, CV->RHO_E);
32315 if(QThresholdOutput) QThreshold.p[c] = (flt)qData(2, cellId);
32316#endif
32317 }
32318 }
32319
32320 // WRITE
32321 if(domainId() == 0) {
32322 cerr << "write...";
32323 }
32324
32325 ofstream ofl;
32326 ofl.open(fileName.c_str(), ios_base::out | ios_base::trunc);
32327 if(ofl.is_open() && ofl.good()) {
32328 offset = 0;
32329
32330 // VTKFile
32331 ofl << "<?xml version=\"1.0\"?>" << endl;
32332 ofl << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
32333 ofl << "<UnstructuredGrid>" << endl;
32334
32335
32336 // FieldData
32337 ofl << "<FieldData>" << endl;
32338 ofl << "<DataArray type=\"" << dataType << "\" Name=\"time\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32339 << m_time << "\" RangeMax=\"" << m_time << "\">" << endl;
32340 ofl << m_time << endl;
32341 ofl << "</DataArray>" << endl;
32342 ofl << "<DataArray type=\"" << dataType
32343 << "\" Name=\"physicalTime\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\"" << m_physicalTime
32344 << "\" RangeMax=\"" << m_physicalTime << "\">" << endl;
32345 ofl << m_physicalTime << endl;
32346 ofl << "</DataArray>" << endl;
32347 ofl << "<DataArray type=\"" << dataType << "\" Name=\"timeStep\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32348 << timeStep() << "\" RangeMax=\"" << timeStep() << "\">" << endl;
32349 ofl << timeStep() << endl;
32350 ofl << "</DataArray>" << endl;
32351 ofl << "<DataArray type=\"" << iDataType
32352 << "\" Name=\"globalTimeStep\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\"" << globalTimeStep
32353 << "\" RangeMax=\"" << globalTimeStep << "\">" << endl;
32354 ofl << globalTimeStep << endl;
32355 ofl << "</DataArray>" << endl;
32356 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Ma\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32357 << m_Ma << "\" RangeMax=\"" << m_Ma << "\">" << endl;
32358 ofl << m_Ma << endl;
32359 ofl << "</DataArray>" << endl;
32360 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Re\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32361 << m_Re << "\" RangeMax=\"" << m_Re << "\">" << endl;
32362 ofl << m_Re << endl;
32363 ofl << "</DataArray>" << endl;
32364 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Pr\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32365 << m_Pr << "\" RangeMax=\"" << m_Pr << "\">" << endl;
32366 ofl << m_Pr << endl;
32367 ofl << "</DataArray>" << endl;
32368 ofl << "<DataArray type=\"" << dataType << "\" Name=\"gamma\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32369 << m_gamma << "\" RangeMax=\"" << m_gamma << "\">" << endl;
32370 ofl << m_gamma << endl;
32371 ofl << "</DataArray>" << endl;
32372 ofl << "<DataArray type=\"" << dataType << "\" Name=\"CFL\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32373 << m_cfl << "\" RangeMax=\"" << m_cfl << "\">" << endl;
32374 ofl << m_cfl << endl;
32375 ofl << "</DataArray>" << endl;
32376 ofl << "<DataArray type=\"" << dataType << "\" Name=\"uInf\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32377 << m_UInfinity << "\" RangeMax=\"" << m_UInfinity << "\">" << endl;
32378 ofl << m_UInfinity << endl;
32379 ofl << "</DataArray>" << endl;
32380 ofl << "<DataArray type=\"" << dataType << "\" Name=\"vInf\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32381 << m_VInfinity << "\" RangeMax=\"" << m_VInfinity << "\">" << endl;
32382 ofl << m_VInfinity << endl;
32383 ofl << "</DataArray>" << endl;
32384 ofl << "<DataArray type=\"" << dataType << "\" Name=\"pInf\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32385 << m_PInfinity << "\" RangeMax=\"" << m_PInfinity << "\">" << endl;
32386 ofl << m_PInfinity << endl;
32387 ofl << "</DataArray>" << endl;
32388 ofl << "<DataArray type=\"" << dataType << "\" Name=\"rhoInf\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
32389 << m_rhoInfinity << "\" RangeMax=\"" << m_rhoInfinity << "\">" << endl;
32390 ofl << m_rhoInfinity << endl;
32391 ofl << "</DataArray>" << endl;
32392 ofl << "</FieldData>" << endl;
32393
32394 // Dimensions
32395 ofl << "<Piece NumberOfPoints=\"" << noPoints << "\" NumberOfCells=\"" << noCells << "\">" << endl;
32396
32397 // Points
32398 ofl << "<Points>" << endl;
32399 ofl << "<DataArray type=\"" << dataType << "\" NumberOfComponents=\"3\" format=\"appended\" offset=\"" << offset
32400 << "\"/>" << endl;
32401 offset += points.m_memsize + sizeof(MUint);
32402 ofl << "</Points>" << endl;
32403
32404 // Cells
32405 ofl << "<Cells>" << endl;
32406 ofl << "<DataArray type=\"" << uIDataType << "\" Name=\"connectivity\" format=\"appended\" offset=\"" << offset
32407 << "\"/>" << endl;
32408 offset += connectivity.m_memsize + sizeof(MUint);
32409
32410 ofl << "<DataArray type=\"" << uIDataType << "\" Name=\"offsets\" format=\"appended\" offset=\"" << offset << "\"/>"
32411 << endl;
32412 offset += offsets.m_memsize + sizeof(MUint);
32413
32414 ofl << "<DataArray type=\"" << uI8DataType << "\" Name=\"types\" format=\"appended\" offset=\"" << offset << "\"/>"
32415 << endl;
32416 offset += types.m_memsize + sizeof(MUint);
32417
32418 ofl << "</Cells>" << endl;
32419
32420 // CellData/PointData
32421 ofl << "<CellData Scalars=\"scalars\">" << endl;
32422
32423 ofl << "<DataArray type=\"" << iDataType << "\" Name=\"cellIds\" format=\"appended\" offset=\"" << offset << "\"/>"
32424 << endl;
32425 offset += cellIds.m_memsize + sizeof(MUint);
32426
32427 if(m_haloCellOutput) {
32428 ofl << "<DataArray type=\"" << uI8DataType << "\" Name=\"vtkGhostLevels\" format=\"appended\" offset=\"" << offset
32429 << "\"/>" << endl;
32430 offset += vtkGhostLevels.m_memsize + sizeof(MUint);
32431 }
32432
32433#ifdef _MB_DEBUG_
32434
32435 ofl << "<DataArray type=\"" << iDataType << "\" Name=\"bndryIds\" format=\"appended\" offset=\"" << offset << "\"/>"
32436 << endl;
32437 offset += bndryIds.m_memsize + sizeof(MUint);
32438
32439 ofl << "<DataArray type=\"" << dataType64 << "\" Name=\"drho_dt\" format=\"appended\" offset=\"" << offset << "\"/>"
32440 << endl;
32441 offset += drho_dt.m_memsize + sizeof(MUint);
32442
32443 ofl << "<DataArray type=\"" << dataType64 << "\" Name=\"drhou_dt\" format=\"appended\" offset=\"" << offset
32444 << "\"/>" << endl;
32445 offset += drhou_dt.m_memsize + sizeof(MUint);
32446
32447 ofl << "<DataArray type=\"" << dataType << "\" Name=\"levelSetFunction\" format=\"appended\" offset=\"" << offset
32448 << "\"/>" << endl;
32449 offset += levelSetFunction.m_memsize + sizeof(MUint);
32450
32451 if(sensorOutput) {
32452 ofl << "<DataArray type=\"" << dataType << "\" Name=\"tauC\" format=\"appended\" offset=\"" << offset << "\"/>"
32453 << endl;
32454 offset += tauC.m_memsize + sizeof(MUint);
32455 ofl << "<DataArray type=\"" << dataType << "\" Name=\"tauE\" format=\"appended\" offset=\"" << offset << "\"/>"
32456 << endl;
32457 offset += tauE.m_memsize + sizeof(MUint);
32458 }
32459
32460#endif
32461
32462 if(writePointData) {
32463 ofl << "</CellData>" << endl;
32464 ofl << "<PointData Scalars=\"scalars\">" << endl;
32465 }
32466
32467 ofl << "<DataArray type=\"" << dataType << "\" Name=\"pressure\" format=\"appended\" offset=\"" << offset << "\"/>"
32468 << endl;
32469 offset += pressure.m_memsize + sizeof(MUint);
32470
32471 ofl << "<DataArray type=\"" << dataType
32472 << "\" Name=\"velocity\" NumberOfComponents=\"3\" format=\"appended\" offset=\"" << offset << "\"/>" << endl;
32473 offset += velocity.m_memsize + sizeof(MUint);
32474
32475 ofl << "<DataArray type=\"" << dataType << "\" Name=\"density\" format=\"appended\" offset=\"" << offset << "\"/>"
32476 << endl;
32477 offset += density.m_memsize + sizeof(MUint);
32478
32479 ofl << "<DataArray type=\"" << dataType << "\" Name=\"vorticity\" format=\"appended\" offset=\"" << offset << "\"/>"
32480 << endl;
32481 offset += vorticity.m_memsize + sizeof(MUint);
32482
32483 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Qcriterion\" format=\"appended\" offset=\"" << offset
32484 << "\"/>" << endl;
32485 offset += Qcriterion.m_memsize + sizeof(MUint);
32486
32487 if(entropyChangeOutput) {
32488 ofl << "<DataArray type=\"" << dataType << "\" Name=\"dS\" format=\"appended\" offset=\"" << offset << "\"/>"
32489 << endl;
32490 offset += dS.m_memsize + sizeof(MUint);
32491 }
32492
32493#ifdef _MB_DEBUG_
32494
32495 ofl << "<DataArray type=\"" << dataType << "\" Name=\"rhoE\" format=\"appended\" offset=\"" << offset << "\"/>"
32496 << endl;
32497 offset += rhoE.m_memsize + sizeof(MUint);
32498
32499 if(QThresholdOutput) {
32500 ofl << "<DataArray type=\"" << dataType << "\" Name=\"QThreshold\" format=\"appended\" offset=\"" << offset
32501 << "\"/>" << endl;
32502 offset += QThreshold.m_memsize + sizeof(MUint);
32503 }
32504
32505#endif
32506 if(writePointData) {
32507 ofl << "</PointData>" << endl;
32508 } else {
32509 ofl << "</CellData>" << endl;
32510 }
32511
32512 ofl << "</Piece>" << endl;
32513 ofl << "</UnstructuredGrid>" << endl;
32514
32515
32516 // AppendedData
32517 ofl << "<AppendedData encoding=\"raw\">" << endl;
32518 ofl << "_";
32519 ofl.close();
32520 ofl.clear();
32521 } else {
32522 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing! (1)" << endl;
32523 }
32524 ofl.open(fileName.c_str(), ios_base::out | ios_base::app | ios_base::binary);
32525 if(ofl.is_open() && ofl.good()) {
32526 // point coordinates
32527 uinumber = (MUint)points.m_memsize;
32528 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(MUint));
32529 ofl.write(reinterpret_cast<const char*>(points.getPointer()), uinumber);
32530
32531 // connectivity
32532 uinumber = (MUint)connectivity.m_memsize;
32533 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(MUint));
32534 ofl.write(reinterpret_cast<const char*>(connectivity.getPointer()), uinumber);
32535
32536 // offsets
32537 uinumber = (MUint)offsets.m_memsize;
32538 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32539 ofl.write(reinterpret_cast<const char*>(offsets.getPointer()), uinumber);
32540
32541 // cell types
32542 uinumber = (MUint)types.m_memsize;
32543 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32544 ofl.write(reinterpret_cast<const char*>(types.getPointer()), uinumber);
32545
32546 // cellIds
32547 uinumber = (MUint)cellIds.m_memsize;
32548 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32549 ofl.write(reinterpret_cast<const char*>(cellIds.getPointer()), uinumber);
32550
32551 // vtkGhostLevels
32552 if(m_haloCellOutput) {
32553 uinumber = (MUint)vtkGhostLevels.m_memsize;
32554 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32555 ofl.write(reinterpret_cast<const char*>(vtkGhostLevels.getPointer()), uinumber);
32556 }
32557
32558#ifdef _MB_DEBUG_
32559
32560 // bndryIds
32561 uinumber = (MUint)bndryIds.m_memsize;
32562 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32563 ofl.write(reinterpret_cast<const char*>(bndryIds.getPointer()), uinumber);
32564
32565 // drho_dt
32566 uinumber = (MUint)drho_dt.m_memsize;
32567 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32568 ofl.write(reinterpret_cast<const char*>(drho_dt.getPointer()), uinumber);
32569
32570 // drhou_dt
32571 uinumber = (MUint)drhou_dt.m_memsize;
32572 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32573 ofl.write(reinterpret_cast<const char*>(drhou_dt.getPointer()), uinumber);
32574
32575 // levelSetFunction
32576 uinumber = (MUint)levelSetFunction.m_memsize;
32577 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32578 ofl.write(reinterpret_cast<const char*>(levelSetFunction.getPointer()), uinumber);
32579
32580 // tauC / tauE
32581 if(sensorOutput) {
32582 uinumber = (MUint)tauC.m_memsize;
32583 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32584 ofl.write(reinterpret_cast<const char*>(tauC.getPointer()), uinumber);
32585 uinumber = (MUint)tauE.m_memsize;
32586 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32587 ofl.write(reinterpret_cast<const char*>(tauE.getPointer()), uinumber);
32588 }
32589
32590#endif
32591
32592 // pressure
32593 uinumber = (MUint)pressure.m_memsize;
32594 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32595 ofl.write(reinterpret_cast<const char*>(pressure.getPointer()), uinumber);
32596
32597 // velocity
32598 uinumber = (MUint)velocity.m_memsize;
32599 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32600 ofl.write(reinterpret_cast<const char*>(velocity.getPointer()), uinumber);
32601
32602 // density
32603 uinumber = (MUint)density.m_memsize;
32604 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32605 ofl.write(reinterpret_cast<const char*>(density.getPointer()), uinumber);
32606
32607 // vorticity
32608 uinumber = (MUint)vorticity.m_memsize;
32609 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32610 ofl.write(reinterpret_cast<const char*>(vorticity.getPointer()), uinumber);
32611
32612 // Qcriterion
32613 uinumber = (MUint)Qcriterion.m_memsize;
32614 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32615 ofl.write(reinterpret_cast<const char*>(Qcriterion.getPointer()), uinumber);
32616
32617 if(entropyChangeOutput) {
32618 // dS
32619 uinumber = (MUint)dS.m_memsize;
32620 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32621 ofl.write(reinterpret_cast<const char*>(dS.getPointer()), uinumber);
32622 }
32623
32624#ifdef _MB_DEBUG_
32625 // rhoE
32626 uinumber = (MUint)rhoE.m_memsize;
32627 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32628 ofl.write(reinterpret_cast<const char*>(rhoE.getPointer()), uinumber);
32629
32630 if(QThresholdOutput) {
32631 // QThreshold
32632 uinumber = (MUint)QThreshold.m_memsize;
32633 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
32634 ofl.write(reinterpret_cast<const char*>(QThreshold.getPointer()), uinumber);
32635 }
32636
32637#endif
32638
32639 ofl.close();
32640 ofl.clear();
32641 } else {
32642 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing! (2)" << endl;
32643 }
32644
32645 ofl.open(fileName.c_str(), ios_base::out | ios_base::app);
32646 if(ofl.is_open() && ofl.good()) {
32647 ofl << endl;
32648 ofl << "</AppendedData>" << endl;
32649
32650 ofl << "</VTKFile>" << endl;
32651 ofl.close();
32652 ofl.clear();
32653 } else {
32654 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing! (3)" << endl;
32655 }
32656}
32657
32658
32663template <MInt nDim, class SysEqn>
32664template <class _, std::enable_if_t<nDim == 3, _*>>
32665void FvMbCartesianSolverXD<nDim, SysEqn>::writeVtkXmlOutput(const MString& /*fileName*/, MBool /*debugOutput*/) {}
32666
32667
32672template <MInt nDim, class SysEqn>
32673template <class _, std::enable_if_t<nDim == 2, _*>>
32675 TRACE();
32676
32677 MInt noCells = 1;
32678 MInt noPoints = 1;
32679
32680 MBool writePointData = false;
32681 writePointData = Context::getSolverProperty<MBool>("writePointData", solverId(), AT_, &writePointData);
32682
32683#ifdef _MB_DEBUG_
32684 MBool sensorOutput = m_adaptation;
32685#endif
32686 MBool QThresholdOutput = true;
32687 MBool entropyChangeOutput = true;
32688
32689 const MInt baseCellType = 8;
32690 const MInt polyCellType = 7;
32691 MInt cellId, ghostCellId, counter;
32692
32693 const string dataType64 = "Float64";
32694#ifdef DOUBLE_PRECISION_OUTPUT
32695 const string dataType = "Float64";
32696#else
32697 const string dataType = "Float32";
32698#endif
32699 const string iDataType = "Int32";
32700 const string uIDataType = "UInt32";
32701 const string uI8DataType = "UInt8";
32702 const string uI16DataType = "UInt16";
32703
32704 MUint uinumber;
32705#ifdef DOUBLE_PRECISION_OUTPUT
32706 MFloat fnumber;
32707 typedef MFloat flt;
32708#else
32709 // float fnumber;
32710 typedef float flt;
32711#endif
32712
32713 if(noDomains() == 1) {
32714 cerr << "extracted";
32715 cerr << "(" << m_extractedCells->size() << ")...";
32716 }
32717
32718 noPoints = m_gridPoints->size();
32719 MInt noExtractedCells = m_extractedCells->size();
32720 noCells = noExtractedCells;
32721
32722 // 4 node ids for each direction
32723 const MInt ltable[4][3] = {{2, 3}, {0, 2}, {1, 0}, {3, 1}};
32724 const MInt pointOrder[4] = {0, 1, 3, 2};
32725 const MInt dirOrder[4] = {2, 1, 3, 0};
32726 const MInt reverseDir[4] = {1, 0, 3, 2};
32727
32728 MInt centerId;
32729
32730 ScratchSpace<MInt> cellTypes(noExtractedCells, AT_, "cellTypes");
32731 ScratchSpace<MInt> polyIds(noExtractedCells, AT_, "polyIds");
32732 ScratchSpace<MInt> reverseMapping(a_noCells(), AT_, "reverseMapping");
32733 ScratchSpace<MInt> cutPointIds(2 * m_noDirs * m_fvBndryCnd->m_bndryCells->size(), AT_, "cutPointIds");
32734
32735 MInt noPolyCells;
32736
32737 // integrity check 1
32738 for(MInt c = 0; c < noExtractedCells; c++) {
32739 cellId = m_extractedCells->a[c].m_cellId;
32740 for(MInt k = 0; k < m_noCellNodes; k++) {
32741 MInt pid = m_extractedCells->a[c].m_pointIds[k];
32742 if(pid < 0 || pid >= noPoints) {
32743 mTerm(1, AT_,
32744 "Error A in FvMbSolver2D::writeVtkXmlOutput_MGC(..). Quit. " + to_string(cellId) + " " + to_string(k)
32745 + " " + to_string(pid));
32746 }
32747 }
32748 }
32749
32750 for(MInt i = 0; i < 2 * m_noDirs * m_fvBndryCnd->m_bndryCells->size(); i++) {
32751 cutPointIds.p[i] = -1;
32752 }
32753
32754 if(noDomains() == 1) {
32755 cerr << "prepare...";
32756 }
32757 for(MInt c = 0; c < a_noCells(); c++) {
32758 reverseMapping.p[c] = -1;
32759 }
32760 for(MInt c = 0; c < noExtractedCells; c++) {
32761 reverseMapping.p[m_extractedCells->a[c].m_cellId] = c;
32762 }
32763
32764 MBool isPolyCell;
32765 noPolyCells = 0;
32766
32767 for(MInt c = 0; c < noExtractedCells; c++) {
32768 cellId = m_extractedCells->a[c].m_cellId;
32769 cellTypes.p[c] = baseCellType;
32770 polyIds.p[c] = -1;
32771 isPolyCell = false;
32772 if(a_bndryId(cellId) > -1) {
32773 isPolyCell = true;
32774 } else {
32775 for(MInt i = 0; i < m_noDirs; i++) {
32776 if(checkNeighborActive(cellId, i) && a_hasNeighbor(cellId, i) > 0) {
32777 if(c_noChildren(c_neighborId(cellId, i)) > 0) {
32778 isPolyCell = true;
32779 MInt nghbrId = c_neighborId(cellId, i);
32780 if(nghbrId < 0) continue;
32781 for(MInt j = 0; j < m_noCellNodes; j++) {
32782 MInt childId = c_childId(nghbrId, j);
32783 if(reverseMapping.p[childId] < 0) {
32784 isPolyCell = false;
32785 }
32786 }
32787 }
32788 }
32789 }
32790 }
32791 if(isPolyCell) {
32792 cellTypes.p[c] = polyCellType;
32793 polyIds.p[c] = noPolyCells;
32794 noPolyCells++;
32795 }
32796 }
32797
32798 MBool isPolyFace;
32799 MInt eCell, nghbrId;
32800 const MInt maxNoExtraPoints = 8;
32801 const MInt maxNoPolyCells = noPolyCells;
32802 ScratchSpace<MInt> polyCellLink(maxNoPolyCells, AT_, "polyCellLink");
32803 ScratchSpace<MInt> extraPoints(maxNoPolyCells * maxNoExtraPoints, AT_, "extraPoints");
32804 ScratchSpace<MInt> noExtraPoints(maxNoPolyCells, AT_, "noExtraPoints");
32805 ScratchSpace<MInt> noInternalPoints(maxNoPolyCells, AT_, "noInternalPoints");
32806 MInt offset, pointCount;
32807
32808 for(MInt c = 0; c < noExtractedCells; c++) {
32809 if(cellTypes.p[c] == polyCellType) {
32810 polyCellLink.p[polyIds.p[c]] = c;
32811 }
32812 }
32813
32814
32815 const MInt noInternalGridPoints = m_gridPoints->size();
32816 const MInt maxPointsXD = 12;
32817
32818 for(MInt pc = 0; pc < noPolyCells; pc++) {
32819 eCell = polyCellLink.p[pc];
32820 cellId = m_extractedCells->a[eCell].m_cellId;
32821 noInternalPoints.p[pc] = m_noCellNodes;
32822 noExtraPoints.p[pc] = 0;
32823
32824 // a) cut cells at the boundary
32825 if(a_bndryId(cellId) > -1) {
32826 if(a_bndryId(cellId) < m_noOuterBndryCells) {
32827 MInt bndryId = a_bndryId(cellId);
32828
32829 noInternalPoints.p[pc] = 0;
32830
32831 for(MInt i = 0; i < m_noDirs; i++) {
32832 MInt p = pointOrder[i];
32833 MInt dir = dirOrder[i];
32834
32835 // 0. determine internal vertices
32836 if(!m_pointIsInside[bndryId][IDX_LSSETMB(p, 0)]) {
32837 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = m_extractedCells->a[eCell].m_pointIds[p];
32838 noExtraPoints.p[pc]++;
32839 }
32840
32841 // 1. add cut points
32842 for(MInt cp = 0; cp < m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
32843 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cp] == dir) {
32844 MInt gridPointId = -1;
32845 if(checkNeighborActive(cellId, dir) && a_hasNeighbor(cellId, dir) > 0) {
32846 if(a_bndryId(c_neighborId(cellId, dir)) > -1) {
32847 gridPointId = cutPointIds.p[m_noDirs * a_bndryId(c_neighborId(cellId, dir)) + reverseDir[dir]];
32848 if(gridPointId > -1) {
32849 m_gridPoints->a[gridPointId].m_cellIds[m_gridPoints->a[gridPointId].m_noAdjacentCells] = cellId;
32850 m_gridPoints->a[gridPointId].m_noAdjacentCells++;
32851 }
32852 }
32853 }
32854 if(gridPointId >= noPoints) {
32855 mTerm(1, AT_, "Error 0 in FvMbSolver3D::writeVtkXmlOutput(..). Quit.");
32856 }
32857 if(gridPointId < 0) {
32858 gridPointId = m_gridPoints->size();
32860 noPoints++;
32861 m_gridPoints->a[gridPointId].m_noAdjacentCells = 1;
32862 m_gridPoints->a[gridPointId].m_cellIds[0] = cellId;
32863 for(MInt j = 0; j < nDim; j++) {
32864 m_gridPoints->a[gridPointId].m_coordinates[j] =
32865 m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_cutCoordinates[cp][j];
32866 }
32867 }
32868 cutPointIds.p[m_noDirs * bndryId + dir] = gridPointId;
32869
32870 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = gridPointId;
32871 noExtraPoints.p[pc]++;
32872 }
32873 }
32874 }
32875 } else {
32876 MInt bndryId = a_bndryId(cellId);
32877 noInternalPoints.p[pc] = 0;
32878 for(MInt f = 0; f < m_noCutCellFaces[bndryId]; f++) {
32879 for(MInt fp = 0; fp < m_noCutFacePoints[bndryId][f]; fp++) {
32880 MInt point = m_cutFacePointIds[bndryId][maxPointsXD * f + fp];
32881 if(point < m_noCellNodes) { // is grid point
32882 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = m_extractedCells->a[eCell].m_pointIds[point];
32883 noExtraPoints.p[pc]++;
32884 } else { // is cut point
32885 point -= m_noCellNodes;
32886 // first try: just add cut point!
32887 MInt gridPointId = m_gridPoints->size();
32889 noPoints++;
32890 m_gridPoints->a[gridPointId].m_noAdjacentCells = 1;
32891 m_gridPoints->a[gridPointId].m_cellIds[0] = cellId;
32892
32893 // find right cut point:
32894 MInt previousCutPoints = -1;
32895 MInt pointFound = false;
32896 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
32897 for(MInt cp = 0; cp < m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_noCutPoints; cp++) {
32898 previousCutPoints++;
32899 if(previousCutPoints == point) {
32900 for(MInt j = 0; j < nDim; j++) {
32901 m_gridPoints->a[gridPointId].m_coordinates[j] =
32902 m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[srfc]->m_cutCoordinates[cp][j];
32903 }
32904 pointFound = true;
32905 break;
32906 }
32907 }
32908 if(pointFound) break;
32909 }
32910 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = gridPointId;
32911 noExtraPoints.p[pc]++;
32912 }
32913 }
32914 }
32915 }
32916 }
32917 // b) cells at fine/coarse mesh interfaces
32918 else {
32919 noInternalPoints.p[pc] = 0;
32920
32921 for(MInt i = 0; i < m_noDirs; i++) {
32922 MInt p = pointOrder[i];
32923 MInt dir = dirOrder[i];
32924
32925 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = m_extractedCells->a[eCell].m_pointIds[p];
32926 noExtraPoints.p[pc]++;
32927
32928 isPolyFace = false;
32929 if(checkNeighborActive(cellId, dir) && a_hasNeighbor(cellId, dir) > 0) {
32930 nghbrId = c_neighborId(cellId, dir);
32931 if(c_noChildren(nghbrId) > 0) {
32932 isPolyFace = true;
32933 for(MInt child = 0; child < m_noCellNodes; child++) {
32934 if(!childCode[dir][child]) continue;
32935 MInt childId = c_childId(nghbrId, child);
32936 if(childId < 0) {
32937 isPolyFace = false;
32938 }
32939 if(reverseMapping.p[childId] < 0) {
32940 isPolyFace = false;
32941 }
32942 }
32943 }
32944 }
32945
32946 if(isPolyFace) {
32947 // store four faces (polygon numbering!)
32948 nghbrId = reverseMapping.p[c_childId(c_neighborId(cellId, dir), ltable[i][0])];
32949 if(nghbrId < 0) {
32950 cerr << "=== VTK XML ERROR LOG === " << domainId() << endl;
32951 cerr << endl
32952 << cellId << " " << a_bndryId(cellId) << " " << c_childId(c_neighborId(cellId, dir), ltable[i][0])
32953 << endl;
32954 cerr << endl << a_noCells() << " " << dir << " " << ltable[i][0] << endl;
32955 cerr << a_levelSetValuesMb(cellId, 0) << " " << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
32956 cerr << "props: " << a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) << " " << a_isHalo(cellId) << " "
32957 << a_hasProperty(cellId, SolverCell::IsNotGradient) << " "
32958 << a_hasProperty(c_neighborId(cellId, dir), SolverCell::IsOnCurrentMGLevel) << " "
32959 << a_hasProperty(c_childId(c_neighborId(cellId, dir), ltable[i][0]), SolverCell::IsOnCurrentMGLevel)
32960 << endl;
32961 cerr << endl
32962 << cellId << " " << c_neighborId(cellId, dir) << " "
32963 << c_childId(c_neighborId(cellId, dir), ltable[i][0]) << " / " << a_level(cellId) << " "
32964 << a_level(c_neighborId(cellId, dir)) << " "
32965 << a_level(c_childId(c_neighborId(cellId, dir), ltable[i][0])) << " / " << c_noChildren(cellId) << " "
32966 << c_noChildren(c_neighborId(cellId, dir)) << " "
32967 << c_noChildren(c_childId(c_neighborId(cellId, dir), ltable[i][0])) << endl;
32968 cerr << c_childId(c_neighborId(cellId, dir), 0) << " " << c_childId(c_neighborId(cellId, dir), 1) << " "
32969 << c_childId(c_neighborId(cellId, dir), 2) << " " << c_childId(c_neighborId(cellId, dir), 3) << endl;
32970 cerr << a_coordinate(c_neighborId(cellId, dir), 0) << " " << a_coordinate(c_neighborId(cellId, dir), 1)
32971 << endl;
32972 for(MInt j = 0; j < m_noCellNodes; j++) {
32973 cerr << a_hasProperty(c_childId(c_neighborId(cellId, dir), j), SolverCell::IsInactive) << " ";
32974 }
32975 cerr << endl;
32976 for(MInt j = 0; j < m_noCellNodes; j++) {
32977 cerr << a_hasProperty(c_childId(c_neighborId(cellId, dir), j), SolverCell::IsOnCurrentMGLevel) << " ";
32978 }
32979 cerr << endl;
32980 mTerm(1, AT_, "Error 1 in FvMbSolver2D::writeVtkXmlOutput_MGC(..). Quit.");
32981 }
32982 centerId = m_extractedCells->a[nghbrId].m_pointIds[ltable[i][1]];
32983 extraPoints.p[pc * maxNoExtraPoints + noExtraPoints.p[pc]] = centerId;
32984 noExtraPoints.p[pc]++;
32985
32986 if(m_gridPoints->a[centerId].m_noAdjacentCells < m_noCellNodes) {
32987 m_gridPoints->a[centerId].m_cellIds[m_gridPoints->a[centerId].m_noAdjacentCells] = cellId;
32988 m_gridPoints->a[centerId].m_noAdjacentCells++;
32989 } else {
32990 cerr << endl << cellId << " / ";
32991 for(MInt c = 0; c < m_gridPoints->a[centerId].m_noAdjacentCells; c++)
32992 cerr << m_gridPoints->a[centerId].m_cellIds[c] << " ";
32993 cerr << endl;
32994 mTerm(1, AT_, "Error 2 in FvMbSolver2D::writeVtkXmlOutput_MGC(..). Quit.");
32995 }
32996 }
32997 }
32998 }
32999 }
33000
33001 pointCount = 0;
33002 for(MInt c = 0; c < noExtractedCells; c++) {
33003 MInt pc = polyIds.p[c];
33004 if(pc > -1) {
33005 pointCount += noInternalPoints.p[pc];
33006 pointCount += noExtraPoints.p[pc];
33007 } else {
33008 pointCount += m_noCellNodes;
33009 }
33010 }
33011
33012 MInt qDataSize = 2;
33013 if(QThresholdOutput) qDataSize++;
33014 ScratchSpace<MFloat> qData(qDataSize, a_noCells(), AT_, "qData");
33015 MFloat gradU[2][2];
33016 for(MInt c = 0; c < noExtractedCells; c++) {
33017 cellId = m_extractedCells->a[c].m_cellId;
33018
33019 for(MInt i = 0; i < nDim; i++) {
33020 for(MInt j = 0; j < nDim; j++) {
33021 gradU[i][j] = a_slope(cellId, PV->VV[i], j) * m_referenceLength / m_UInfinity;
33022 }
33023 }
33024 MFloat omega = F1B2 * (gradU[1][0] - gradU[0][1]);
33025 MFloat omega2 = POW2(omega);
33026 MFloat S2 = 0;
33027 for(MInt i = 0; i < nDim; i++) {
33028 for(MInt j = 0; j < nDim; j++) {
33029 S2 += POW2(F1B2 * (gradU[i][j] + gradU[j][i]));
33030 }
33031 }
33032 MFloat Q = F1B2 * (omega2 - S2);
33033 qData(0, cellId) = Q;
33034 qData(1, cellId) = omega;
33035 if(QThresholdOutput) qData(2, cellId) = F1B2 * ((omega2 / mMax(m_eps, S2)) - F1);
33036 }
33037
33038 // GATHER
33039 if(noDomains() == 1) {
33040 cerr << "gather...";
33041 }
33042
33043 // points
33044 ScratchSpace<flt> points(3 * noPoints, AT_, "points");
33045 for(MInt p = 0; p < noPoints; p++) {
33046 for(MInt i = 0; i < nDim; i++) {
33047 points.p[3 * p + i] = (flt)m_gridPoints->a[p].m_coordinates[i];
33048 }
33049 points.p[3 * p + 2] = (flt)F0;
33050 }
33051
33052 // connectivity
33053 ScratchSpace<MUint> connectivity(pointCount, AT_, "connectivity");
33054 counter = 0;
33055 for(MInt c = 0; c < noExtractedCells; c++) {
33056 MInt pc = polyIds.p[c];
33057 if(pc > -1) {
33058 for(MInt p = 0; p < noExtraPoints.p[pc]; p++) {
33059 connectivity.p[counter] = (MUint)extraPoints.p[pc * maxNoExtraPoints + p];
33060 counter++;
33061 }
33062 } else {
33063 for(MInt p = 0; p < m_noCellNodes; p++) {
33064 connectivity.p[counter] = (MUint)m_extractedCells->a[c].m_pointIds[p];
33065 counter++;
33066 }
33067 }
33068 }
33069
33070 if(counter != pointCount) {
33071 mTerm(1, AT_, "E1");
33072 }
33073
33074 // offsets
33075 ScratchSpace<MUint> offsets(noCells, AT_, "offsets");
33076 counter = 0;
33077 for(MInt c = 0; c < noExtractedCells; c++) {
33078 MInt pc = polyIds.p[c];
33079 if(pc > -1)
33080 counter += noInternalPoints.p[pc] + noExtraPoints.p[pc];
33081 else
33082 counter += m_noCellNodes;
33083
33084 offsets.p[c] = (MUint)counter;
33085 }
33086
33087 // types
33088 ScratchSpace<unsigned char> types(noCells, AT_, "types");
33089 for(MInt c = 0; c < noExtractedCells; c++) {
33090 types.p[c] = (unsigned char)cellTypes.p[c];
33091 }
33092
33093 // cellIds
33094 ScratchSpace<MInt> cellIds(noCells, AT_, "cellIds");
33095 for(MInt c = 0; c < noExtractedCells; c++) {
33096 cellIds.p[c] = c_globalId(m_extractedCells->a[c].m_cellId);
33097 }
33098
33099 // vtkGhostLevels
33100 const MInt noCh = (m_haloCellOutput) ? noCells : 1;
33101 ScratchSpace<unsigned char> vtkGhostLevels(noCh, AT_, "vtkGhostLevels");
33102 if(m_haloCellOutput) {
33103 for(MInt c = 0; c < noExtractedCells; c++) {
33104 vtkGhostLevels.p[c] = (unsigned char)0;
33105 if(a_isHalo(m_extractedCells->a[c].m_cellId)) vtkGhostLevels.p[c] = (unsigned char)1;
33106 if(a_hasProperty(m_extractedCells->a[c].m_cellId, SolverCell::IsNotGradient))
33107 vtkGhostLevels.p[c] = (unsigned char)2;
33108 }
33109 }
33110
33111#ifdef _MB_DEBUG_
33112
33113 // bndryIds
33114 ScratchSpace<MInt> bndryIds(noCells, AT_, "bndryIds");
33115 for(MInt c = 0; c < noExtractedCells; c++) {
33116 bndryIds.p[c] = a_bndryId(m_extractedCells->a[c].m_cellId);
33117 if(bndryIds.p[c] < 0 && a_hasProperty(m_extractedCells->a[c].m_cellId, SolverCell::IsInactive)) bndryIds.p[c] = -3;
33118 }
33119
33120 // drho_dt
33121 ScratchSpace<MFloat> drho_dt(noCells, AT_, "drho_dt");
33122 for(MInt c = 0; c < noExtractedCells; c++) {
33123 drho_dt.p[c] =
33124 a_FcellVolume(m_extractedCells->a[c].m_cellId) * a_rightHandSide(m_extractedCells->a[c].m_cellId, CV->RHO);
33125 }
33126
33127 // drhou_dt
33128 ScratchSpace<MFloat> drhou_dt(noCells, AT_, "drhou_dt");
33129 for(MInt c = 0; c < noExtractedCells; c++) {
33130 drhou_dt.p[c] =
33131 a_FcellVolume(m_extractedCells->a[c].m_cellId) * a_rightHandSide(m_extractedCells->a[c].m_cellId, CV->RHO_U);
33132 }
33133
33134 // levelSetFunction
33135 ScratchSpace<flt> levelSetFunction(noCells, AT_, "levelSetFunction");
33136 for(MInt c = 0; c < noExtractedCells; c++) {
33137 levelSetFunction.p[c] = (flt)a_levelSetValuesMb(m_extractedCells->a[c].m_cellId, 0);
33138 }
33139
33140 // volume
33141 ScratchSpace<flt> volume(noCells, AT_, "volume");
33142 for(MInt c = 0; c < noExtractedCells; c++) {
33143 volume.p[c] = (flt)a_cellVolume(m_extractedCells->a[c).m_cellId]
33144 / grid().gridCellVolume(a_level(m_extractedCells->a[c].m_cellId));
33145 }
33146
33147 // spongeFac
33148 ScratchSpace<flt> spongeFac(noCells, AT_, "spongeFac");
33149 for(MInt c = 0; c < noExtractedCells; c++) {
33150 spongeFac.p[c] = (flt)a_spongeFactor(m_extractedCells->a[c].m_cellId);
33151 }
33152
33153 const MInt sensorSize = sensorOutput ? noCells : 1;
33154 ScratchSpace<flt> tauC(sensorSize, AT_, "tauC");
33155 ScratchSpace<flt> tauE(sensorSize, AT_, "tauE");
33156 if(sensorOutput) {
33157 for(MInt c = 0; c < noExtractedCells; c++) {
33158 tauC.p[c] = (flt)m_tauC[m_extractedCells->a[c].m_cellId];
33159 tauE.p[c] = (flt)m_tauE[m_extractedCells->a[c].m_cellId];
33160 }
33161 }
33162#endif
33163
33164 // additional cellData/pointData
33165 MInt asize = noCells;
33166 if(writePointData) {
33167 asize = noPoints;
33168 }
33169 ScratchSpace<flt> pressure(asize, AT_, "pressure");
33170 ScratchSpace<flt> velocity(3 * asize, AT_, "velocity");
33171 ScratchSpace<flt> density(asize, AT_, "density");
33172 ScratchSpace<flt> vorticity(asize, AT_, "vorticity");
33173 ScratchSpace<flt> Qcriterion(asize, AT_, "Qcriterion");
33174 const MInt dSSize = entropyChangeOutput ? asize : 1;
33175 ScratchSpace<flt> dS(dSSize, AT_, "dS");
33176#ifdef _MB_DEBUG_
33177 ScratchSpace<flt> rhoE(asize, AT_, "rhoE");
33178 const MInt qtSize = QThresholdOutput ? asize : 1;
33179 ScratchSpace<flt> QThreshold(qtSize, AT_, "QThreshold");
33180#endif
33181
33182 MFloat tmp;
33183 MFloat weights[m_noCellNodes];
33184 if(writePointData) {
33185 for(MInt p = 0; p < noInternalGridPoints; p++) {
33186 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
33187 weights[n] = F0;
33188 }
33189 tmp = F0;
33190 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
33191 cellId = m_gridPoints->a[p].m_cellIds[n];
33192 if(a_bndryId(cellId) > -1) {
33193 weights[n] =
33194 F1
33195 / (sqrt(POW2(a_coordinate(cellId, 0) + m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_coordinates[0]
33196 - m_gridPoints->a[p].m_coordinates[0])
33197 + POW2(a_coordinate(cellId, 1) + m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_coordinates[1]
33198 - m_gridPoints->a[p].m_coordinates[1])));
33199 tmp += weights[n];
33200 } else {
33201 weights[n] = F1
33202 / (sqrt(POW2(a_coordinate(cellId, 0) - m_gridPoints->a[p].m_coordinates[0])
33203 + POW2(a_coordinate(cellId, 1) - m_gridPoints->a[p].m_coordinates[1])));
33204 tmp += weights[n];
33205 }
33206 }
33207 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
33208 weights[n] /= tmp;
33209 }
33210
33211 pressure.p[p] = (flt)F0;
33212 density.p[p] = (flt)F0;
33213 vorticity.p[p] = (flt)F0;
33214 Qcriterion.p[p] = (flt)F0;
33215 if(entropyChangeOutput) dS.p[p] = (flt)F0;
33216 for(MInt i = 0; i < nDim; i++) {
33217 velocity.p[3 * p + i] = (flt)F0;
33218 }
33219 velocity.p[3 * p + 2] = (flt)F0;
33220#ifdef _MB_DEBUG_
33221 rhoE.p[p] = (flt)F0;
33222 if(QThresholdOutput) QThreshold.p[p] = (flt)F0;
33223#endif
33224 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
33225 cellId = m_gridPoints->a[p].m_cellIds[n];
33226 pressure.p[p] += (flt)weights[n] * a_pvariable(cellId, PV->P);
33227 density.p[p] += (flt)weights[n] * a_pvariable(cellId, PV->RHO);
33228 vorticity.p[p] += (flt)weights[n] * qData(1, cellId); // a_slope( cellId , 0 , 0 );
33229 Qcriterion.p[p] += (flt)weights[n] * qData(0, cellId); // a_slope( cellId , 2 , 0 );
33230 if(entropyChangeOutput) dS.p[p] += (flt)weights[n] * (entropy(cellId) - m_SInfinity) / m_SInfinity;
33231 for(MInt i = 0; i < nDim; i++) {
33232 velocity.p[3 * p + i] += (flt)weights[n] * a_pvariable(cellId, PV->VV[i]);
33233 }
33234#ifdef _MB_DEBUG_
33235 rhoE.p[p] += (flt)weights[n] * a_variable(cellId, CV->RHO_E);
33236 if(QThresholdOutput) QThreshold.p[p] += (flt)weights[n] * qData(2, cellId);
33237#endif
33238 }
33239 }
33240 for(MInt p = noInternalGridPoints; p < noPoints; p++) {
33241 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
33242 weights[n] = F0;
33243 }
33244 tmp = F0;
33245 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
33246 cellId = m_gridPoints->a[p].m_cellIds[n];
33247 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
33248 if(a_bndryId(cellId) < 0) continue;
33249 weights[n] = F1
33250 / (sqrt(POW2(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_coordinates[0]
33251 - m_gridPoints->a[p].m_coordinates[0])
33252 + POW2(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_coordinates[1]
33253 - m_gridPoints->a[p].m_coordinates[1])));
33254 tmp += weights[n];
33255 }
33256 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
33257 weights[n] /= tmp;
33258 }
33259 pressure.p[p] = (flt)F0;
33260 density.p[p] = (flt)F0;
33261 vorticity.p[p] = (flt)F0;
33262 Qcriterion.p[p] = (flt)F0;
33263 if(entropyChangeOutput) dS.p[p] = (flt)F0;
33264 for(MInt i = 0; i < nDim; i++) {
33265 velocity.p[3 * p + i] = (flt)F0;
33266 }
33267 velocity.p[3 * p + 2] = F0;
33268#ifdef _MB_DEBUG_
33269 rhoE.p[p] = (flt)F0;
33270 if(QThresholdOutput) QThreshold.p[p] = (flt)F0;
33271#endif
33272 for(MInt n = 0; n < m_gridPoints->a[p].m_noAdjacentCells; n++) {
33273 cellId = m_gridPoints->a[p].m_cellIds[n];
33274 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
33275 if(a_bndryId(cellId) < 0) continue;
33276 ghostCellId = m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcVariables[0]->m_ghostCellId;
33277 if(a_bndryId(cellId) < m_noOuterBndryCells) {
33278 MFloat pb = F1B2 * (a_pvariable(cellId, PV->P) + a_pvariable(ghostCellId, PV->P));
33279 MFloat rhob = F1B2 * (a_pvariable(cellId, PV->RHO) + a_pvariable(ghostCellId, PV->RHO));
33280 pressure.p[p] += (flt)weights[n] * pb;
33281 density.p[p] += (flt)weights[n] * rhob;
33282 vorticity.p[p] += (flt)weights[n] * qData(1, cellId); // a_slope( cellId , 0 , 0 );
33283 Qcriterion.p[p] += (flt)weights[n] * qData(0, cellId); // a_slope( cellId , 2 , 0 );
33284 MFloat SG = sysEqn().entropy(pb, rhob);
33285 if(entropyChangeOutput) dS.p[p] += (flt)weights[n] * (SG - m_SInfinity) / m_SInfinity;
33286 for(MInt i = 0; i < nDim; i++) {
33287 velocity.p[3 * p + i] +=
33288 (flt)weights[n] * F1B2 * (a_pvariable(cellId, PV->VV[i]) + a_pvariable(ghostCellId, PV->VV[i]));
33289 }
33290#ifdef _MB_DEBUG_
33291 rhoE.p[p] += (flt)weights[n] * a_variable(cellId, CV->RHO_E);
33292 if(QThresholdOutput) QThreshold.p[p] += (flt)weights[n] * qData(2, cellId);
33293#endif
33294 } else {
33295 MInt bndryId = a_bndryId(cellId);
33296 pressure.p[p] += (flt)weights[n] * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->P];
33297 density.p[p] += (flt)weights[n] * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->RHO];
33298 vorticity.p[p] += (flt)weights[n] * qData(1, cellId); // a_slope( cellId , 0 , 0 );
33299 Qcriterion.p[p] += (flt)weights[n] * qData(0, cellId); // a_slope( cellId , 2 , 0 );
33300 MFloat SG = sysEqn().entropy(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->P],
33301 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->RHO]);
33302 if(entropyChangeOutput) dS.p[p] += (flt)weights[n] * (SG - m_SInfinity) / m_SInfinity;
33303 for(MInt i = 0; i < nDim; i++) {
33304 velocity.p[3 * p + i] +=
33305 (flt)weights[n] * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_primVars[PV->VV[i]];
33306 }
33307#ifdef _MB_DEBUG_
33308 rhoE.p[p] += (flt)weights[n] * a_variable(cellId, CV->RHO_E);
33309 if(QThresholdOutput) QThreshold.p[p] += (flt)weights[n] * qData(2, cellId);
33310#endif
33311 }
33312 }
33313 }
33314 } else {
33315 for(MInt c = 0; c < noExtractedCells; c++) {
33316 cellId = m_extractedCells->a[c].m_cellId;
33317 pressure.p[c] = (flt)a_pvariable(cellId, PV->P);
33318 density.p[c] = (flt)a_pvariable(cellId, PV->RHO);
33319 vorticity.p[c] = (flt)qData(1, cellId); // a_slope( cellId , 0 , 0 ) ;
33320 Qcriterion.p[c] = (flt)qData(0, cellId); // a_slope( cellId , 2 , 0 ) ;
33321 if(entropyChangeOutput) dS.p[c] = (flt)(entropy(cellId) - m_SInfinity) / m_SInfinity;
33322 for(MInt i = 0; i < nDim; i++) {
33323 velocity.p[3 * c + i] = (flt)a_pvariable(cellId, PV->VV[i]);
33324 }
33325 velocity.p[3 * c + 2] = (flt)F0;
33326#ifdef _MB_DEBUG_
33327 rhoE.p[c] = (flt)a_variable(cellId, CV->RHO_E);
33328 if(QThresholdOutput) QThreshold.p[c] = (flt)qData(2, cellId);
33329#endif
33330 }
33331 }
33332
33333 // WRITE
33334 if(domainId() == 0) {
33335 cerr << "write...";
33336 }
33337
33338 ofstream ofl;
33339 ofl.open(fileName.c_str(), ios_base::out | ios_base::trunc);
33340 if(ofl.is_open() && ofl.good()) {
33341 offset = 0;
33342
33343 // VTKFile
33344 ofl << "<?xml version=\"1.0\"?>" << endl;
33345 ofl << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">" << endl;
33346 ofl << "<UnstructuredGrid>" << endl;
33347
33348 // FieldData
33349 ofl << "<FieldData>" << endl;
33350
33351 ofl << "<DataArray type=\"" << dataType << "\" Name=\"time\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33352 << m_time << "\" RangeMax=\"" << m_time << "\">" << endl;
33353 ofl << m_time << endl;
33354 ofl << "</DataArray>" << endl;
33355 ofl << "<DataArray type=\"" << dataType
33356 << "\" Name=\"physicalTime\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\"" << m_physicalTime
33357 << "\" RangeMax=\"" << m_physicalTime << "\">" << endl;
33358 ofl << m_physicalTime << endl;
33359 ofl << "</DataArray>" << endl;
33360 ofl << "<DataArray type=\"" << dataType << "\" Name=\"timeStep\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33361 << timeStep() << "\" RangeMax=\"" << timeStep() << "\">" << endl;
33362 ofl << timeStep() << endl;
33363 ofl << "</DataArray>" << endl;
33364 ofl << "<DataArray type=\"" << iDataType
33365 << "\" Name=\"globalTimeStep\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\"" << globalTimeStep
33366 << "\" RangeMax=\"" << globalTimeStep << "\">" << endl;
33367 ofl << globalTimeStep << endl;
33368 ofl << "</DataArray>" << endl;
33369 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Ma\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33370 << m_Ma << "\" RangeMax=\"" << m_Ma << "\">" << endl;
33371 ofl << m_Ma << endl;
33372 ofl << "</DataArray>" << endl;
33373 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Re\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33374 << m_Re << "\" RangeMax=\"" << m_Re << "\">" << endl;
33375 ofl << m_Re << endl;
33376 ofl << "</DataArray>" << endl;
33377 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Pr\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33378 << m_Pr << "\" RangeMax=\"" << m_Pr << "\">" << endl;
33379 ofl << m_Pr << endl;
33380 ofl << "</DataArray>" << endl;
33381 ofl << "<DataArray type=\"" << dataType << "\" Name=\"gamma\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33382 << m_gamma << "\" RangeMax=\"" << m_gamma << "\">" << endl;
33383 ofl << m_gamma << endl;
33384 ofl << "</DataArray>" << endl;
33385 ofl << "<DataArray type=\"" << dataType << "\" Name=\"CFL\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33386 << m_cfl << "\" RangeMax=\"" << m_cfl << "\">" << endl;
33387 ofl << m_cfl << endl;
33388 ofl << "</DataArray>" << endl;
33389 ofl << "<DataArray type=\"" << dataType << "\" Name=\"uInf\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33390 << m_UInfinity << "\" RangeMax=\"" << m_UInfinity << "\">" << endl;
33391 ofl << m_UInfinity << endl;
33392 ofl << "</DataArray>" << endl;
33393 ofl << "<DataArray type=\"" << dataType << "\" Name=\"vInf\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33394 << m_VInfinity << "\" RangeMax=\"" << m_VInfinity << "\">" << endl;
33395 ofl << m_VInfinity << endl;
33396 ofl << "</DataArray>" << endl;
33397 ofl << "<DataArray type=\"" << dataType << "\" Name=\"pInf\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33398 << m_PInfinity << "\" RangeMax=\"" << m_PInfinity << "\">" << endl;
33399 ofl << m_PInfinity << endl;
33400 ofl << "</DataArray>" << endl;
33401 ofl << "<DataArray type=\"" << dataType << "\" Name=\"rhoInf\" format=\"ascii\" NumberOfTuples=\"1\" RangeMin=\""
33402 << m_rhoInfinity << "\" RangeMax=\"" << m_rhoInfinity << "\">" << endl;
33403 ofl << m_rhoInfinity << endl;
33404 ofl << "</DataArray>" << endl;
33405 ofl << "</FieldData>" << endl;
33406
33407 // Dimensions
33408 ofl << "<Piece NumberOfPoints=\"" << noPoints << "\" NumberOfCells=\"" << noCells << "\">" << endl;
33409
33410 // Points
33411 ofl << "<Points>" << endl;
33412 ofl << "<DataArray type=\"" << dataType << "\" NumberOfComponents=\"3\" format=\"appended\" offset=\"" << offset
33413 << "\"/>" << endl;
33414 offset += points.m_memsize + sizeof(MUint);
33415 ofl << "</Points>" << endl;
33416
33417 // Cells
33418 ofl << "<Cells>" << endl;
33419
33420 ofl << "<DataArray type=\"" << uIDataType << "\" Name=\"connectivity\" format=\"appended\" offset=\"" << offset
33421 << "\"/>" << endl;
33422 offset += connectivity.m_memsize + sizeof(MUint);
33423
33424 ofl << "<DataArray type=\"" << uIDataType << "\" Name=\"offsets\" format=\"appended\" offset=\"" << offset << "\"/>"
33425 << endl;
33426 offset += offsets.m_memsize + sizeof(MUint);
33427
33428 ofl << "<DataArray type=\"" << uI8DataType << "\" Name=\"types\" format=\"appended\" offset=\"" << offset << "\"/>"
33429 << endl;
33430 offset += types.m_memsize + sizeof(MUint);
33431
33432 ofl << "</Cells>" << endl;
33433
33434 // CellData/PointData
33435 ofl << "<CellData Scalars=\"scalars\">" << endl;
33436
33437 ofl << "<DataArray type=\"" << iDataType << "\" Name=\"cellIds\" format=\"appended\" offset=\"" << offset << "\"/>"
33438 << endl;
33439 offset += cellIds.m_memsize + sizeof(MUint);
33440
33441 if(m_haloCellOutput) {
33442 ofl << "<DataArray type=\"" << uI8DataType << "\" Name=\"vtkGhostLevels\" format=\"appended\" offset=\"" << offset
33443 << "\"/>" << endl;
33444 offset += vtkGhostLevels.m_memsize + sizeof(MUint);
33445 }
33446
33447#ifdef _MB_DEBUG_
33448 ofl << "<DataArray type=\"" << iDataType << "\" Name=\"bndryIds\" format=\"appended\" offset=\"" << offset << "\"/>"
33449 << endl;
33450 offset += bndryIds.m_memsize + sizeof(MUint);
33451
33452 ofl << "<DataArray type=\"" << dataType64 << "\" Name=\"drho_dt\" format=\"appended\" offset=\"" << offset << "\"/>"
33453 << endl;
33454 offset += drho_dt.m_memsize + sizeof(MUint);
33455
33456 ofl << "<DataArray type=\"" << dataType64 << "\" Name=\"drhou_dt\" format=\"appended\" offset=\"" << offset
33457 << "\"/>" << endl;
33458 offset += drhou_dt.m_memsize + sizeof(MUint);
33459
33460 ofl << "<DataArray type=\"" << dataType << "\" Name=\"levelSetFunction\" format=\"appended\" offset=\"" << offset
33461 << "\"/>" << endl;
33462 offset += levelSetFunction.m_memsize + sizeof(MUint);
33463
33464 ofl << "<DataArray type=\"" << dataType << "\" Name=\"volume\" format=\"appended\" offset=\"" << offset << "\"/>"
33465 << endl;
33466 offset += volume.m_memsize + sizeof(MUint);
33467
33468 ofl << "<DataArray type=\"" << dataType << "\" Name=\"spongeFactor\" format=\"appended\" offset=\"" << offset
33469 << "\"/>" << endl;
33470 offset += spongeFac.m_memsize + sizeof(MUint);
33471
33472 if(sensorOutput) {
33473 ofl << "<DataArray type=\"" << dataType << "\" Name=\"tauC\" format=\"appended\" offset=\"" << offset << "\"/>"
33474 << endl;
33475 offset += tauC.m_memsize + sizeof(MUint);
33476 ofl << "<DataArray type=\"" << dataType << "\" Name=\"tauE\" format=\"appended\" offset=\"" << offset << "\"/>"
33477 << endl;
33478 offset += tauE.m_memsize + sizeof(MUint);
33479 }
33480
33481#endif
33482
33483 if(writePointData) {
33484 ofl << "</CellData>" << endl;
33485 ofl << "<PointData Scalars=\"scalars\">" << endl;
33486 }
33487
33488 ofl << "<DataArray type=\"" << dataType << "\" Name=\"pressure\" format=\"appended\" offset=\"" << offset << "\"/>"
33489 << endl;
33490 offset += pressure.m_memsize + sizeof(MUint);
33491
33492 ofl << "<DataArray type=\"" << dataType
33493 << "\" Name=\"velocity\" NumberOfComponents=\"3\" format=\"appended\" offset=\"" << offset << "\"/>" << endl;
33494 offset += velocity.m_memsize + sizeof(MUint);
33495
33496 ofl << "<DataArray type=\"" << dataType << "\" Name=\"density\" format=\"appended\" offset=\"" << offset << "\"/>"
33497 << endl;
33498 offset += density.m_memsize + sizeof(MUint);
33499
33500 ofl << "<DataArray type=\"" << dataType << "\" Name=\"vorticity\" format=\"appended\" offset=\"" << offset << "\"/>"
33501 << endl;
33502 offset += vorticity.m_memsize + sizeof(MUint);
33503
33504 ofl << "<DataArray type=\"" << dataType << "\" Name=\"Qcriterion\" format=\"appended\" offset=\"" << offset
33505 << "\"/>" << endl;
33506 offset += Qcriterion.m_memsize + sizeof(MUint);
33507
33508 if(entropyChangeOutput) {
33509 ofl << "<DataArray type=\"" << dataType << "\" Name=\"dS\" format=\"appended\" offset=\"" << offset << "\"/>"
33510 << endl;
33511 offset += dS.m_memsize + sizeof(MUint);
33512 }
33513
33514#ifdef _MB_DEBUG_
33515 ofl << "<DataArray type=\"" << dataType << "\" Name=\"rhoE\" format=\"appended\" offset=\"" << offset << "\"/>"
33516 << endl;
33517 offset += rhoE.m_memsize + sizeof(MUint);
33518
33519 if(QThresholdOutput) {
33520 ofl << "<DataArray type=\"" << dataType << "\" Name=\"QThreshold\" format=\"appended\" offset=\"" << offset
33521 << "\"/>" << endl;
33522 offset += QThreshold.m_memsize + sizeof(MUint);
33523 }
33524
33525#endif
33526
33527 if(writePointData) {
33528 ofl << "</PointData>" << endl;
33529 } else {
33530 ofl << "</CellData>" << endl;
33531 }
33532
33533 ofl << "</Piece>" << endl;
33534 ofl << "</UnstructuredGrid>" << endl;
33535
33536 ofl << "<AppendedData encoding=\"raw\">" << endl;
33537 ofl << "_";
33538 ofl.close();
33539 ofl.clear();
33540 } else {
33541 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing! (1)" << endl;
33542 }
33543 ofl.open(fileName.c_str(), ios_base::out | ios_base::app | ios_base::binary);
33544
33545 if(ofl.is_open() && ofl.good()) {
33546 // point coordinates
33547 uinumber = (MUint)points.m_memsize;
33548 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(MUint));
33549 ofl.write(reinterpret_cast<const char*>(points.getPointer()), uinumber);
33550
33551 // connectivity
33552 uinumber = (MUint)connectivity.m_memsize;
33553 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(MUint));
33554 ofl.write(reinterpret_cast<const char*>(connectivity.getPointer()), uinumber);
33555
33556 // offsets
33557 uinumber = (MUint)offsets.m_memsize;
33558 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33559 ofl.write(reinterpret_cast<const char*>(offsets.getPointer()), uinumber);
33560
33561 // cell types
33562 uinumber = (MUint)types.m_memsize;
33563 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33564 ofl.write(reinterpret_cast<const char*>(types.getPointer()), uinumber);
33565
33566 // cellIds
33567 uinumber = (MUint)cellIds.m_memsize;
33568 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33569 ofl.write(reinterpret_cast<const char*>(cellIds.getPointer()), uinumber);
33570
33571 // vtkGhostLevels
33572 if(m_haloCellOutput) {
33573 uinumber = (MUint)vtkGhostLevels.m_memsize;
33574 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33575 ofl.write(reinterpret_cast<const char*>(vtkGhostLevels.getPointer()), uinumber);
33576 }
33577
33578#ifdef _MB_DEBUG_
33579 // bndryIds
33580 uinumber = (MUint)bndryIds.m_memsize;
33581 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33582 ofl.write(reinterpret_cast<const char*>(bndryIds.getPointer()), uinumber);
33583
33584 // drho_dt
33585 uinumber = (MUint)drho_dt.m_memsize;
33586 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33587 ofl.write(reinterpret_cast<const char*>(drho_dt.getPointer()), uinumber);
33588
33589 // drhou_dt
33590 uinumber = (MUint)drhou_dt.m_memsize;
33591 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33592 ofl.write(reinterpret_cast<const char*>(drhou_dt.getPointer()), uinumber);
33593
33594 // levelSetFunction
33595 uinumber = (MUint)levelSetFunction.m_memsize;
33596 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33597 ofl.write(reinterpret_cast<const char*>(levelSetFunction.getPointer()), uinumber);
33598
33599 // volume
33600 uinumber = (MUint)volume.m_memsize;
33601 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33602 ofl.write(reinterpret_cast<const char*>(volume.getPointer()), uinumber);
33603
33604 // spongeFac
33605 uinumber = (MUint)spongeFac.m_memsize;
33606 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33607 ofl.write(reinterpret_cast<const char*>(spongeFac.getPointer()), uinumber);
33608
33609 // tauC / tauE
33610 if(sensorOutput) {
33611 uinumber = (MUint)tauC.m_memsize;
33612 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33613 ofl.write(reinterpret_cast<const char*>(tauC.getPointer()), uinumber);
33614 uinumber = (MUint)tauE.m_memsize;
33615 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33616 ofl.write(reinterpret_cast<const char*>(tauE.getPointer()), uinumber);
33617 }
33618
33619#endif
33620
33621 // pressure
33622 uinumber = (MUint)pressure.m_memsize;
33623 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33624 ofl.write(reinterpret_cast<const char*>(pressure.getPointer()), uinumber);
33625
33626 // velocity
33627 uinumber = (MUint)velocity.m_memsize;
33628 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33629 ofl.write(reinterpret_cast<const char*>(velocity.getPointer()), uinumber);
33630
33631 // density
33632 uinumber = (MUint)density.m_memsize;
33633 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33634 ofl.write(reinterpret_cast<const char*>(density.getPointer()), uinumber);
33635
33636 // vorticity
33637 uinumber = (MUint)vorticity.m_memsize;
33638 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33639 ofl.write(reinterpret_cast<const char*>(vorticity.getPointer()), uinumber);
33640
33641 // Qcriterion
33642 uinumber = (MUint)Qcriterion.m_memsize;
33643 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33644 ofl.write(reinterpret_cast<const char*>(Qcriterion.getPointer()), uinumber);
33645
33646 // dS
33647 if(entropyChangeOutput) {
33648 uinumber = (MUint)dS.m_memsize;
33649 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33650 ofl.write(reinterpret_cast<const char*>(dS.getPointer()), uinumber);
33651 }
33652
33653#ifdef _MB_DEBUG_
33654
33655 // rhoE
33656 uinumber = (MUint)rhoE.m_memsize;
33657 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33658 ofl.write(reinterpret_cast<const char*>(rhoE.getPointer()), uinumber);
33659
33660 if(QThresholdOutput) {
33661 uinumber = (MUint)QThreshold.m_memsize;
33662 ofl.write(reinterpret_cast<const char*>(&uinumber), sizeof(uinumber));
33663 ofl.write(reinterpret_cast<const char*>(QThreshold.getPointer()), uinumber);
33664 }
33665
33666#endif
33667
33668 ofl.close();
33669 ofl.clear();
33670 } else {
33671 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing! (2)" << endl;
33672 }
33673
33674 ofl.open(fileName.c_str(), ios_base::out | ios_base::app);
33675 if(ofl.is_open() && ofl.good()) {
33676 ofl << endl;
33677 ofl << "</AppendedData>" << endl;
33678
33679 ofl << "</VTKFile>" << endl;
33680 ofl.close();
33681 ofl.clear();
33682 } else {
33683 cerr << "ERROR! COULD NOT OPEN FILE " << fileName << " for writing! (3)" << endl;
33684 }
33685}
33686
33687
33692template <MInt nDim, class SysEqn>
33693template <class _, std::enable_if_t<nDim == 2, _*>>
33695 TRACE();
33696
33697 ofstream ofl;
33698 ofl.open(fileName.c_str());
33699
33700 if(ofl.is_open() && ofl.good()) {
33701 ofl << "<?xml version=\"1.0\"?>" << endl;
33702 ofl << R"(<VTKFile type="PolyData" version="0.1")" << endl;
33703 ofl << "<PolyData>" << endl;
33704 ofl << "<Piece NumberOfPoints=\"" << 0 << "\" NumberOfCells=\"" << 0 << "\">" << endl;
33705 ofl << "</Piece>" << endl;
33706 ofl << "</PolyData>" << endl;
33707 ofl << "</VTKFile>" << endl;
33708 ofl.close();
33709 ofl.clear();
33710 return 0;
33711 }
33712 return 0;
33713}
33714
33715
33720template <MInt nDim, class SysEqn>
33721template <class _, std::enable_if_t<nDim == 3, _*>>
33723 return -1;
33724}
33725
33726
33731template <MInt nDim, class SysEqn>
33732template <class _, std::enable_if_t<nDim == 2, _*>>
33733void FvMbCartesianSolverXD<nDim, SysEqn>::writeVTKFileOfCell(MInt cellId, const std::vector<polyEdge2D>* edges,
33734 const std::vector<polyVertex>* vertices, MInt set) {
33735 const MChar* fileName = "cell_";
33736 stringstream fileName2;
33737 fileName2 << fileName << cellId << "_s" << set << "_D" << domainId() << ".vtk";
33738 ofstream ofl;
33739 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
33740
33741 if(ofl) {
33742 // set fixed floating point output
33743 ofl.setf(ios::fixed);
33744 ofl.precision(7);
33745
33746 ofl << "# vtk DataFile Version 3.0" << endl
33747 << "MAIAD cutsurface file" << endl
33748 << "ASCII" << endl
33749 << endl
33750 << "DATASET UNSTRUCTURED_GRID" << endl
33751 << endl;
33752
33753 ofl << "POINTS " << (*vertices).size() << " float" << endl;
33754
33755 for(MInt v = 0; (unsigned)v < (*vertices).size(); v++) {
33756 for(MInt i = 0; i < nDim; i++)
33757 ofl << (*vertices)[v].coordinates[i] << " ";
33758 ofl << F0 << " ";
33759 ofl << endl;
33760 }
33761
33762 ofl << endl;
33763 MInt numPoints = 0;
33764 MInt noEdges = (*edges).size();
33765 numPoints += noEdges * 2;
33766 ofl << "CELLS " << noEdges << " " << noEdges + numPoints << endl;
33767
33768
33769 for(MInt i = 0; i < noEdges; i++) {
33770 unsigned noVerts = 2;
33771 ofl << noVerts << " ";
33772 ofl << (*edges)[i].vertices[0] << " ";
33773 ofl << (*edges)[i].vertices[1] << " ";
33774 ofl << endl;
33775 }
33776 ofl << endl;
33777
33778 ofl << "CELL_TYPES " << noEdges << endl;
33779 for(MInt i = 0; i < noEdges; i++) {
33780 ofl << 3 << endl;
33781 }
33782
33783 ofl.close();
33784 }
33785}
33786
33787
33792template <MInt nDim, class SysEqn>
33793template <class _, std::enable_if_t<nDim == 2, _*>>
33794void FvMbCartesianSolverXD<nDim, SysEqn>::writeVTKFileOfCutCell(MInt cellId, std::vector<polyCutCell>* cutCells,
33795 const std::vector<polyEdge2D>* edges,
33796 const std::vector<polyVertex>* vertices, MInt set) {
33797 const MChar* fileName = "cutCell_";
33798 stringstream fileName2;
33799 fileName2 << fileName << cellId << "_s" << set << "_D" << domainId() << ".vtk";
33800 ofstream ofl;
33801 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
33802
33803 if(ofl) {
33804 // set fixed floating point output
33805 ofl.setf(ios::fixed);
33806 ofl.precision(7);
33807
33808 ofl << "# vtk DataFile Version 3.0" << endl
33809 << "MAIAD cutsurface file" << endl
33810 << "ASCII" << endl
33811 << endl
33812 << "DATASET UNSTRUCTURED_GRID" << endl
33813 << endl;
33814
33815 ofl << "POINTS " << (*vertices).size() << " float" << endl;
33816
33817 for(MInt v = 0; (unsigned)v < (*vertices).size(); v++) {
33818 for(MInt i = 0; i < nDim; i++)
33819 ofl << (*vertices)[v].coordinates[i] << " ";
33820 ofl << F0 << " ";
33821 ofl << endl;
33822 }
33823
33824 ofl << endl;
33825 MInt numPoints = 0;
33826 MInt noEdges = 0;
33827 for(MInt c = 0; (unsigned)c < (*cutCells).size(); c++) {
33828 MInt noEdgesCC = (*cutCells)[c].faces_edges.size();
33829 numPoints += noEdgesCC * 2;
33830 noEdges += noEdgesCC;
33831 }
33832 ofl << "CELLS " << noEdges << " " << noEdges + numPoints << endl;
33833
33834
33835 for(MInt c = 0; (unsigned)c < (*cutCells).size(); c++) {
33836 for(MInt i = 0; (unsigned)i < (*cutCells)[c].faces_edges.size(); i++) {
33837 MInt edge = (*cutCells)[c].faces_edges[i];
33838 unsigned noVerts = 2;
33839 ofl << noVerts << " ";
33840 ofl << (*edges)[edge].vertices[0] << " ";
33841 ofl << (*edges)[edge].vertices[1] << " ";
33842 ofl << endl;
33843 }
33844 ofl << endl;
33845 }
33846 ofl << endl;
33847
33848 ofl << "CELL_TYPES " << noEdges << endl;
33849 for(MInt i = 0; i < noEdges; i++) {
33850 ofl << 3 << endl;
33851 }
33852
33853 ofl << endl;
33854 ofl << "CELL_DATA " << noEdges << endl;
33855 ofl << "FIELD FieldData " << 2 << endl;
33856 ofl << "cutCell"
33857 << " " << 1 << " " << noEdges << " "
33858 << "int" << endl;
33859 for(MInt c = 0; (unsigned)c < (*cutCells).size(); c++) {
33860 for(MInt f = 0; (unsigned)f < (*cutCells)[c].faces_edges.size(); f++) {
33861 MInt edge = (*cutCells)[c].faces_edges[f];
33862 ofl << (*edges)[edge].cutCell << " ";
33863 }
33864 }
33865 ofl << endl;
33866 ofl << "bodyId"
33867 << " " << 1 << " " << noEdges << " "
33868 << "int" << endl;
33869 for(MInt c = 0; (unsigned)c < (*cutCells).size(); c++) {
33870 for(MInt f = 0; (unsigned)f < (*cutCells)[c].faces_edges.size(); f++) {
33871 MInt edge = (*cutCells)[c].faces_edges[f];
33872 ofl << (*edges)[edge].bodyId << " ";
33873 }
33874 }
33875 ofl << endl;
33876
33877 ofl.close();
33878 }
33879}
33880
33881
33886template <MInt nDim, class SysEqn>
33887template <class _, std::enable_if_t<nDim == 2, _*>>
33888void FvMbCartesianSolverXD<nDim, SysEqn>::outputPolyData(const MInt cellId, const std::vector<polyCutCell>* cutCells,
33889 const std::vector<polyEdge2D>* edges,
33890 const std::vector<polyVertex>* vertices, MInt set) {
33891 const MChar* fileName = "polyData_";
33892 stringstream fileName2;
33893 fileName2 << fileName << cellId << "_s" << set << "_D" << domainId();
33894 ofstream ofl;
33895 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
33896
33897 if(ofl) {
33898 // set fixed floating point output
33899 ofl.setf(ios::fixed);
33900 ofl.precision(7);
33901
33902 ofl << "VERTICES:" << endl;
33903 for(MInt v = 0; (unsigned)v < (*vertices).size(); v++) {
33904 ofl << v << ": " << endl;
33905 ofl << "coordinates: " << (*vertices)[v].coordinates[0] << " " << (*vertices)[v].coordinates[1] << endl;
33906 ofl << "pointId: " << (*vertices)[v].pointId;
33907 ofl << ", pointType: " << (*vertices)[v].pointType << endl;
33908 ofl << "edges: ";
33909 for(MInt e = 0; (unsigned)e < (*vertices)[v].edges.size(); e++)
33910 ofl << (*vertices)[v].edges[e] << " ";
33911 ofl << endl << endl;
33912 }
33913
33914 ofl << endl << "EDGES:" << endl;
33915 for(MInt e = 0; (unsigned)e < (*edges).size(); e++) {
33916 ofl << e << ": " << endl;
33917 ofl << "vertices: " << (*edges)[e].vertices[0] << " " << (*edges)[e].vertices[1] << endl;
33918 ofl << "edgeId: " << (*edges)[e].edgeId;
33919 ofl << ", edgeType: " << (*edges)[e].edgeType;
33920 ofl << ", bodyId: " << (*edges)[e].bodyId;
33921 ofl << ", cutCell: " << (*edges)[e].cutCell << endl;
33922 ofl << "area: " << (*edges)[e].area << endl;
33923 ofl << "center: " << (*edges)[e].center[0] << " " << (*edges)[e].center[1] << endl;
33924 ofl << "normal: " << (*edges)[e].normal[0] << " " << (*edges)[e].normal[1] << endl;
33925 ofl << "w: " << (*edges)[e].w << endl;
33926 ofl << endl << endl;
33927 }
33928
33929 ofl << endl << "CUT CELLS:" << endl;
33930 for(MInt c = 0; (unsigned)c < (*cutCells).size(); c++) {
33931 ofl << c << ": " << endl;
33932 ofl << "volume: " << (*cutCells)[c].volume << endl;
33933 ofl << "center: " << (*cutCells)[c].center[0] << " " << (*cutCells)[c].center[1] << endl;
33934 ofl << "cartesianCell: " << (*cutCells)[c].cartesianCell << endl;
33935 ofl << "edges: ";
33936 for(MInt f = 0; (unsigned)f < (*cutCells)[c].faces_edges.size(); f++)
33937 ofl << (*cutCells)[c].faces_edges[f] << " ";
33938 ofl << endl << endl;
33939 }
33940
33941 ofl.close();
33942 }
33943}
33944
33945
33950template <MInt nDim, class SysEqn>
33951template <class _, std::enable_if_t<nDim == 3, _*>>
33952void FvMbCartesianSolverXD<nDim, SysEqn>::outputPolyData(const MInt cellId, const std::vector<polyCutCell>* cutCells,
33953 const std::vector<polyFace>* faces,
33954 const std::vector<polyEdge3D>* edges,
33955 const std::vector<polyVertex>* vertices, MInt set) {
33956 const MChar* fileName = "polyData_";
33957 stringstream fileName2;
33958 fileName2 << fileName << cellId << "_s" << set << "_D" << domainId();
33959 ofstream ofl;
33960 ofl.open((fileName2.str()).c_str(), ofstream::trunc);
33961
33962 if(ofl) {
33963 // set fixed floating point output
33964 ofl.setf(ios::fixed);
33965 ofl.precision(20);
33966
33967 ofl << "VERTICES:" << endl;
33968 for(MInt v = 0; (unsigned)v < (*vertices).size(); v++) {
33969 ofl << v << ": " << endl;
33970 ofl << "coordinates: " << (*vertices)[v].coordinates[0] << " " << (*vertices)[v].coordinates[1] << " "
33971 << (*vertices)[v].coordinates[2] << endl;
33972 ofl << "pointId: " << (*vertices)[v].pointId;
33973 ofl << ", pointType: " << (*vertices)[v].pointType << endl;
33974 ofl << "surfaceIdentificators: ";
33975 for(std::set<MInt>::iterator it = (*vertices)[v].surfaceIdentificators.begin();
33976 it != (*vertices)[v].surfaceIdentificators.end();
33977 it++)
33978 ofl << *it << " ";
33979 ofl << endl;
33980 ofl << "edges: ";
33981 for(MInt e = 0; (unsigned)e < (*vertices)[v].edges.size(); e++)
33982 ofl << (*vertices)[v].edges[e] << " ";
33983 ofl << endl << endl;
33984 }
33985
33986 ofl << endl << "EDGES:" << endl;
33987 for(MInt e = 0; (unsigned)e < (*edges).size(); e++) {
33988 ofl << e << ": " << endl;
33989 ofl << "vertices: " << (*edges)[e].vertices[0] << " " << (*edges)[e].vertices[1] << endl;
33990 ofl << "faces: " << (*edges)[e].face[0] << " " << (*edges)[e].face[1] << endl;
33991 ofl << "edgeId: " << (*edges)[e].edgeId;
33992 ofl << ", edgeType: " << (*edges)[e].edgeType << endl;
33993 ofl << endl << endl;
33994 }
33995
33996 ofl << endl << "FACES:" << endl;
33997 for(MInt f = 0; (unsigned)f < (*faces).size(); f++) {
33998 ofl << f << ": " << endl;
33999 ofl << "area: " << (*faces)[f].area << endl;
34000 ofl << "center: " << (*faces)[f].center[0] << " " << (*faces)[f].center[1] << " " << (*faces)[f].center[2]
34001 << endl;
34002 ofl << "normal: " << (*faces)[f].normal[0] << " " << (*faces)[f].normal[1] << " " << (*faces)[f].normal[2]
34003 << endl;
34004 ofl << "w: " << (*faces)[f].w << endl;
34005 ofl << "faceId: " << (*faces)[f].faceId;
34006 ofl << ", faceType: " << (*faces)[f].faceType << endl;
34007 ofl << "bodyId: " << (*faces)[f].bodyId << endl;
34008 ofl << "setIndex: " << (*faces)[f].tmpSetIndex << endl;
34009 ofl << "cutCell: " << (*faces)[f].cutCell << endl;
34010 ofl << "edges: ";
34011 for(MInt e = 0; (unsigned)e < (*faces)[f].edges.size(); e++)
34012 ofl << (*faces)[f].edges[e].first << ", dir " << (*faces)[f].edges[e].second << " ";
34013 ofl << endl << endl;
34014 }
34015
34016 ofl << endl << "CUT CELLS:" << endl;
34017 for(MInt c = 0; (unsigned)c < (*cutCells).size(); c++) {
34018 ofl << c << ": " << endl;
34019 ofl << "volume: " << (*cutCells)[c].volume << endl;
34020 ofl << "center: " << (*cutCells)[c].center[0] << " " << (*cutCells)[c].center[1] << " "
34021 << (*cutCells)[c].center[2] << endl;
34022 ofl << "cartesianCell: " << (*cutCells)[c].cartesianCell << endl;
34023 ofl << "faces: ";
34024 for(MInt f = 0; (unsigned)f < (*cutCells)[c].faces_edges.size(); f++)
34025 ofl << (*cutCells)[c].faces_edges[f] << " ";
34026 ofl << endl << endl;
34027 }
34028
34029 ofl.close();
34030 }
34031}
34032
34033
34046template <MInt nDim, class SysEqn>
34047template <class _, std::enable_if_t<nDim == 2, _*>>
34049 TRACE();
34050
34054 if(first) {
34055 bodyFaceJoinMode = Context::getSolverProperty<MInt>("bodyFaceJoinMode", solverId(), AT_, &bodyFaceJoinMode);
34056 maxA = Context::getSolverProperty<MFloat>("bodyFaceJoinCriterion", solverId(), AT_, &maxA);
34057 first = false;
34058 }
34059
34060 const MInt faceOrder[4] = {2, 1, 3, 0};
34061 const MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
34062 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
34063 const MInt edgeCornerCode[4][2] = {{2, 0}, {1, 3}, {0, 1}, {3, 2}};
34064
34065 const MInt maxNoSets = 6;
34066 ASSERT2(m_noLevelSetsUsedForMb < maxNoSets, "");
34067 MIntScratchSpace outcode_set(m_noLevelSetsUsedForMb, AT_, "outcode_set");
34068 MIntScratchSpace noCutPointsFromSet(m_noLevelSetsUsedForMb, AT_, "noCutPointsFromSet");
34069 MIntScratchSpace cutSetPointers(m_noLevelSetsUsedForMb, AT_, "cutSetPointers");
34070
34071 const MInt maxNoVertices = 25;
34072 const MInt maxNoEdges = 25;
34073
34074 stack<MInt> multiEdgeStack;
34075 std::vector<polyVertex> vertices[maxNoSets];
34076 std::vector<polyEdge2D> edges[maxNoSets];
34077 std::vector<polyCutCell> cutCells;
34078
34079 std::vector<CsgPolygon> csg_polygons;
34080 std::vector<CsgVertex> csg_vertices;
34081 std::vector<Csg> csg;
34082 std::vector<CsgPolygon> result;
34083 std::vector<polyVertex> vertices_result;
34084 stack<MInt> edgeStack;
34085 std::vector<MInt> faceVertices;
34086
34087 MIntScratchSpace multiEdgeConnection(maxNoEdges, AT_, "multiEdgeConnection");
34088 MIntScratchSpace vertices_renamed(2, maxNoVertices, AT_, "vertices_renamed");
34089 MIntScratchSpace bodyFaces(maxNoEdges, AT_, "bodyFaces");
34090 MFloatScratchSpace normalDotProduct(maxNoEdges, maxNoEdges, AT_, "normalDotProduct"); // stores 1 - n1*n2 -> in [0;2]
34091 MIntScratchSpace pointEdgeId(2 * m_noEdges, AT_, "pointEdgeId");
34092 MIntScratchSpace newCutPointId(maxNoVertices, AT_, "newCutPointId");
34093 MBoolScratchSpace isPartOfBodySurface(maxNoVertices, AT_, "isPartOfBodySurface");
34094 MIntScratchSpace tmp_Edges(maxNoEdges, AT_, "tmp_Edges");
34095 MIntScratchSpace vertexCutCellPointer(maxNoEdges, AT_, "vertexCutCellPointer");
34096
34097 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
34098 FvBndryCell<2, SysEqn>* bndryCell = &m_fvBndryCnd->m_bndryCells->a[bndryId];
34099 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
34100 const MInt cndId = m_bndryCandidateIds[cellId];
34101 ASSERT(cndId > -1, "");
34102
34103 for(MInt f = 0; f < m_noDirs; f++) {
34104 bndryCell->m_externalFaces[f] = false;
34105 }
34106
34107 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints == 0) {
34108 cerr << "** fvmbsolver2d ERROR" << endl;
34109 cerr << "boundary cell " << bndryId << endl;
34110 cerr << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << endl;
34111 cerr << " -> number of cut points is zero" << endl;
34112 continue;
34113 }
34114
34115 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints % 2 != 0) {
34116 cerr << "** fvmbsolver2d ERROR" << endl;
34117 cerr << "boundary cell " << bndryId << endl;
34118 cerr << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << endl;
34119 cerr << " -> number of cut points uneven" << endl;
34120 continue;
34121 }
34122
34123 const MFloat cellLength0 = c_cellLengthAtLevel(a_level(cellId));
34124 const MFloat cellHalfLength = F1B2 * cellLength0;
34125
34126 // reset some variables
34127 for(MInt s = 0; s < m_noLevelSetsUsedForMb; s++) {
34128 vertices[s].clear();
34129 edges[s].clear();
34130 cutSetPointers[s] = -1;
34131 noCutPointsFromSet[s] = 0;
34132 }
34133 cutCells.clear();
34134
34135 MBool isGapCell = false;
34136 if(m_levelSet && m_closeGaps) {
34137 isGapCell = (a_hasProperty(cellId, SolverCell::IsGapCell));
34138 }
34139 MInt startSet = 0;
34140 MInt endSet = 1;
34141 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell)) {
34142 startSet = 1;
34143 endSet = m_noLevelSetsUsedForMb;
34144 } else if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (isGapCell)) {
34145 startSet = 0;
34146 endSet = 1;
34147 }
34148
34149 // preprocess cut points - find out which level set functions contain relevant cut points
34150 // if no relevant cut points are present -> don't cut the cell with the set
34151 MInt noCutSets = 0;
34152 MBool isCompletelyOutside = false;
34153 for(MInt s = startSet; s < endSet; s++) {
34154 // 1.1. get In/Outcode of the corners of the voxel
34155 // 0 -> Corner is outside Fluid Domain
34156 // 1 -> Corner is inside Fluid Domain or on Boundary
34157 unsigned char outcode = 0;
34158 for(MInt c = 0; c < m_noCorners; c++) {
34159 MBool currentOutcode = (!m_pointIsInside[bndryId][IDX_LSSETMB(c, s)]);
34160 if(currentOutcode) outcode = outcode | (1 << c);
34161 }
34162 outcode_set[s] = outcode;
34163 if(outcode == 0) isCompletelyOutside = true;
34164 }
34165 for(MInt cutPoint = 0; cutPoint < bndryCell->m_srfcs[0]->m_noCutPoints; cutPoint++) {
34166 ASSERT(bndryCell->m_srfcs[0]->m_bodyId[cutPoint] > -1
34167 && bndryCell->m_srfcs[0]->m_bodyId[cutPoint] < m_noEmbeddedBodies,
34168 "bodyId out of bounds " + to_string(cellId) + " " + to_string(cutPoint) + " "
34169 + to_string(bndryCell->m_srfcs[0]->m_bodyId[cutPoint]));
34170 MInt set = 0;
34171 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell))
34172 set = m_bodyToSetTable[bndryCell->m_srfcs[0]->m_bodyId[cutPoint]];
34173 ASSERT(set > -1 && set < m_noLevelSetsUsedForMb, "set out of bounds " + to_string(cellId) + " "
34174 + to_string(cutPoint) + " " + to_string(set) + " "
34175 + to_string(bndryCell->m_srfcs[0]->m_bodyId[cutPoint]));
34176 noCutPointsFromSet[set]++;
34177 }
34178 for(MInt set = startSet; set < endSet; set++) {
34179 if(noCutPointsFromSet[set] && !isCompletelyOutside) {
34180 cutSetPointers[set] = noCutSets++;
34181 }
34182 }
34183
34184 // computation of cuts with individual sets
34185 for(MInt set = startSet; set < endSet; set++) {
34186 MInt setIndex = cutSetPointers[set];
34187 if(setIndex < 0) continue;
34188 MInt bodyId = a_associatedBodyIds(cellId, set);
34189 if(bodyId < 0) continue;
34190
34191 // store all cut points in a separate array
34192 // and prepare all vertices for polyeder/polygon datastructure
34193 // vertices = cut points and fluid corners of the cell
34194 MInt cutPoints[4] = {-1, -1, -1, -1};
34195 MInt cutPointToVertexMap[4] = {-1, -1, -1, -1};
34196 MInt noCutPoints = 0;
34197 for(MInt cutPoint = 0; cutPoint < bndryCell->m_srfcs[0]->m_noCutPoints; cutPoint++) {
34198 if(m_complexBoundary && m_noLevelSetsUsedForMb > 1 && (!isGapCell))
34199 if(m_bodyToSetTable[bndryCell->m_srfcs[0]->m_bodyId[cutPoint]] != set) continue;
34200 noCutPoints++;
34201 cutPoints[bndryCell->m_srfcs[0]->m_cutEdge[cutPoint]] = cutPoint;
34202 vertices[setIndex].push_back(polyVertex(bndryCell->m_srfcs[0]->m_cutCoordinates[cutPoint], cutPoint, 1));
34203 cutPointToVertexMap[cutPoint] = vertices[setIndex].size() - 1;
34204 }
34205 MInt cornerToVertexMap[4] = {-1, -1, -1, -1};
34206 for(MInt c = 0; c < m_noCorners; c++) {
34207 if(!m_pointIsInside[bndryId][IDX_LSSETMB(c, set)]) {
34208 MFloat tmp_coords[2];
34209 for(MInt i = 0; i < nDim; i++)
34210 tmp_coords[i] = a_coordinate(cellId, i) + signStencil[c][i] * cellHalfLength;
34211 vertices[setIndex].push_back(polyVertex(tmp_coords, c, 0));
34212 cornerToVertexMap[c] = vertices[setIndex].size() - 1;
34213 }
34214 }
34215
34216 // 1. find correct marching cubes state and substate -> including disambiguation
34217
34218 // 1.1. get In/Outcode of the corners of the voxel
34219 // 0 -> Corner is outside Fluid Domain
34220 // 1 -> Corner is inside Fluid Domain or on Boundary
34221 MInt outcode = outcode_set[set];
34222
34223 // 1.2. determine Case and check if case is implemented
34224 MInt currentCase = (MInt)cases2D[outcode][0];
34225 MInt currentSubCase = (MInt)cases2D[outcode][1];
34226 MInt subConfig = 0;
34227 // 1.2 determine ambiguous cells
34228 if(!caseStates2D[currentCase]) { // ambiguous case -> disambiguate
34229 MBool centerIsFluid = test_face(cndId, 4, set);
34230 if((centerIsFluid && currentSubCase == 1) || (!centerIsFluid && currentCase == 0)) subConfig = 1;
34231 }
34232 // 1.3. decide which tiling should be used, how many triangles are to be created for the cut face(s), etc.
34233 MInt noLines = 0;
34234 const MInt* tilingPointer = nullptr;
34235 noLines = noEdges2D[currentCase];
34236 switch(currentCase) {
34237 case 0:
34238 break;
34239
34240 case 1:
34241 tilingPointer = tiling1_2D[currentSubCase];
34242 break;
34243 case 2:
34244 tilingPointer = tiling2_2D[currentSubCase];
34245 break;
34246 case 3: {
34247 if(subConfig == 0)
34248 tilingPointer = tiling3_A_2D[currentSubCase];
34249 else
34250 tilingPointer = tiling3_B_2D[currentSubCase];
34251 break;
34252 }
34253 default:
34254 mTerm(1, AT_, "invalid MC case, how could this happen? exiting...");
34255 break;
34256 }
34257
34258 // 2. build edges for body surfaces -> MC
34259 for(MInt t = 0; t < noLines; t++) {
34260 // create a new edge
34261 MInt p[2];
34262 MInt cutEdge0 = tilingPointer[t * 2 + 0];
34263 MInt cutEdge1 = tilingPointer[t * 2 + 1];
34264 MInt p0 = cutPoints[cutEdge0];
34265 MInt p1 = cutPoints[cutEdge1];
34266 p[0] = cutPointToVertexMap[p0];
34267 p[1] = cutPointToVertexMap[p1];
34268 MInt newEdge = edges[setIndex].size();
34269 MInt edgeType = 2;
34270 MInt edgeId = -1;
34271 edges[setIndex].push_back(polyEdge2D(p[0], p[1], edgeId, edgeType, bodyId));
34272 vertices[setIndex][p[0]].edges.push_back(newEdge);
34273 vertices[setIndex][p[1]].edges.push_back(newEdge);
34274
34275 // compute normal of edge:
34276 computeNormal(vertices[setIndex][p[0]].coordinates, vertices[setIndex][p[1]].coordinates,
34277 edges[setIndex][newEdge].normal, edges[setIndex][newEdge].w);
34278 }
34279
34280 // 3. prepare basic edges -> between two inside corner vertices or between a corner vertex and a cut point
34281 for(MInt e = 0; e < m_noEdges; e++) {
34282 MInt edge = faceOrder[e];
34283 MBool p0Fluid = !m_pointIsInside[bndryId][IDX_LSSETMB(edgeCornerCode[edge][0], set)];
34284 MBool p1Fluid = !m_pointIsInside[bndryId][IDX_LSSETMB(edgeCornerCode[edge][1], set)];
34285 if(p0Fluid && p1Fluid) { // created a full Cartesian edge
34286 MInt v0 = cornerToVertexMap[edgeCornerCode[edge][0]];
34287 MInt v1 = cornerToVertexMap[edgeCornerCode[edge][1]];
34288 edges[setIndex].push_back(polyEdge2D(v0, v1, edge, 0, -1));
34289 vertices[setIndex][v0].edges.push_back(edges[setIndex].size() - 1);
34290 vertices[setIndex][v1].edges.push_back(edges[setIndex].size() - 1);
34291 computeNormal(vertices[setIndex][v0].coordinates, vertices[setIndex][v1].coordinates,
34292 edges[setIndex][edges[setIndex].size() - 1].normal,
34293 edges[setIndex][edges[setIndex].size() - 1].w);
34294 } else if(p0Fluid) { // create a cut edge from p0 to cut point
34295 MInt v0 = cornerToVertexMap[edgeCornerCode[edge][0]];
34296 MInt v1 = cutPointToVertexMap[cutPoints[edge]];
34297 edges[setIndex].push_back(polyEdge2D(v0, v1, edge, 1, -1));
34298 vertices[setIndex][v0].edges.push_back(edges[setIndex].size() - 1);
34299 vertices[setIndex][v1].edges.push_back(edges[setIndex].size() - 1);
34300 computeNormal(vertices[setIndex][v0].coordinates, vertices[setIndex][v1].coordinates,
34301 edges[setIndex][edges[setIndex].size() - 1].normal,
34302 edges[setIndex][edges[setIndex].size() - 1].w);
34303 } else if(p1Fluid) { // create a cut edge from cut point to p1
34304 MInt v0 = cutPointToVertexMap[cutPoints[edge]];
34305 MInt v1 = cornerToVertexMap[edgeCornerCode[edge][1]];
34306 edges[setIndex].push_back(polyEdge2D(v0, v1, edge, 1, -1));
34307 vertices[setIndex][v0].edges.push_back(edges[setIndex].size() - 1);
34308 vertices[setIndex][v1].edges.push_back(edges[setIndex].size() - 1);
34309 computeNormal(vertices[setIndex][v0].coordinates, vertices[setIndex][v1].coordinates,
34310 edges[setIndex][edges[setIndex].size() - 1].normal,
34311 edges[setIndex][edges[setIndex].size() - 1].w);
34312 } // else create no edge since edge is fully located outside
34313 }
34314 }
34315
34316 // 4.a combine polygons that are computed with different sets to one polygon
34317 // set up the CSG datastructure for each polygon
34318 // MBool error = false;
34319 const MInt startSetIndex = 0;
34320 MInt referenceSet = startSet;
34321 for(MInt set = startSet; set < endSet; set++) {
34322 if(cutSetPointers[set] > -1) {
34323 referenceSet = set;
34324 break;
34325 }
34326 }
34327 for(MInt set = referenceSet + 1; set < endSet; set++) {
34328 MInt setIndex = cutSetPointers[set];
34329 if(setIndex < 0) continue;
34330 csg.clear();
34331 csg_polygons.clear();
34332
34333 for(MInt e = 0; (unsigned)e < edges[startSetIndex].size(); e++) {
34334 csg_vertices.clear();
34335 MInt vertex0 = edges[startSetIndex][e].vertices[0];
34336 MInt vertex1 = edges[startSetIndex][e].vertices[1];
34337 csg_vertices.push_back(
34338 CsgVertex(CsgVector(vertices[startSetIndex][vertex0].coordinates), vertex0, startSetIndex));
34339 csg_vertices.push_back(
34340 CsgVertex(CsgVector(vertices[startSetIndex][vertex1].coordinates), vertex1, startSetIndex));
34341 csg_polygons.push_back(CsgPolygon(csg_vertices, startSetIndex, edges[startSetIndex][e].edgeId,
34342 edges[startSetIndex][e].edgeType, edges[startSetIndex][e].bodyId));
34343 }
34344 csg.push_back(Csg(csg_polygons));
34345
34346 csg_polygons.clear();
34347 for(MInt e = 0; (unsigned)e < edges[setIndex].size(); e++) {
34348 csg_vertices.clear();
34349 MInt vertex0 = edges[setIndex][e].vertices[0];
34350 MInt vertex1 = edges[setIndex][e].vertices[1];
34351 csg_vertices.push_back(CsgVertex(CsgVector(vertices[setIndex][vertex0].coordinates), vertex0, setIndex));
34352 csg_vertices.push_back(CsgVertex(CsgVector(vertices[setIndex][vertex1].coordinates), vertex1, setIndex));
34353 csg_polygons.push_back(CsgPolygon(csg_vertices, setIndex, edges[setIndex][e].edgeId,
34354 edges[setIndex][e].edgeType, edges[setIndex][e].bodyId));
34355 }
34356 csg.push_back(Csg(csg_polygons));
34357
34358 // call intersect
34359 result.clear();
34360 result = csg[0].intersect(csg[1]);
34361 vertices_result.clear();
34362
34363 // post process vertices, edges, faces:
34364 // first: regenerate polyVertices (unique vertices) vector
34365 for(MInt i = 0; i < 2; i++)
34366 for(MInt j = 0; j < maxNoVertices; j++)
34367 vertices_renamed(i, j) = -1;
34368
34369 MInt noVertices = 0;
34370 for(MInt p = 0; (unsigned)p < result.size(); p++) {
34371 for(MInt v = 0; (unsigned)v < result[p].vertices.size(); v++) {
34372 ASSERT(result[p].vertices.size() <= (unsigned)maxNoVertices, "");
34373 MInt vertexId = result[p].vertices[v].vertexId;
34374 MInt vertexSetIndex = result[p].vertices[v].setIndex;
34375 if(vertexId > -1) { // vertex corresponds to an existing vertex
34376 if(vertices_renamed(vertexSetIndex, vertexId) == -1) {
34377 // check if vertex has been added to vertices_result vector
34378 MBool vertexFound = false;
34379 MInt vertexIndex = -1;
34380 for(MInt i = 0; (unsigned)i < vertices_result.size(); i++) {
34381 if(vertices_result[i].pointType != 3) continue;
34382 MFloat coord_diff = F0;
34383 coord_diff += (result[p].vertices[v].pos.xx[0] - vertices_result[i].coordinates[0])
34384 * (result[p].vertices[v].pos.xx[0] - vertices_result[i].coordinates[0]);
34385 coord_diff += (result[p].vertices[v].pos.xx[1] - vertices_result[i].coordinates[1])
34386 * (result[p].vertices[v].pos.xx[1] - vertices_result[i].coordinates[1]);
34387
34388 if(coord_diff < m_eps * 10) {
34389 vertexFound = true;
34390 vertexIndex = i;
34391 break;
34392 }
34393 }
34394 if(vertexFound) {
34395 vertices_renamed(vertexSetIndex, vertexId) = vertexIndex;
34396 } else {
34397 vertices_renamed(vertexSetIndex, vertexId) = noVertices;
34398 vertices_result.push_back(polyVertex(vertices[vertexSetIndex][vertexId].pointId,
34399 vertices[vertexSetIndex][vertexId].pointType));
34400 vertices_result[noVertices].coordinates[0] = vertices[vertexSetIndex][vertexId].coordinates[0];
34401 vertices_result[noVertices].coordinates[1] = vertices[vertexSetIndex][vertexId].coordinates[1];
34402 noVertices++;
34403 }
34404 }
34405 result[p].vertices[v].vertexId = vertices_renamed(vertexSetIndex, vertexId);
34406 result[p].vertices[v].setIndex = -1;
34407 }
34408 }
34409 }
34410 for(MInt p = 0; (unsigned)p < result.size(); p++) {
34411 for(MInt v = 0; (unsigned)v < result[p].vertices.size(); v++) {
34412 MInt vertexId = result[p].vertices[v].vertexId;
34413 if(vertexId == -1) { // remaining vertices...
34414 // check if vertex has been added to vertices_result vector
34415 MBool vertexFound = false;
34416 MInt vertexIndex = -1;
34417 for(MInt i = 0; (unsigned)i < vertices_result.size(); i++) {
34418 MFloat coord_diff = F0;
34419 coord_diff += (result[p].vertices[v].pos.xx[0] - vertices_result[i].coordinates[0])
34420 * (result[p].vertices[v].pos.xx[0] - vertices_result[i].coordinates[0]);
34421 coord_diff += (result[p].vertices[v].pos.xx[1] - vertices_result[i].coordinates[1])
34422 * (result[p].vertices[v].pos.xx[1] - vertices_result[i].coordinates[1]);
34423
34424 if(coord_diff < m_eps * 10) {
34425 vertexFound = true;
34426 vertexIndex = i;
34427 break;
34428 }
34429 }
34430 if(vertexFound) {
34431 result[p].vertices[v].vertexId = vertexIndex;
34432 result[p].vertices[v].setIndex = -1;
34433 } else {
34434 vertices_result.push_back(polyVertex(-1, 3));
34435 vertices_result[noVertices].coordinates[0] = result[p].vertices[v].pos.xx[0];
34436 vertices_result[noVertices].coordinates[1] = result[p].vertices[v].pos.xx[1];
34437 result[p].vertices[v].vertexId = noVertices;
34438 result[p].vertices[v].setIndex = -1;
34439 noVertices++;
34440 }
34441 }
34442 }
34443 }
34444
34445 vertices[startSetIndex].swap(vertices_result);
34446 vertices_result.clear();
34447 edges[startSetIndex].clear();
34448 // second: regenerate edges and faces vectors (unique edges)
34449 MInt noFaces = 0;
34450 MInt noEdges = 0;
34451 for(MInt p = 0; (unsigned)p < result.size(); p++) {
34452 MInt bId = result[p].bodyId;
34453 MInt eId = result[p].faceId;
34454 MInt eType = result[p].faceType;
34455
34456 // add edges
34457 for(MInt v = 0; (unsigned)v < result[p].vertices.size() - 1; v++) {
34458 MInt j = (v + 1) % result[p].vertices.size();
34459 MInt vertexId = result[p].vertices[v].vertexId;
34460 MInt vertexIdNext = result[p].vertices[j].vertexId;
34461 MBool edgeFound = false;
34462 for(MInt e = 0; (unsigned)e < edges[startSetIndex].size(); e++) {
34463 MInt v0 = edges[startSetIndex][e].vertices[0];
34464 MInt v1 = edges[startSetIndex][e].vertices[1];
34465 if(vertexId == v0 && vertexIdNext == v1) {
34466 edgeFound = true;
34467 break;
34468 } else if(vertexId == v1 && vertexIdNext == v0) {
34469 edgeFound = true;
34470 break;
34471 }
34472 }
34473 if(!edgeFound) {
34474 edges[startSetIndex].push_back(polyEdge2D(vertexId, vertexIdNext, eId, eType, bId));
34475 vertices[startSetIndex][vertexId].edges.push_back(noEdges);
34476 vertices[startSetIndex][vertexIdNext].edges.push_back(noEdges);
34477 edges[startSetIndex][noEdges].normal[0] = result[p].plane.normal.xx[0];
34478 edges[startSetIndex][noEdges].normal[1] = result[p].plane.normal.xx[1];
34479 edges[startSetIndex][noEdges].w = -result[p].plane.w;
34480 noEdges++;
34481 }
34482 }
34483 noFaces++;
34484 }
34485 // TODO labels:FVMB change CSG routine such that it works with the present datastructure!
34486 }
34487
34488 // debug: test, if each vertex has exactly 2 edges:
34489 for(MInt v = 0; (unsigned)v < vertices[startSetIndex].size(); v++) {
34490 if(vertices[startSetIndex][v].edges.size() == 2) continue;
34491 cerr << " Error on cell " << cellId << ". Cell has vertex with not 2 edges... " << v << "/"
34492 << vertices[startSetIndex][v].edges.size() << endl;
34493 writeVTKFileOfCell(cellId, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34494 outputPolyData(cellId, &cutCells, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34495 ASSERT(vertices[startSetIndex][v].edges.size() == 2, "");
34496 }
34497
34498 // 4. b compose cell
34499 if(edges[startSetIndex].size() == 0) {
34500 cutCells.push_back(polyCutCell(bndryId, &a_coordinate(cellId, 0)));
34501 }
34502 for(MInt edgeCounter = 0; (unsigned)edgeCounter < edges[startSetIndex].size(); edgeCounter++) {
34503 if(edges[startSetIndex][edgeCounter].cutCell > -1) continue;
34504 edgeStack.push(edgeCounter);
34505 MInt currentCutCell = cutCells.size();
34506 cutCells.push_back(polyCutCell(bndryId, &a_coordinate(cellId, 0)));
34507 edges[startSetIndex][edgeCounter].cutCell = currentCutCell;
34508 cutCells[currentCutCell].faces_edges.push_back(edgeCounter);
34509 while(!edgeStack.empty()) {
34510 MInt currentEdge = edgeStack.top();
34511 edgeStack.pop();
34512 MInt vertex = edges[startSetIndex][currentEdge].vertices[1];
34513 MInt otherEdge = vertices[startSetIndex][vertex].edges[0];
34514 if(otherEdge == currentEdge) otherEdge = vertices[startSetIndex][vertex].edges[1];
34515 if(edges[startSetIndex][otherEdge].cutCell == -1) {
34516 cutCells[currentCutCell].faces_edges.push_back(otherEdge);
34517 edges[startSetIndex][otherEdge].cutCell = currentCutCell;
34518 edgeStack.push(otherEdge);
34519 }
34520 }
34521 }
34522
34523 // 5. compute polyhedron(polyhedra)
34524 compVolumeIntegrals(&cutCells, &edges[startSetIndex], &vertices[startSetIndex]);
34525
34526 // 5.1. if required, join cut surfaces if their normal vectors are similar enough
34527
34528 // 6. relate polyhedron(polyhedra) quantities to Cartesian cell quantities -> finish cell
34529 // 6.0. Currently: Split cells and split Cartesian surfaces are not allowed -> check here!
34530 if(cutCells.size() > 1) {
34531 cerr << "split cell detected. These are not implemented in MB framework yet. cell " << cellId << endl;
34532 writeVTKFileOfCell(cellId, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34533 outputPolyData(cellId, &cutCells, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34534 mTerm(1, AT_, "split cell detected. These are not implemented in MB framework yet. exiting...");
34535 continue;
34536 }
34537 MInt noFacesPerCartesianFace[6] = {0, 0, 0, 0};
34538 MInt noBodySurfaces = 0;
34539 for(MInt e = 0; (unsigned)e < cutCells[0].faces_edges.size(); e++) {
34540 MInt edge = cutCells[0].faces_edges[e];
34541 if(edges[startSetIndex][edge].edgeType == 0 || edges[startSetIndex][edge].edgeType == 1)
34542 noFacesPerCartesianFace[edges[startSetIndex][edge].edgeId]++;
34543 else
34544 noBodySurfaces++;
34545 }
34546 for(MInt i = 0; i < m_noDirs; i++) {
34547 if(noFacesPerCartesianFace[i] > 1) {
34548 cerr << "split face detected. These are not implemented in MB framework yet. cell " << cellId << ", face " << i
34549 << endl;
34550 writeVTKFileOfCell(cellId, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34551 writeVTKFileOfCutCell(cellId, &cutCells, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34552 outputPolyData(cellId, &cutCells, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34553 mTerm(1, AT_, " split face detected. These are not implemented in MB framework yet. exiting...");
34554 continue;
34555 }
34556 }
34557 if(noBodySurfaces > FvBndryCell<2, SysEqn>::m_maxNoSurfaces) {
34558 cerr << "more than FvBndryCell<2,SysEqn>::m_maxNoSurfaces cut surfaces detected for a cell. This is not "
34559 "implemented "
34560 "in MB framework yet. cell "
34561 << cellId << endl;
34562 writeVTKFileOfCell(cellId, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34563 writeVTKFileOfCutCell(cellId, &cutCells, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34564 outputPolyData(cellId, &cutCells, &edges[startSetIndex], &vertices[startSetIndex], startSetIndex);
34565 mTerm(1, AT_,
34566 " more than 3 cut surfaces detected for a cell. This is not implemented in MB framework yet. "
34567 "exiting...");
34568 continue;
34569 }
34570
34571
34572 // 6.1. set bndry cell and surface properties
34573 // deactivate cells with no faces
34574 if(cutCells[0].faces_edges.size() == 0) {
34575 a_hasProperty(cellId, SolverCell::IsInactive) = true;
34576 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) = false;
34577 cutCells[0].volume = F0;
34578 cutCells[0].center[0] = a_coordinate(cellId, 0);
34579 cutCells[0].center[1] = a_coordinate(cellId, 1);
34580 }
34581
34582 ASSERT(!(cutCells[0].volume < F0), "");
34583 ASSERT(!(std::isnan(cutCells[0].volume)), "");
34584 ASSERT(!(std::isnan(cutCells[0].center[0])), "");
34585 ASSERT(!(std::isnan(cutCells[0].center[1])), "");
34586 ASSERT(!(std::isinf(cutCells[0].volume)), "");
34587 ASSERT(!(std::isinf(cutCells[0].center[0])), "");
34588 ASSERT(!(std::isinf(cutCells[0].center[1])), "");
34589
34590 // non fluid sides:
34591 for(MInt f = 0; f < m_noDirs; f++) {
34592 if(noFacesPerCartesianFace[f] == 0) { // non fluid face
34593 bndryCell->m_externalFaces[f] = true;
34594 MInt srfcId = m_cellSurfaceMapping[cellId][f];
34595 if(srfcId > -1) {
34596 a_surfaceArea(srfcId) = F0;
34597 // m_isActiveSurface[ srfcId ] = false;
34598 deleteSurface(srfcId);
34599 }
34600 bndryCell->m_associatedSrfc[f] = -1;
34601 m_cutFaceArea[bndryId][f] = F0;
34602
34603 MInt nghbrId = c_neighborId(cellId, f);
34604 MInt nghbrBndryId = -1;
34605 if(nghbrId > -1) nghbrBndryId = a_bndryId(nghbrId);
34606
34607 if(nghbrBndryId > -1) {
34608 m_bndryCells->a[nghbrBndryId].m_associatedSrfc[m_revDir[f]] = -1;
34609 m_cutFaceArea[nghbrBndryId][m_revDir[f]] = F0;
34610 }
34611 }
34612 }
34613 // before reassigning cut points, store the relevant information
34614
34615 ASSERT(vertices[startSetIndex].size() <= (unsigned)maxNoVertices, "");
34616 for(MInt cp = 0; cp < maxNoVertices; cp++)
34617 newCutPointId[cp] = -1;
34618 for(MInt i = 0; (unsigned)i < vertices[startSetIndex].size(); i++)
34619 isPartOfBodySurface[i] = false;
34620 for(MInt e = 0; e < 2 * m_noEdges; e++) {
34621 pointEdgeId[e] = bndryCell->m_srfcs[0]->m_cutEdge[e];
34622 }
34623 noBodySurfaces = 0;
34624 bndryCell->m_volume = cutCells[0].volume;
34625 for(MInt i = 0; i < nDim; i++)
34626 bndryCell->m_coordinates[i] = cutCells[0].center[i] - a_coordinate(cellId, i);
34627 for(MInt f = 0; (unsigned)f < cutCells[0].faces_edges.size(); f++) {
34628 MInt edge = cutCells[0].faces_edges[f];
34629 ASSERT(!(edges[startSetIndex][edge].area < F0), "");
34630 ASSERT(!(std::isnan(edges[startSetIndex][edge].area)), "");
34631 ASSERT(!(std::isnan(edges[startSetIndex][edge].center[0])), "");
34632 ASSERT(!(std::isnan(edges[startSetIndex][edge].center[1])), "");
34633 ASSERT(!(std::isinf(edges[startSetIndex][edge].area)), "");
34634 ASSERT(!(std::isinf(edges[startSetIndex][edge].center[0])), "");
34635 ASSERT(!(std::isinf(edges[startSetIndex][edge].center[1])), "");
34636
34637 if(edges[startSetIndex][edge].edgeType > 1) { // body surface
34638 typename FvBndryCell<2, SysEqn>::BodySurface* bodySurface = bndryCell->m_srfcs[noBodySurfaces];
34639 bodySurface->m_area = edges[startSetIndex][edge].area;
34640 for(MInt i = 0; i < nDim; i++) {
34641 bodySurface->m_coordinates[i] = edges[startSetIndex][edge].center[i];
34642 bodySurface->m_normalVector[i] = edges[startSetIndex][edge].normal[i];
34643 }
34644 bodySurface->m_noCutPoints = 2;
34645 bodySurface->m_bndryCndId = m_movingBndryCndId;
34646 for(MInt cp = 0; (unsigned)cp < 2; cp++) {
34647 MInt vertex = edges[startSetIndex][edge].vertices[cp];
34648 isPartOfBodySurface[vertex] = true;
34649 MInt cutPointId = vertices[startSetIndex][vertex].pointId;
34650 newCutPointId[vertex] = cp;
34651 vertices[startSetIndex][vertex].cartSrfcId = noBodySurfaces;
34652 for(MInt i = 0; i < nDim; i++)
34653 bodySurface->m_cutCoordinates[cp][i] = vertices[startSetIndex][vertex].coordinates[i];
34654 if(cutPointId > -1) {
34655 bodySurface->m_cutEdge[cp] = pointEdgeId[cutPointId];
34656 bodySurface->m_bodyId[cp] = edges[startSetIndex][edge].bodyId;
34657 } else {
34658 bodySurface->m_cutEdge[cp] = -1;
34659 bodySurface->m_bodyId[cp] = edges[startSetIndex][edge].bodyId;
34660 }
34661 }
34662 noBodySurfaces++;
34663 } else { // Cartesian face
34664 MInt dirId = edges[startSetIndex][edge].edgeId;
34665 MInt srfcId = m_cellSurfaceMapping[cellId][dirId];
34666
34667 if(srfcId > -1) {
34668 for(MInt i = 0; i < nDim; i++) {
34669 a_surfaceCoordinate(srfcId, i) = edges[startSetIndex][edge].center[i];
34670 }
34671 a_surfaceArea(srfcId) = edges[startSetIndex][edge].area;
34672 bndryCell->m_associatedSrfc[dirId] = srfcId;
34673 }
34674 m_cutFaceArea[bndryId][dirId] = edges[startSetIndex][edge].area;
34675
34676 MInt nghbrId = c_neighborId(cellId, dirId);
34677 MInt nghbrBndryId = -1;
34678 if(nghbrId > -1) nghbrBndryId = a_bndryId(nghbrId);
34679 if(nghbrBndryId > -1) {
34680 m_bndryCells->a[nghbrBndryId].m_associatedSrfc[m_revDir[dirId]] = srfcId;
34681 m_cutFaceArea[nghbrBndryId][m_revDir[dirId]] = edges[startSetIndex][edge].area;
34682 }
34683 } // end else
34684 }
34685
34686 bndryCell->m_noSrfcs = (MInt)noBodySurfaces;
34687
34688 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
34689 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId = m_movingBndryCndId;
34690 }
34691
34692
34693 // transfer poly information to to output variables m_cutFacePointIds etc.
34694 m_noCutCellFaces[bndryId] = 0;
34695 const MInt maxPointsXD = 12;
34696 for(MInt c = 0; (unsigned)c < cutCells.size(); c++) {
34697 MInt nccf = m_noCutCellFaces[bndryId];
34698 m_noCutFacePoints[bndryId][nccf] = 0;
34699 for(MInt f = 0; (unsigned)f < cutCells[c].faces_edges.size(); f++) {
34700 MInt edge = cutCells[c].faces_edges[f];
34701 MInt vertex = edges[startSetIndex][edge].vertices[0];
34702 if(vertices[startSetIndex][vertex].pointType == 0) {
34703 m_cutFacePointIds[bndryId][maxPointsXD * nccf + m_noCutFacePoints[bndryId][nccf]] =
34704 vertices[startSetIndex][vertex].pointId;
34705 m_noCutFacePoints[bndryId][nccf]++;
34706 } else {
34707 if(!isPartOfBodySurface[vertex]) continue;
34708 MInt numCutPointsPreviousFaces = 0;
34709 for(MInt srfc = 0; srfc < vertices[startSetIndex][vertex].cartSrfcId; srfc++) {
34710 numCutPointsPreviousFaces += m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_noCutPoints;
34711 }
34712 MInt cp = numCutPointsPreviousFaces + newCutPointId[vertex];
34713 m_cutFacePointIds[bndryId][maxPointsXD * nccf + m_noCutFacePoints[bndryId][nccf]] = m_noCellNodes + (cp);
34714 m_noCutFacePoints[bndryId][nccf]++;
34715 }
34716 }
34717 m_noCutCellFaces[bndryId]++;
34718 }
34719 }
34720}
34721
34722
34731template <MInt nDim, class SysEqn>
34732void FvMbCartesianSolverXD<nDim, SysEqn>::sensorPatch(std::vector<std::vector<MFloat>>& sensors,
34733 std::vector<std::bitset<64>>& sensorCellFlag,
34734 std::vector<MFloat>& sensorWeight, MInt sensorOffset, MInt sen) {
34735 if(!m_engineSetup || !m_closeGaps) {
34736 this->patchRefinement(sensors, sensorCellFlag, sensorWeight, sensorOffset, sen);
34737 } else {
34738 // patch refinement only for certain crankAngles
34739 const MFloat cad = this->crankAngle(m_physicalTime, 0);
34740
34741 // define crank angles for which the patch is necesary
34742 const MFloat duration = 5;
34743 if(m_forceNoGaps == 2
34744 && ((cad > m_gapAngleOpen[0] && cad < m_gapAngleOpen[0] + duration) || // first Opening
34745 (cad > m_gapAngleClose[0] - duration && cad < m_gapAngleClose[0]) // first Closure
34746 )) {
34747 if(domainId() == 0) {
34748 cerr << "Setting sensor Patch-refinement for current CA!" << endl;
34749 }
34750
34751 this->patchRefinement(sensors, sensorCellFlag, sensorWeight, sensorOffset, sen);
34752
34753 const MInt valveBodyId = 2;
34754 const MInt bodySet = m_bodyToSetTable[valveBodyId];
34755 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
34756 const MInt gridCellId = grid().tree().solver2grid(cellId);
34757 if(sensors[sensorOffset + sen][gridCellId] > 0) {
34758 const MFloat valveDist = a_levelSetValuesMb(cellId, bodySet);
34759 if(fabs(valveDist) < 0.06757) continue;
34760 sensors[sensorOffset + sen][gridCellId] = 0;
34761 sensorCellFlag[gridCellId][sensorOffset + sen] = 0;
34762 }
34763 if(a_wasGapCell(cellId)) {
34764 sensors[sensorOffset + sen][gridCellId] = 1;
34765 sensorCellFlag[gridCellId][sensorOffset + sen] = 1;
34766 }
34767 }
34768 } else {
34769 if(domainId() == 0) {
34770 cerr << "Surpressing Patch-refinement for current CA!" << endl;
34771 }
34772 }
34773 }
34774}
34775
34776
34784template <MInt nDim, class SysEqn>
34786 TRACE();
34787
34788 vector<MInt> deletedBndryCells;
34789 vector<MInt> bndryChilds;
34790 std::map<MInt, MFloat> childBndryCells;
34791 std::map<MInt, MFloat> haloBndryCells;
34792
34793 MInt noRefOldBndryCells = m_refOldBndryCells.size();
34794 MPI_Allreduce(MPI_IN_PLACE, &noRefOldBndryCells, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
34795 "noRefOldBndryCells");
34796
34797 if(noRefOldBndryCells == 0) return;
34798
34799 m_log << "Correcting newly refined BndryCells after adaptation ...";
34800
34801 // NOTE: noChildren on non-leaf-Level cells may differ between window-and halo cells!!!
34802 MIntScratchSpace noRelevantChilds(a_noCells(), AT_, "noRelevantChilds");
34803 noRelevantChilds.fill(-1);
34804
34805 vector<MInt> refOldBndryCellsNew;
34806
34807 for(MInt it = 0; it < (signed)m_refOldBndryCells.size(); it++) {
34808 const MInt cellId = m_refOldBndryCells[it];
34809 ASSERT(c_isLeafCell(cellId), "");
34810
34811 if(a_hasProperty(cellId, SolverCell::IsInactive)) {
34812 // treat inactive oldBndryCells as if they were inactive before!
34813 a_hasProperty(cellId, SolverCell::WasInactive) = true;
34814 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId));
34815 for(MInt v = 0; v < m_noFVars; v++) {
34816 m_rhs0[cellId][v] = 0;
34817 }
34818 auto it1 = m_oldBndryCells.find(cellId);
34819 m_oldBndryCells.erase(it1);
34820 } else {
34821 if(!a_isBndryCell(cellId)) {
34822 // treat uncut oldBndryCells as if they were active before!
34823 a_hasProperty(cellId, SolverCell::WasInactive) = false;
34824 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId));
34825 for(MInt v = 0; v < m_noFVars; v++) {
34826 m_rhs0[cellId][v] = 0;
34827 }
34828 auto it1 = m_oldBndryCells.find(cellId);
34829 m_oldBndryCells.erase(it1);
34830 } else {
34831 // oldBndryCell is also newBndryCell
34832 a_hasProperty(cellId, SolverCell::WasInactive) = false;
34833 // save bndryCells to update m_refOldBndryCells with bndryCells which remain
34834 // bndryCells!
34835 refOldBndryCellsNew.push_back(cellId);
34836 if(a_isHalo(cellId)) continue;
34837 // count other BndryCells from the same parent!
34838 MInt noBndryCellChilds = 0;
34839 const MInt parent = c_parentId(cellId);
34840 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
34841 const MInt child = c_childId(parent, childId);
34842 if(child == -1) continue;
34843 if(a_isBndryCell(child)) noBndryCellChilds++;
34844 }
34845 ASSERT(noBndryCellChilds > 0, ""); // atleast the cellId
34846 noRelevantChilds(cellId) = noBndryCellChilds;
34847 // for mass-conservity the rhs0 parent (oldBndryCell) value must be split evenly
34848 // between all newBndryCells, as the values in all other cells are resetted!
34849 // setting the old Volume/sweptVolume based on currecnt values as in firstRHS
34850 // reduces pressure waves!
34851 // NOTE: as the boundaryVelocity is not set yet, the value will be updated in
34852 // correctRefinedBndryCellVolume later!
34853 for(MInt v = 0; v < m_noFVars; v++) {
34854 m_rhs0[cellId][v] = m_rhs0[parent][v] / noBndryCellChilds;
34855 }
34856 }
34857 }
34858 }
34859
34860 exchangeData(&noRelevantChilds[0],
34861 1); // Skip azimuthal exchange since infromation on azimuthal windows and halos is not the same
34862
34863 for(MInt cellId = noInternalCells(); cellId < c_noCells(); cellId++) {
34864 ASSERT(a_isHalo(cellId), "");
34865 if(!a_isBndryCell(cellId)) continue;
34866 auto it = std::find(m_refOldBndryCells.begin(), m_refOldBndryCells.end(), cellId);
34867 if(it != m_refOldBndryCells.end()) {
34868 MInt noBndryCellChilds = noRelevantChilds(cellId);
34869 const MInt parent = c_parentId(cellId);
34870 for(MInt v = 0; v < m_noFVars; v++) {
34871 m_rhs0[cellId][v] = m_rhs0[parent][v] / noBndryCellChilds;
34872 }
34873 }
34874 }
34875
34876 m_refOldBndryCells.clear();
34877
34878 // now add old bndryCells which will remain bndryCell!
34879 for(MInt it = 0; it < (signed)refOldBndryCellsNew.size(); it++) {
34880 const MInt cellId = refOldBndryCellsNew[it];
34881 m_refOldBndryCells.push_back(cellId);
34882 }
34883
34884 m_log << " Finished" << endl;
34885}
34886
34887
34892template <MInt nDim, class SysEqn>
34894 TRACE();
34895
34896 for(MInt it = 0; it < (signed)m_refOldBndryCells.size(); it++) {
34897 const MInt cellId = m_refOldBndryCells[it];
34898 ASSERT(c_isLeafCell(cellId), "");
34899 ASSERT(a_isBndryCell(cellId), "");
34900
34901 MFloat dV = F0;
34902 MFloat dt = timeStep(true);
34903 const MInt bndryId = a_bndryId(cellId);
34904 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
34905 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
34906 for(MInt i = 0; i < nDim; i++) {
34907 MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
34908 dV -= dt * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] * nml * area;
34909 }
34910 }
34911 const MFloat deltaVol = m_RKalpha[m_noRKSteps - 2] * dV + (F1 - m_RKalpha[m_noRKSteps - 2]) * dV;
34912
34913 // old values are set based on the current values!
34914 // not exactly mass-conservative, but reduces pressure problems at the newly refined bndry!
34915 m_cellVolumesDt1[cellId] = mMax(m_volumeThreshold, a_cellVolume(cellId) - deltaVol);
34916 m_sweptVolumeDt1[bndryId] = dV;
34917
34918 auto it1 = m_oldBndryCells.find(cellId);
34919 ASSERT(it1 != m_oldBndryCells.end(), "");
34920 m_oldBndryCells.erase(it1);
34921 m_oldBndryCells.insert(make_pair(cellId, dV));
34922 }
34923 m_refOldBndryCells.clear();
34924}
34925
34926
34931template <MInt nDim, class SysEqn>
34933 TRACE();
34934
34935 for(auto it = m_coarseOldBndryCells.begin(); it != m_coarseOldBndryCells.end(); it++) {
34936 const MInt cellId = *it;
34937 ASSERT(c_isLeafCell(cellId), "");
34938
34939 if(a_isBndryCell(cellId)) {
34940 MFloat dV = F0;
34941 MFloat dt = timeStep(true);
34942 const MInt bndryId = a_bndryId(cellId);
34943 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
34944 MFloat area = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
34945 for(MInt i = 0; i < nDim; i++) {
34946 MFloat nml = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_normalVector[i];
34947 dV -= dt * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]] * nml * area;
34948 }
34949 }
34950
34951 // old values are set based on the current values!
34952 // not exactly mass-conservative, but reduces pressure problems at the newly refined bndry!
34953 const MFloat deltaVol = m_RKalpha[m_noRKSteps - 2] * dV + (F1 - m_RKalpha[m_noRKSteps - 2]) * dV;
34954 m_cellVolumesDt1[cellId] = mMax(m_volumeThreshold, a_cellVolume(cellId) - deltaVol);
34955 m_sweptVolumeDt1[bndryId] = dV;
34956
34957 auto it1 = m_oldBndryCells.find(cellId);
34958 ASSERT(it1 != m_oldBndryCells.end(), "");
34959 m_oldBndryCells.erase(it1);
34960 m_oldBndryCells.insert(make_pair(cellId, dV));
34961 }
34962 }
34963
34964 m_coarseOldBndryCells.clear();
34965}
34966
34967
34972template <MInt nDim, class SysEqn>
34973template <class _, std::enable_if_t<nDim == 3, _*>>
34974ATTRIBUTES1(ATTRIBUTE_NO_AUTOVEC)
34976 TRACE();
34977
34978 // returns the dir in which the cutPoint on the edge is not 1 or -1
34979 const MInt DOFStencil[12] = {1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 2, 2};
34980 NEW_SUB_TIMER_STATIC(tCutFace_00, "cutFaceNew_00", m_tCutGroup);
34981 RECORD_TIMER_START(tCutFace_00);
34982
34983 using CC = CutCell<nDim>;
34984 std::vector<CC> cutCellData;
34985
34986 std::vector<MInt> cutCellIdMapping;
34987 cutCellIdMapping.resize(a_noCells());
34988 for(MInt i = 0; i < a_noCells(); i++) {
34989 cutCellIdMapping[i] = -1;
34990 }
34991
34992 cutCellData.reserve((signed)m_fvBndryCnd->m_bndryCells->size() - m_noOuterBndryCells);
34993 // plus 1 percent for split cells?
34994
34995 MInt cnt = 0;
34996 ASSERT(m_noLevelSetsUsedForMb <= CC::maxNoSets, "");
34997 const MInt faceCornerMapping[6][4] = {{2, 6, 4, 0}, {1, 5, 7, 3}, {0, 4, 5, 1},
34998 {3, 7, 6, 2}, {2, 3, 1, 0}, {6, 7, 5, 4}};
34999 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
35000 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
35001 cutCellData.emplace_back();
35002 cutCellData[cnt].cellId = cellId;
35003 cutCellData[cnt].isGapCell = false;
35004 cutCellIdMapping[cellId] = cnt;
35005 if(m_levelSet && m_closeGaps) {
35006 cutCellData[cnt].isGapCell = (a_hasProperty(cellId, SolverCell::IsGapCell));
35007 }
35008 ASSERT(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints <= CC::maxNoCutPoints, "");
35009 cutCellData[cnt].noCutPoints = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
35010 for(MInt cp = 0; cp < m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cp++) {
35011 const MInt cutEdge = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cp];
35012 const MInt nonZeroDir = DOFStencil[cutEdge];
35013
35014 for(MInt k = 0; k < nDim; k++) {
35015 MFloat cutCoordinate = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cp][k];
35016 // NOTE: scaling cut-coordinate to the range of -1,1!
35018 const MFloat cellLength = c_cellLengthAtLevel(a_cutCellLevel(cellId));
35019 const MFloat cellHalfLength = F1B2 * cellLength;
35020 cutCoordinate = (cutCoordinate - a_coordinate(cellId, k)) / cellHalfLength;
35021
35022 if(k != nonZeroDir) {
35023 // cutCoordinate should be F1 or -F1!
35024 if(cutCoordinate > F0) {
35025 cutCoordinate = F1;
35026 } else {
35027 cutCoordinate = -F1;
35028 }
35029 } else {
35030 // cut Coordinate should be between (-F1 + 20 * m_eps) and (F1 - 20 * m_eps)
35031 if(cutCoordinate > F1 - 20 * m_eps) cutCoordinate = F1 - 20 * m_eps;
35032 if(cutCoordinate < -F1 + 20 * m_eps) cutCoordinate = -F1 + 20 * m_eps;
35033 }
35034 }
35035 cutCellData[cnt].cutPoints[cp][k] = cutCoordinate;
35036 }
35037
35038
35039 cutCellData[cnt].cutBodyIds[cp] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_bodyId[cp];
35040 cutCellData[cnt].cutEdges[cp] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cp];
35041 }
35042 MInt cndId = m_bndryCandidateIds[cellId];
35043 if(cndId < 0) mTerm(1, AT_, "error: cell is not a bndryCandidate!");
35044 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
35045 cutCellData[cnt].associatedBodyIds[set] = a_associatedBodyIds(cellId, set);
35046 for(MInt k = 0; k < CC::noCorners; k++) {
35047 if(!m_candidateNodeSet[cndId * m_noCellNodes + k]) cerr << "Warning: node not set!" << endl;
35048 cutCellData[cnt].cornerIsInsideGeometry[set][k] = m_pointIsInside[bndryId][IDX_LSSETMB(k, set)];
35049 }
35050 for(MInt k = 0; k < CC::noFaces; k++) {
35051 MFloat phi = F0;
35052 for(MInt j = 0; j < 4; j++) {
35053 phi += F1B4 * m_candidateNodeValues[IDX_LSSETNODES(cndId, faceCornerMapping[k][j], set)];
35054 }
35055 cutCellData[cnt].faceCentroidIsInsideGeometry[set][k] = (phi < F0);
35056 }
35057 }
35058 cnt++;
35059 }
35060
35061 const MUint noCutCells = cutCellData.size();
35062
35063 // debug-output:
35064 // check that the cut-edges, match with the according corner ls-values!
35065 MBool debugOutput = false;
35066 if(debugOutput && domainId() == 302 && globalTimeStep == -1) {
35067 MInt cutCellId = 10;
35068 MInt neighborCutCellId = 30;
35069 MInt neighbrId = cutCellData[neighborCutCellId].cellId;
35070
35071 MInt cellId = cutCellData[cutCellId].cellId;
35072 MInt cndId = m_bndryCandidateIds[cellId];
35073
35074 cerr << "Found " << cutCellData[cutCellId].noCutPoints << " Cut-Points for CellId " << cellId << endl;
35075 cerr << "Cut edges are: " << endl;
35076 for(MInt cp = 0; cp < cutCellData[cutCellId].noCutPoints; cp++) {
35077 cerr << " Cut-Point " << cp << " " << cutCellData[cutCellId].cutEdges[cp] << endl;
35078 }
35079
35080 cerr << "Corner-values are: " << endl;
35081 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
35082 for(MInt k = 0; k < CC::noCorners; k++) {
35083 cerr << set << " " << m_candidateNodeValues[IDX_LSSETNODES(cndId, k, set)];
35084 }
35085 cerr << endl;
35086 }
35087
35088 cerr << "Found " << cutCellData[neighborCutCellId].noCutPoints << " Cut-Points for neighborCutCellId " << neighbrId
35089 << endl;
35090 cerr << "Cut edges are: " << endl;
35091 for(MInt cp = 0; cp < cutCellData[neighborCutCellId].noCutPoints; cp++) {
35092 cerr << " Cut-Point " << cp << " " << cutCellData[neighborCutCellId].cutEdges[cp] << endl;
35093 }
35094
35095 MInt nghbrCndId = m_bndryCandidateIds[neighbrId];
35096
35097 cerr << "Corner-values are: " << endl;
35098 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
35099 for(MInt k = 0; k < CC::noCorners; k++) {
35100 cerr << set << " " << m_candidateNodeValues[IDX_LSSETNODES(nghbrCndId, k, set)];
35101 }
35102 cerr << endl;
35103 }
35104 }
35105
35106 // Performe Cut-Cell-Checks:
35107 for(MUint cutc = 0; cutc < noCutCells; cutc++) {
35108 // 1) Have at least nDim Cut-Cells
35109 if(cutCellData[cutc].noCutPoints < nDim) {
35110 mTerm(1, AT_, "CutCell with less than nDim CutPoints");
35111 }
35112 ASSERT(cutCellData[cutc].cellId == m_fvBndryCnd->m_bndryCells->a[cutc + m_noOuterBndryCells].m_cellId, "");
35113
35114 MInt startSet = 0;
35115 MInt endSet = 1;
35116 if(m_complexBoundary && (!cutCellData[cutc].isGapCell)) {
35117 startSet = 1;
35118 endSet = m_noLevelSetsUsedForMb;
35119 }
35120
35121 // 2) cornerIsInsideGeometry must fit with the corner LS-value!
35122 MInt cndId = m_bndryCandidateIds[cutCellData[cutc].cellId];
35123 for(MInt set = startSet; set < endSet; set++) {
35124 for(MInt k = 0; k < CC::noCorners; k++) {
35125 if(cutCellData[cutc].cornerIsInsideGeometry[set][k]) {
35126 ASSERT(m_candidateNodeValues[IDX_LSSETNODES(cndId, k, set)] < F0, "");
35127 } else {
35128 ASSERT(m_candidateNodeValues[IDX_LSSETNODES(cndId, k, set)] > F0,
35129 "ERROR in " + to_string(domainId()) + " " + to_string(cutCellData[cutc].cellId) + " "
35130 + to_string(c_globalId(cutCellData[cutc].cellId)) + " " + to_string(k) + " "
35131 + to_string(m_candidateNodeValues[IDX_LSSETNODES(cndId, k, set)]));
35132 }
35133 }
35134 }
35135 }
35136
35137 const MInt maxNoVertices = 300;
35138 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
35139 MIntScratchSpace splitFaceCellIds(m_fvBndryCnd->m_maxNoBndryCells, AT_, "splitFaceCellIds");
35140 for(MInt c = 0; c < m_fvBndryCnd->m_maxNoBndryCells; c++)
35141 splitFaceCellIds[c] = -1;
35142 MIntScratchSpace splitCellIds(noBndryCells, AT_, "splitCellIds");
35143 std::vector<cellWithSplitFace> splitFaceCells;
35144 MIntScratchSpace surfaceIdentificatorCounters(m_noDirs + m_noEmbeddedBodies, AT_, "surfaceIdentificatorCounters");
35145 MIntScratchSpace cellSurfaceMapping_backup(m_noDirs, AT_, "cellSurfaceMapping_backup");
35146 MIntScratchSpace splitCellList(CC::maxSplitCells, AT_, "splitCellList");
35147
35148 const MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
35149 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
35150
35151 const MInt faceCornerCode[6][4] = {{0, 2, 6, 4}, // in MAIA
35152 {3, 1, 5, 7}, {1, 0, 4, 5}, {2, 3, 7, 6}, {0, 1, 3, 2}, {5, 4, 6, 7}};
35153
35154 RECORD_TIMER_STOP(tCutFace_00);
35155
35157
35158 // debugging-Output:
35159 debugOutput = false;
35160 MInt debugTimeStep = -1; // 33
35161 MInt debugDomainId = 302;
35162 MInt debugCellId = 23192;
35163 MInt debugNeighborId = 23160;
35164 MInt debugDir = 4;
35165 MInt reverseDir = m_revDir[debugDir];
35166 MInt debugSrfcId = m_cellSurfaceMapping[debugCellId][debugDir];
35167
35168 if(debugOutput && globalTimeStep == debugTimeStep && domainId() == debugDomainId) {
35169 MInt debugCutCellId = -1;
35170 MInt debugNeighborCutCellId = -1;
35171
35172 ASSERT(m_cellSurfaceMapping[debugCellId][debugDir], "");
35173
35174 cerr << "Debug-Surface-Id is " << debugSrfcId << " with " << endl;
35175 cerr << "Surface-Neighbor-0 " << a_surfaceNghbrCellId(debugSrfcId, 0) << endl;
35176 cerr << "Surface-Neighbor-1 " << a_surfaceNghbrCellId(debugSrfcId, 1) << endl;
35177
35178 if(debugSrfcId > -1) {
35179 if(a_surfaceNghbrCellId(debugSrfcId, 0) == debugCellId) {
35180 debugNeighborId = a_surfaceNghbrCellId(debugSrfcId, 1);
35181 } else {
35182 debugNeighborId = a_surfaceNghbrCellId(debugSrfcId, 0);
35183 }
35184 }
35185
35186 for(MUint cutc = 0; cutc < noCutCells; cutc++) {
35187 if(cutCellData[cutc].cellId == debugNeighborId) {
35188 cerr << "Neighbor CutCellId " << cutc << endl;
35189 debugNeighborCutCellId = cutc;
35190 }
35191 if(cutCellData[cutc].cellId == debugCellId) {
35192 cerr << "Cell CutCellId " << cutc << endl;
35193 debugCutCellId = cutc;
35194 }
35195 }
35196
35197 MInt cellSet = a_associatedBodyIds(debugCellId, 0);
35198 MInt neighborSet = a_associatedBodyIds(debugNeighborId, 0);
35199
35200 cerr << "Cell-Set: " << cellSet;
35201 cerr << "Neighbor-Set: " << neighborSet;
35202
35203 if(debugCutCellId > -1) {
35204 cerr << "Cell-CutCellInfo " << cutCellData[debugCutCellId].cellId << " has "
35205 << cutCellData[debugCutCellId].noSplitChilds << " SplitChilds and "
35206 << cutCellData[debugCutCellId].noFacesPerCartesianDir[debugDir] << " Faces in the debug-Direction!"
35207 << "The ls-vales of the face are: " << endl;
35208 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
35209 for(MInt corner = 0; corner < 4; corner++) {
35210 cerr << set << " " << setprecision(16)
35211 << m_candidateNodeValues[IDX_LSSETNODES(m_bndryCandidateIds[debugCellId],
35212 faceCornerCode[debugDir][corner], set)];
35213 }
35214 cerr << endl;
35215 }
35216 }
35217
35218 if(debugNeighborCutCellId) {
35219 cerr << "Neighbor-CutCellInfo " << cutCellData[debugNeighborCutCellId].cellId << " has "
35220 << cutCellData[debugNeighborCutCellId].noSplitChilds << " SplitChilds and "
35221 << cutCellData[debugNeighborCutCellId].noFacesPerCartesianDir[reverseDir]
35222 << " Faces in the reverse-debug-Direction!"
35223 << "The ls-vales of the face are: " << endl;
35224 for(MInt set = 0; set < m_noLevelSetsUsedForMb; set++) {
35225 for(MInt corner = 0; corner < 4; corner++) {
35226 cerr << set << " " << setprecision(16)
35227 << m_candidateNodeValues[IDX_LSSETNODES(m_bndryCandidateIds[debugNeighborId],
35228 faceCornerCode[reverseDir][corner], set)];
35229 }
35230 cerr << endl;
35231 }
35232 }
35233 cerr << "Coordiantes: " << a_coordinate(debugCellId, 0) << " " << a_coordinate(debugCellId, 1) << " "
35234 << a_coordinate(debugCellId, 2) << endl;
35235 cerr << "Coordinates2: " << a_coordinate(debugNeighborId, 0) << " " << a_coordinate(debugNeighborId, 1) << " "
35236 << a_coordinate(debugNeighborId, 2) << endl;
35237 }
35238
35239
35240 NEW_SUB_TIMER_STATIC(tCutFace_8, "cutFaceNew_8", m_tCutGroup);
35241 NEW_SUB_TIMER_STATIC(tCutFace_9, "cutFaceNew_9", m_tCutGroup);
35242 NEW_SUB_TIMER_STATIC(tCutFace_10, "cutFaceNew_10", m_tCutGroup);
35243
35244 RECORD_TIMER_START(tCutFace_8);
35245
35246 // a) add split-childs to the fvmb-cell-collector
35247 for(MUint cutc = 0; cutc < noCutCells; cutc++) {
35248 const MInt cellId = cutCellData[cutc].cellId;
35249 const MInt bndryId = a_bndryId(cellId);
35250 MInt noSplitChildren = cutCellData[cutc].noSplitChilds;
35251
35252 MInt splitCellId = -1;
35253 if(noSplitChildren > 1) {
35254 // uses newst splitCell-Version:
35255 splitCellId = createSplitCell(cellId, noSplitChildren);
35256 for(MInt sc = 0; sc < noSplitChildren; sc++) {
35257 MUint splitcutc = cutCellData[cutc].splitChildIds[sc];
35258
35259 MInt splitChildId = m_splitChilds[splitCellId][sc];
35260 cutCellData[splitcutc].cellId = splitChildId;
35261 }
35262 }
35263 splitCellIds(bndryId) = splitCellId;
35264 }
35265
35266 // update coordinate and length of the scaled cutCell:
35268 for(MUint cutc = 0; cutc < cutCellData.size(); cutc++) {
35269 const MInt cellId = cutCellData[cutc].cellId;
35270 const MInt bndryId = a_bndryId(cellId);
35271 const MFloat cellLength = c_cellLengthAtLevel(a_cutCellLevel(cellId));
35272 const MFloat cellHalfLength = F1B2 * cellLength;
35273
35274 for(MInt cpId = 0; cpId < cutCellData[cutc].noCutPoints; cpId++) {
35275 for(MInt i = 0; i < nDim; i++) {
35276 cutCellData[cutc].cutPoints[cpId][i] =
35277 cutCellData[cutc].cutPoints[cpId][i] * cellHalfLength + a_coordinate(cellId, i);
35278
35279 ASSERT(fabs(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cpId][i]
35280 - cutCellData[cutc].cutPoints[cpId][i])
35281 < 0.00000001,
35282 "");
35283 }
35284 }
35285
35286 cutCellData[cutc].volume = cutCellData[cutc].volume * POW3(cellHalfLength);
35287 if(cutCellData[cutc].volume < m_eps) cutCellData[cutc].volume = m_eps;
35288
35289 // NOTE: the volumetricCentroid is the distance to the cartesian Cell center
35290 // and not to the origin!
35291 for(MInt i = 0; i < nDim; i++) {
35292 cutCellData[cutc].volumetricCentroid[i] = cutCellData[cutc].volumetricCentroid[i] * cellHalfLength;
35293 }
35294
35295 for(MInt bs = 0; bs < cutCellData[cutc].noBoundarySurfaces; bs++) {
35296 for(MInt i = 0; i < nDim; i++) {
35297 cutCellData[cutc].boundarySurfaceCentroid[bs][i] =
35298 cutCellData[cutc].boundarySurfaceCentroid[bs][i] * cellHalfLength + a_coordinate(cellId, i);
35299 }
35300 cutCellData[cutc].boundarySurfaceArea[bs] = cutCellData[cutc].boundarySurfaceArea[bs] * POW2(cellHalfLength);
35301
35302 if(cutCellData[cutc].boundarySurfaceArea[bs] < m_eps) cutCellData[cutc].boundarySurfaceArea[bs] = m_eps;
35303 }
35304
35305
35306 for(MInt cs = 0; cs < cutCellData[cutc].noCartesianSurfaces; cs++) {
35307 for(MInt i = 0; i < nDim; i++) {
35308 cutCellData[cutc].cartFaceCentroid[cs][i] =
35309 cutCellData[cutc].cartFaceCentroid[cs][i] * cellHalfLength + a_coordinate(cellId, i);
35310 }
35311 cutCellData[cutc].cartFaceArea[cs] = cutCellData[cutc].cartFaceArea[cs] * POW2(cellHalfLength);
35312
35313 if(cutCellData[cutc].cartFaceArea[cs] < m_eps) cutCellData[cutc].cartFaceArea[cs] = m_eps;
35314 }
35315
35316 for(MInt aId = 0; aId < cutCellData[cutc].noAdditionalVertices; aId++) {
35317 for(MInt i = 0; i < nDim; i++) {
35318 cutCellData[cutc].additionalVertices[aId][i] =
35319 cutCellData[cutc].additionalVertices[aId][i] * cellHalfLength + a_coordinate(cellId, i);
35320 }
35321 }
35322 }
35323 }
35324
35325
35326 // b) convert data back from the geometry-intersection class to the old bndryCell class!
35327 for(MUint cutc = 0; cutc < cutCellData.size(); cutc++) {
35328 // MInt bndryId = cutCellData[cutc].cutCellId;
35329 const MInt cellId = cutCellData[cutc].cellId;
35330 const MInt bndryId = a_bndryId(cellId);
35331 MInt splitParentId = cutCellData[cutc].splitParentId;
35332 MInt noSplitChilds = cutCellData[cutc].noSplitChilds;
35333 FvBndryCell<nDim, SysEqn>* bndryCell = &m_fvBndryCnd->m_bndryCells->a[bndryId];
35334 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId != cutCellData[cutc].cellId) {
35335 cerr << domainId() << ": diff0 " << cutc << " " << noSplitChilds << " " << splitParentId << " "
35336 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId << " " << cutCellData[cutc].cellId << endl;
35337 continue;
35338 }
35339 bndryCell->m_volume = cutCellData[cutc].volume;
35340 for(MInt i = 0; i < nDim; i++) {
35341 bndryCell->m_coordinates[i] = cutCellData[cutc].volumetricCentroid[i];
35342 }
35343 MInt noSrfcs = cutCellData[cutc].noBoundarySurfaces;
35344 bndryCell->m_noSrfcs = noSrfcs;
35345 for(MInt bs = 0; bs < noSrfcs; bs++) {
35346 typename FvBndryCell<3, SysEqn>::BodySurface* bodySurface = bndryCell->m_srfcs[bs];
35347 for(MInt i = 0; i < nDim; i++) {
35348 bodySurface->m_coordinates[i] = cutCellData[cutc].boundarySurfaceCentroid[bs][i];
35349 bodySurface->m_normalVector[i] = cutCellData[cutc].boundarySurfaceNormal[bs][i];
35350 }
35351 bodySurface->m_area = cutCellData[cutc].boundarySurfaceArea[bs];
35352
35353 cutCellData[cutc].boundarySurfaceBndryCndId[bs] = m_movingBndryCndId;
35354
35355 bodySurface->m_bndryCndId = cutCellData[cutc].boundarySurfaceBndryCndId[bs];
35356 bodySurface->m_bodyId[0] = cutCellData[cutc].boundarySurfaceBodyId[bs];
35357
35358 for(MInt f = 0; f < 2 * nDim; f++) {
35359 bndryCell->m_externalFaces[f] = cutCellData[cutc].externalFaces[f];
35360 }
35361 for(MInt c = 0; c < IPOW2(nDim); c++) {
35362 m_pointIsInside[bndryId][IDX_LSSETMB(c, 0)] = cutCellData[cutc].cornerIsInsideGeometry[0][c];
35363 }
35364 }
35365 }
35366
35367 for(MUint cutc = 0; cutc < noCutCells; cutc++) {
35368 // MInt bndryId = cutCellData[cutc].cutCellId;
35369 const MInt cellId = cutCellData[cutc].cellId;
35370 const MInt bndryId = a_bndryId(cellId);
35371 FvBndryCell<nDim, SysEqn>* bndryCell = &m_fvBndryCnd->m_bndryCells->a[bndryId];
35372 const MFloat cellLength0 = c_cellLengthAtLevel(a_level(cellId));
35373 const MFloat cellHalfLength = F1B2 * cellLength0;
35374 MInt noSplitChildren = cutCellData[cutc].noSplitChilds;
35375 MInt splitCellId = splitCellIds(bndryId);
35376
35377
35378 // c) create a cellSurfaceMapping_backup and the splitCellList
35379 // CAUTION: set noSplitChildren to 1 for all regular cells!
35380 for(MInt dir = 0; dir < m_noDirs; dir++) {
35381 cellSurfaceMapping_backup[dir] = m_cellSurfaceMapping[cellId][dir];
35382 }
35383
35384 if(noSplitChildren > 1) {
35385 ASSERT(splitCellId > -1, "");
35386 for(MInt sc = 0; sc < noSplitChildren; sc++) {
35387 splitCellList[sc] = cutCellData[cutc].splitChildIds[sc];
35388 }
35389 } else {
35390 noSplitChildren = 1;
35391 splitCellList[0] = cutc;
35392 }
35393
35394 // d) reset the cellSurfaceMapping and
35395 // delete all surfaces for neighboring cells with splitChildren
35396 // othweise reset the surface-neighbors between a regular cutCell
35397 // and a cell with splitChilds
35398 if(noSplitChildren > 1) {
35399 for(MInt f = 0; f < m_noDirs; f++) {
35400 bndryCell->m_associatedSrfc[f] = -2;
35401 // if a cell with splitChildren has existing surfaces, they will be corrected later
35402 MInt srfcId = m_cellSurfaceMapping[cellId][f];
35403 if(srfcId > -1) {
35404 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
35405 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
35406
35407 if(debugOutput && globalTimeStep == debugTimeStep && domainId() == debugDomainId && srfcId == debugSrfcId) {
35408 cerr << "Accesing Debug-surface! Nghbrs are : " << nghbr0 << " " << nghbr1 << "Due to " << noSplitChildren
35409 << "splitChilds at CutCellId " << cellId << endl;
35410 }
35411
35412 if(nghbr0 == cellId) {
35413 a_surfaceNghbrCellId(srfcId, 0) = -2;
35414 nghbr0 = -2;
35415 } else if(nghbr1 == cellId) {
35416 a_surfaceNghbrCellId(srfcId, 1) = -2;
35417 nghbr1 = -2;
35418 }
35419
35420 // if other neighbor of surface is already non-existent, delete the surface
35421 if(nghbr0 < 0 && nghbr1 < 0) {
35422 a_surfaceArea(srfcId) = F0;
35423 // m_isActiveSurface[ srfcId ] = false;
35424 deleteSurface(srfcId);
35425 }
35426 m_cellSurfaceMapping[cellId][f] = -2;
35427 }
35428 }
35429 }
35430
35431 // e) now going over all Cut-Cells
35432 // - once for regular CutCells : noSplitChildren = 1 and cutCellId = cutc
35433 // - once for each SplitChild for Split-Cells : cutCellId = splitChildIds
35434 for(MInt sc = 0; sc < noSplitChildren; sc++) {
35435 MInt splitChildId = cellId;
35436 MInt scBndryId = bndryId;
35437 FvBndryCell<nDim, SysEqn>* scBndryCell = &m_fvBndryCnd->m_bndryCells->a[scBndryId];
35438 if(splitCellId > -1) {
35439 splitChildId = m_splitChilds[splitCellId][sc];
35440 scBndryId = a_bndryId(splitChildId);
35441 scBndryCell = &m_fvBndryCnd->m_bndryCells->a[scBndryId];
35442 }
35443 ASSERT(scBndryId > -1, " ");
35444
35445 MInt cutCellId = splitCellList[sc];
35446 if(noSplitChildren == 1) ASSERT(cutCellId == (MInt)cutc, "");
35447 ASSERT(cutCellData[cutCellId].cellId == splitChildId, "");
35448
35449
35450 // f) for all SplitChilds which have multiple-faces in any cartesian direction:
35451 for(MInt i = 0; i < m_noDirs; i++) {
35452 if(cutCellData[cutCellId].noFacesPerCartesianDir[i] > 1) {
35453 //--RELOC2--
35454
35455 a_hasProperty(cellId, SolverCell::HasSplitFace) = true;
35456 // prepare cell/surfaces
35457 MInt id = splitFaceCellIds[scBndryId];
35458 if(id < 0) {
35459 id = splitFaceCells.size();
35460 splitFaceCells.push_back(cellWithSplitFace(splitChildId));
35461 splitFaceCellIds[scBndryId] = id;
35462 }
35463 cellWithSplitFace* scsCell = &splitFaceCells[id];
35464 scsCell->splitFaces.push_back(splitCartesianFace(i));
35465
35466 bndryCell->m_associatedSrfc[i] = -2;
35467 // if cell has existing surfaces, they should not point to this cell anymore. Will be corrected later
35468 // if other neighbor of surface is already non-existent, delete the surface
35469 MInt srfcId = m_cellSurfaceMapping[splitChildId][i];
35470 if(srfcId > -1) {
35471 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
35472 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
35473
35474 if(debugOutput && globalTimeStep == debugTimeStep && domainId() == debugDomainId && srfcId == debugSrfcId) {
35475 cerr << "Accesing Debug-surface! Nghbrs are : " << nghbr0 << " " << nghbr1 << "with CutCellId"
35476 << cutCellId << "due to " << cutCellData[cutCellId].noFacesPerCartesianDir[i]
35477 << " faces in direction " << i << endl;
35478 }
35479
35480 if(nghbr0 == splitChildId) {
35481 a_surfaceNghbrCellId(srfcId, 0) = -2;
35482 nghbr0 = -2;
35483 } else if(nghbr1 == splitChildId) {
35484 a_surfaceNghbrCellId(srfcId, 1) = -2;
35485 nghbr1 = -2;
35486 }
35487 if(nghbr0 < 0 && nghbr1 < 0) {
35488 a_surfaceArea(srfcId) = F0;
35489 // m_isActiveSurface[ srfcId ] = false;
35490 deleteSurface(srfcId);
35491 }
35492 m_cellSurfaceMapping[splitChildId][i] = -2;
35493 }
35494 }
35495 }
35496
35497 // g) Remove surfaces which do not have any cartesian or boundary-surfaces and set the Cells
35498 // inactive!
35499 if(cutCellData[cutCellId].noCartesianSurfaces == 0 && cutCellData[cutCellId].noBoundarySurfaces == 0) {
35500 a_hasProperty(splitChildId, SolverCell::IsInactive) = true;
35501 a_hasProperty(splitChildId, SolverCell::IsOnCurrentMGLevel) = false;
35502 removeSurfaces(splitChildId);
35503 }
35504
35505
35506 // h) Remove surfaces of active-Cells where only part of the Cell has non-fluid faces:
35507 for(MInt f = 0; f < m_noDirs; f++) {
35508 if(cutCellData[cutCellId].noFacesPerCartesianDir[f] == 0) { // non fluid face
35509 scBndryCell->m_externalFaces[f] = true;
35510 // cutCellData[cutCellId].externalFaces[f] = true;
35511 if(splitCellId < 0) {
35512 MInt srfcId = m_cellSurfaceMapping[cellId][f];
35513
35514 if(debugOutput && globalTimeStep == debugTimeStep && domainId() == debugDomainId && srfcId == debugSrfcId
35515 && srfcId > -1) {
35516 cerr << "Deleting surface " << srfcId << " on accord of " << cellId << " with zero faces in direction "
35517 << f << " is externalFace instead " << cutCellData[cutCellId].externalFaces[f] << endl;
35518
35519 cerr << "Cell is an original SplitCell: " << splitCellId << " with "
35520 << cutCellData[cutCellId].noSplitChilds << " # of SplitChildren and "
35521 << cutCellData[cutCellId].noCartesianSurfaces << " Totalfaces. " << endl;
35522 }
35523
35524 if(srfcId > -1) {
35525 a_surfaceArea(srfcId) = F0;
35526 deleteSurface(srfcId);
35527 }
35528 bndryCell->m_associatedSrfc[f] = -1;
35529 m_cutFaceArea[bndryId][f] = F0;
35530
35531 MInt nghbrId = c_neighborId(cellId, f);
35532 MInt nghbrBndryId = -1;
35533 if(nghbrId > -1) nghbrBndryId = a_bndryId(nghbrId);
35534 if(nghbrBndryId > -1) {
35535 m_bndryCells->a[nghbrBndryId].m_associatedSrfc[m_revDir[f]] = -1;
35536 m_cutFaceArea[nghbrBndryId][m_revDir[f]] = F0;
35537 }
35538 }
35539 }
35540 }
35541
35542 //--RELOC4--
35543 for(MInt srf = 0; srf < cutCellData[cutCellId].noCartesianSurfaces; srf++) {
35544 MInt dirId = cutCellData[cutCellId].cartFaceDir[srf];
35545 // MInt spaceId = dirId/2;
35546 MInt srfcId = m_cellSurfaceMapping[splitChildId][dirId];
35547 // for regular cells the cellSurfaceMapping should be intakt!
35548
35549 if(cutCellData[cutCellId].noFacesPerCartesianDir[dirId] > 1) {
35550 // for multiple faces in this direction;
35551 MInt sfCellId = splitFaceCellIds[scBndryId];
35552 cellWithSplitFace* sfCell = &splitFaceCells[sfCellId];
35553 // search the right split surface of ssCell:
35554 MInt sf = -1;
35555 for(MInt s = 0; (unsigned)s < sfCell->splitFaces.size(); s++) {
35556 MInt sfDir = sfCell->splitFaces[s].direction;
35557 if(sfDir == dirId) { // found it!
35558 sf = s;
35559 break;
35560 }
35561 }
35562 ASSERT(sf > -1, "");
35563 ASSERT(srfcId < 0, "");
35564 // check if a surface should be generated! Don't create surfaces:
35565 // - between two halo cells
35566 // - if the cell doesn't have a neighbor in that direction (at the last halo-layer!)
35567 MBool createSrfc = true;
35568 if(a_isHalo(cellId)) {
35569 if(a_hasNeighbor(cellId, dirId)) {
35570 if(a_isHalo(c_neighborId(cellId, dirId))) {
35571 createSrfc = false;
35572 }
35573 } else {
35574 createSrfc = false;
35575 }
35576 }
35577 if(createSrfc) {
35578 srfcId = getNewSurfaceId();
35579 createSurfaceSplit(srfcId, cellId, splitChildId, dirId);
35580 sfCell->splitFaces[sf].srfcIds.push_back(srfcId);
35581 m_cellSurfaceMapping[splitChildId][dirId] = -2; // indicate split surface
35582 }
35583 } else if(splitCellId > -1) {
35584 // for a split cell, but no split surface in this direction
35585 ASSERT(srfcId < 0, "");
35586 // check if a surface should be generated! Don't create surfaces:
35587 // - between two halo cells
35588 // - if the cell doesn't have a neighbor in that direction (at the last halo-layer!)
35589 MBool createSrfc = true;
35590 if(a_isHalo(cellId)) {
35591 if(a_hasNeighbor(cellId, dirId)) {
35592 MInt nghbrTmp = c_neighborId(cellId, dirId);
35593 if(a_isHalo(nghbrTmp)) {
35594 createSrfc = false;
35595 }
35596 } else {
35597 createSrfc = false;
35598 }
35599 }
35600 if(createSrfc) {
35601 srfcId = getNewSurfaceId();
35602 createSurfaceSplit(srfcId, cellId, splitChildId, dirId);
35603 m_cellSurfaceMapping[splitChildId][dirId] = srfcId;
35604 }
35605 }
35606
35607 if(srfcId > -1) {
35608 // update surface area and coordinate for regular cells!
35609 for(MInt i = 0; i < nDim; i++) {
35610 a_surfaceCoordinate(srfcId, i) = cutCellData[cutCellId].cartFaceCentroid[srf][i];
35611 }
35612 a_surfaceArea(srfcId) = cutCellData[cutCellId].cartFaceArea[srf];
35613
35614 if(cutCellData[cutCellId].noFacesPerCartesianDir[dirId] == 1) {
35615 // do not set this for split faces
35616 scBndryCell->m_associatedSrfc[dirId] = srfcId;
35617 }
35618 } else { // srfcId < -1
35619 if(a_hasNeighbor(cellId, dirId) > 0 && (!a_isHalo(cellId))) {
35620 ASSERT(a_level(cellId) == a_level(c_neighborId(cellId, dirId)), "");
35621
35622 // at the level jump the cell-surface-mapping may be broken!
35623 // check that the surface from the neighbor child is correct!
35624 if(!c_isLeafCell(c_neighborId(cellId, dirId))) {
35625 const MInt nghbrId = c_neighborId(cellId, dirId);
35626 ASSERT(c_noChildren(nghbrId) > 0, "");
35627 MBool foundNgbrSrfc = false;
35628 for(MInt child = 0; child < m_noCellNodes; child++) {
35629 if(!childCode[dirId][child]) continue;
35630 const MInt childId = c_childId(nghbrId, child);
35631 if(childId < 0) continue;
35632 if(a_hasProperty(childId, SolverCell::IsInactive)) continue;
35633 if(a_hasProperty(childId, SolverCell::IsNotGradient)) continue;
35634 if(a_isHalo(cellId) && a_isHalo(childId)) continue;
35635 srfcId = m_cellSurfaceMapping[childId][m_revDir[dirId]];
35636 if(srfcId < 0) {
35637 if(cutCellIdMapping[childId] > 0
35638 && cutCellData[cutCellIdMapping[childId]].noFacesPerCartesianDir[m_revDir[dirId]] > 0) {
35639 // meaning that the neighbor child has a cartesian-surface,
35640 // the cellSurfaceMapping has just not been updated yet!
35641 foundNgbrSrfc = true;
35642 break;
35643 } else {
35644 // meaning that the neighbor child does not have a cartesian face in the
35645 // matching direction and a broken cellSurfaceMapping!
35646 // cerr << "Incorrect surface at level-jump" << c_globalId(cellId) << " " << c_globalId(childId)
35647 // << " dir " << dirId << " lvls " << a_level(cellId) << " " << a_level(childId) << " ngb "
35648 // << c_globalId(nghbrId) << endl;
35649 // cerr << cutCellData[cutCellId].noFacesPerCartesianDir[dirId] << " "
35650 // << cutCellData[cutCellIdMapping[childId]].noFacesPerCartesianDir[m_revDir[dirId]] << endl;
35651 }
35652 } else {
35653 foundNgbrSrfc = true;
35654 break;
35655 }
35656 }
35657 if(foundNgbrSrfc) continue;
35658 }
35659
35660 if(cutCellData[cutCellId].cartFaceArea[srf] < m_eps * 10 && !cutCellData[cutCellId].externalFaces[dirId]) {
35661 cerr << " TS " << globalTimeStep << " d " << domainId() << " c " << cellId
35662 << " has small surface inconsistency which is ignored!" << endl;
35663 // removing cartisan surface from cell:
35664 continue;
35665 }
35666
35667 if(splitCellId <= -1 && cutCellData[cutCellId].noFacesPerCartesianDir[dirId] == 1) {
35668 cerr << "ERROR, Found a Cell which is not a splitCell, has one faces in the current direction, yet the "
35669 "Cell-Surface-Mapping is broken!"
35670 << endl;
35671 }
35672 cerr << "Debug-Setting: " << endl;
35673 cerr << "- debugTimeStep = " << globalTimeStep << endl;
35674 cerr << "- debugDomainId = " << domainId() << endl;
35675 cerr << "- debugCellId = " << cellId << endl;
35676 cerr << "- debugNeighborId = " << c_neighborId(cellId, dirId) << endl;
35677 cerr << "- debugDir = " << dirId << endl;
35678
35679 cerr << "Surf-Area is " << cutCellData[cutCellId].cartFaceArea[srf] << endl;
35680
35681 cerr << " domain " << domainId() << " cellId " << cellId << " (" << c_globalId(cellId) << ") CutCellId "
35682 << cutCellId << " splitchildId " << splitChildId << " has no surface in dir " << dirId << endl;
35683
35684 cerr << "However the cell has " << cutCellData[cutCellId].noFacesPerCartesianDir[dirId]
35685 << " Faces in the current direction! "
35686 << " And other Faces: " << cutCellData[cutCellId].noFacesPerCartesianDir[0] << " "
35687 << cutCellData[cutCellId].noFacesPerCartesianDir[1] << cutCellData[cutCellId].noFacesPerCartesianDir[2]
35688 << " " << cutCellData[cutCellId].noFacesPerCartesianDir[3] << " "
35689 << cutCellData[cutCellId].noFacesPerCartesianDir[4] << " "
35690 << cutCellData[cutCellId].noFacesPerCartesianDir[5] << " " << endl;
35691
35692 cerr << "Instead the cell has an external-Face (Solid) in the direction: "
35693 << cutCellData[cutCellId].externalFaces[dirId] << endl;
35694
35695 cerr << "Cell is an original SplitCell: " << splitCellId << " with " << cutCellData[cutCellId].noSplitChilds
35696 << " # of SplitChildren and " << cutCellData[cutCellId].noCartesianSurfaces << " Totalfaces. " << endl;
35697
35698 cerr << "The corner-ls-values of the considered Cell-Face are: " << endl;
35699 for(MInt corner = 0; corner < 4; corner++) {
35700 cerr << " " << setprecision(16)
35701 << m_candidateNodeValues[IDX_LSSETNODES(m_bndryCandidateIds[cellId], faceCornerCode[dirId][corner],
35702 0)];
35703 }
35704 cerr << endl;
35705
35706 cerr << " Current Mapping is " << m_cellSurfaceMapping[splitChildId][dirId] << endl;
35707
35708 cerr << " Nghbr-Id is: " << c_neighborId(cellId, dirId) << " (" << c_globalId(c_neighborId(cellId, dirId))
35709 << "( nghbr is inactive: " << a_hasProperty(c_neighborId(cellId, dirId), SolverCell::IsInactive)
35710 << endl;
35711
35712 cerr << " Cell is " << a_hasProperty(cellId, SolverCell::IsGapCell) << " GapCell and the neighbor is "
35713 << a_hasProperty(c_neighborId(cellId, dirId), SolverCell::IsGapCell) << " Gap-Cell." << endl;
35714 cerr << "Complete corner ls-values: " << endl;
35715 for(MInt corner = 0; corner < 8; corner++) {
35716 cerr << " " << setprecision(16)
35717 << m_candidateNodeValues[IDX_LSSETNODES(m_bndryCandidateIds[cellId], corner, 0)];
35718 }
35719 cerr << endl;
35720
35721 // this should not happen!
35722 // the surface should either: have already been delete or
35723 // the mapping should not have been destroyed!
35724 mTerm(1, AT_, "This was not supposed to happen - where is my surface?!?");
35725 // continue;
35726 } else
35727 continue;
35728 }
35729
35730 m_cutFaceArea[a_bndryId(splitChildId)][dirId] = cutCellData[cutCellId].cartFaceArea[srf];
35731
35732 MInt nghbrId = a_surfaceNghbrCellId(srfcId, dirId % 2);
35733 MInt nghbrBndryId = -1;
35734 if(splitCellId < 0 && cutCellData[cutCellId].noFacesPerCartesianDir[dirId] == 1) {
35735 if(nghbrId > -1) nghbrBndryId = a_bndryId(nghbrId);
35736
35737 if(nghbrBndryId > -1) {
35738 m_bndryCells->a[nghbrBndryId].m_associatedSrfc[m_revDir[dirId]] = srfcId;
35739 }
35740 } else {
35741 nghbrId = c_neighborId(cellId, dirId);
35742 if(nghbrId > -1) nghbrBndryId = a_bndryId(nghbrId);
35743 }
35744 }
35745
35746
35747 //--RELOC6--
35748 // remove face stream and use below data directly!
35749 MBool needFaceStream = false;
35750 if(a_hasProperty(splitChildId, SolverCell::HasSplitFace) || cutCellData[cutCellId].noBoundarySurfaces > 1
35751 || cutCellData[cutCellId].noAdditionalVertices > 0)
35752 needFaceStream = true;
35753
35754 needFaceStream = true;
35755
35756 // if ( m_fvBndryCnd->m_bndryCell[ scBndryId ].m_faceStream.size() > 0 ) { //needFaceStream
35757 if(needFaceStream) {
35758 m_fvBndryCnd->m_bndryCell[scBndryId].m_faceVertices.clear();
35759 m_fvBndryCnd->m_bndryCell[scBndryId].m_faceStream.resize(cutCellData[cutCellId].noTotalFaces);
35760 MInt vertexMap[maxNoVertices];
35761 fill_n(vertexMap, maxNoVertices, -1);
35762 MInt fcnt = 0;
35763 for(MInt faceType = 1; faceType >= 0; faceType--) { // body faces first
35764 for(MInt f = 0; f < cutCellData[cutCellId].noTotalFaces; f++) {
35765 if((faceType == 0) && (cutCellData[cutCellId].allFacesBodyId[f] > -1)) continue;
35766 if((faceType == 1) && (cutCellData[cutCellId].allFacesBodyId[f] < 0)) continue;
35767 m_fvBndryCnd->m_bndryCell[scBndryId].m_faceStream[fcnt].resize(0);
35768 for(MInt p = 0; p < cutCellData[cutCellId].allFacesNoPoints[f]; p++) {
35769 MInt pointId = cutCellData[cutCellId].allFacesPointIds[f][p];
35770 ASSERT(pointId > -1 && pointId < maxNoVertices, "");
35771 if(vertexMap[pointId] < 0) {
35772 vertexMap[pointId] = (signed)m_fvBndryCnd->m_bndryCell[scBndryId].m_faceVertices.size() / nDim;
35773 if(pointId < CC::noCorners) {
35774 for(MInt i = 0; i < nDim; i++) {
35775 m_fvBndryCnd->m_bndryCell[scBndryId].m_faceVertices.push_back(
35776 a_coordinate(cellId, i) + signStencil[pointId][i] * cellHalfLength);
35777 }
35778 } else if(pointId < CC::noCorners + CC::maxNoCutPoints) {
35779 MInt cpId = pointId - CC::noCorners;
35780 for(MInt i = 0; i < nDim; i++) {
35781 m_fvBndryCnd->m_bndryCell[scBndryId].m_faceVertices.push_back(cutCellData[cutc].cutPoints[cpId][i]);
35782 }
35783 } else {
35784 MInt aId = pointId - CC::noCorners - CC::maxNoCutPoints;
35785 ASSERT(aId < cutCellData[cutCellId].noAdditionalVertices, "");
35786 for(MInt i = 0; i < nDim; i++) {
35787 m_fvBndryCnd->m_bndryCell[scBndryId].m_faceVertices.push_back(
35788 cutCellData[cutCellId].additionalVertices[aId][i]);
35789 }
35790 }
35791 }
35792 ASSERT(fcnt < cutCellData[cutCellId].noTotalFaces, "");
35793 m_fvBndryCnd->m_bndryCell[scBndryId].m_faceStream[fcnt].push_back(vertexMap[pointId]);
35794 }
35795 fcnt++;
35796 }
35797 }
35798 }
35799
35800 } // end noCartesianSurfaces-loop
35801
35802 //--REV_RELOC--
35803 // set external faces of split parent cell
35804 if(splitCellId > -1) {
35805 for(MInt dir = 0; dir < m_noDirs; dir++) {
35806 // if( noFacesPerCartesianFaceAll[ dir ] == 0 ){
35807 if(cutCellData[cutc].noFacesPerCartesianDir[dir] == 0) {
35808 bndryCell->m_externalFaces[dir] = true;
35809 // cutCellData[cutc].externalFaces[dir] = true;
35810 MInt srfcId = cellSurfaceMapping_backup[dir];
35811 if(srfcId > -1) {
35812 a_surfaceArea(srfcId) = F0;
35813 deleteSurface(srfcId);
35814 }
35815 }
35816 }
35817 bndryCell->m_srfcs[0]->m_noCutPoints = 0;
35818 }
35819 }
35820
35821 RECORD_TIMER_STOP(tCutFace_8);
35822 RECORD_TIMER_START(tCutFace_9);
35823
35824 // Finalize: Adjust connectivity of split cells and split faces and their neighbors!
35825 // first a small check - all surfaces attached to a split cell should point to -1 or -2
35826 // all surfaces attachted to a split Cartesian surface should also point to -1 or -2,
35827 // anything else is wrong!
35828 MInt noSplitCells = m_splitCells.size();
35829 for(MInt sc = 0; sc < noSplitCells; sc++) {
35830 MInt scId = m_splitCells[sc];
35831 MInt scBndryId = a_bndryId(scId);
35832 for(MInt d = 0; d < m_noDirs; d++) {
35833 if(m_cellSurfaceMapping[scId][d] > -1) mTerm(1, AT_, "splitParent cell has a valid surface attached to it...");
35834 if(m_fvBndryCnd->m_bndryCells->a[scBndryId].m_associatedSrfc[d] > -1)
35835 mTerm(1, AT_, "splitParent cell has a valid surface attached to its boundary cell...");
35836 }
35837 // now check split children
35838 for(MInt ssc = 0; (unsigned)ssc < m_splitChilds[sc].size(); ssc++) {
35839 MInt splitChildId = m_splitChilds[sc][ssc];
35840 MInt splitChildBndryId = a_bndryId(splitChildId);
35841 for(MInt d = 0; d < m_noDirs; d++) {
35842 MInt srfcId = m_cellSurfaceMapping[splitChildId][d];
35843 if(srfcId > -1) {
35844 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
35845 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
35846 if(m_fvBndryCnd->m_bndryCells->a[splitChildBndryId].m_associatedSrfc[d] != srfcId)
35847 mTerm(1, AT_, "splitChild cell no consistent surface information...");
35848 if(nghbr0 == splitChildId) {
35849 if(nghbr1 > -1) mTerm(1, AT_, "splitChild cell has a surface with a valid neighbor attached to it...");
35850 } else if(nghbr1 == splitChildId) {
35851 if(nghbr0 > -1) mTerm(1, AT_, "splitChild cell has a surface with a valid neighbor attached to it...");
35852 } else
35853 mTerm(1, AT_, "splitChild cell has a surface attached to it which does not point to the cell itself...");
35854 } else { // this side should be either a non-fluid side or a split face! do not check now, let's check....
35855 MBool suspicious = true;
35856 if(m_fvBndryCnd->m_bndryCells->a[splitChildBndryId].m_externalFaces[d]) {
35857 suspicious = false;
35858 break;
35859 }
35860 if(a_isHalo(splitChildId)) {
35861 suspicious = false;
35862 break;
35863 }
35864 // if still suspicious, check split face state...
35865 if(!suspicious) continue;
35866 MInt sfId = splitFaceCellIds[splitChildBndryId];
35867 if(sfId > -1) {
35868 cellWithSplitFace* sfCell = &splitFaceCells[sfId];
35869 for(MInt sff = 0; (unsigned)sff < sfCell->splitFaces.size(); sff++) {
35870 splitCartesianFace* splitFace = &sfCell->splitFaces[sff];
35871 MInt dir = splitFace->direction;
35872 if(dir == d) {
35873 suspicious = false;
35874 break;
35875 }
35876 }
35877 }
35878 if(suspicious)
35879 mTerm(1, AT_,
35880 "split cell child has a fluid side which is not split but has no valid surface attached to it!");
35881 }
35882 }
35883 }
35884 }
35885
35886 // check that the split face has no surface attached to it and
35887 // is not otherwise connected to any other cell!
35888 MInt noSplitFaceCells = splitFaceCells.size();
35889 for(MInt sf = 0; sf < noSplitFaceCells; sf++) {
35890 cellWithSplitFace* sfCell = &splitFaceCells[sf];
35891 MInt sfId = sfCell->cellId;
35892 MInt sfBndryId = a_bndryId(sfId);
35893 MInt noSplitFaces = sfCell->splitFaces.size();
35894 for(MInt sff = 0; sff < noSplitFaces; sff++) {
35895 splitCartesianFace* splitFace = &sfCell->splitFaces[sff];
35896 MInt dir = splitFace->direction;
35897 MInt srfcId = m_cellSurfaceMapping[sfId][dir];
35898 if(srfcId > -1) mTerm(1, AT_, "split face has a valid surface attached to it...");
35899 if(m_fvBndryCnd->m_bndryCells->a[sfBndryId].m_associatedSrfc[dir] > -1)
35900 mTerm(1, AT_, "split face has a valid surface attached to its boundary cell...");
35901 for(MInt srfc = 0; (unsigned)srfc < splitFace->srfcIds.size(); srfc++) {
35902 srfcId = splitFace->srfcIds[srfc];
35903 if(srfcId < 0) mTerm(1, AT_, "split face part has no surface attached to it...");
35904 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
35905 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
35906 if(nghbr0 == sfId) {
35907 if(nghbr1 > -1) mTerm(1, AT_, "splitface has a surface with a valid neighbor attached to it...");
35908 } else if(nghbr1 == sfId) {
35909 if(nghbr0 > -1) mTerm(1, AT_, "splitface has a surface with a valid neighbor attached to it...");
35910 } else
35911 mTerm(1, AT_, "splitface has a surface attached to it which does not point to the cell itself...");
35912 }
35913 }
35914 }
35915
35916 // connect all split faces to other split faces or split cells...
35917 for(MInt sf = 0; sf < noSplitFaceCells; sf++) {
35918 cellWithSplitFace* sfCell = &splitFaceCells[sf];
35919 const MInt sfId = sfCell->cellId;
35920 const MBool cellIsSplitChild = a_hasProperty(sfId, SolverCell::IsSplitChild);
35921 const MInt noSplitFaces = sfCell->splitFaces.size();
35922
35923 const MFloat maxXdiff = 1e-4 * c_cellLengthAtLevel(a_cutCellLevel(sfId));
35924 const MFloat maxAdiff =
35926
35927 for(MInt sff = 0; sff < noSplitFaces; sff++) {
35928 splitCartesianFace* splitFace = &sfCell->splitFaces[sff];
35929 MInt dir = splitFace->direction;
35930 for(MInt srfc = 0; (unsigned)srfc < splitFace->srfcIds.size(); srfc++) {
35931 MInt srfcId = splitFace->srfcIds[srfc];
35932 ASSERT(srfcId > -1, "");
35933 MInt srfcNeighbor = a_surfaceNghbrCellId(srfcId, dir % 2);
35934 if(srfcNeighbor > -1) // surface has already been corrected, continue...
35935 continue;
35936 // otherwise, we have to find the correct neigbor... first, find the Cartesian neighbor
35937 MInt nghbrId = -1;
35938 if(cellIsSplitChild) {
35939 MInt splitParent = getAssociatedInternalCell(sfId);
35940 nghbrId = c_neighborId(splitParent, dir);
35941 } else {
35942 nghbrId = c_neighborId(sfId, dir);
35943 }
35944 ASSERT(nghbrId > -1, "");
35945 ASSERT(a_bndryId(nghbrId) > -1, "");
35946 // cartesian neighbor must be split cell, have split surfaces, or both
35947 // so run over all split childs and check their (split) surfaces
35948 MInt splitChildIdN = nghbrId;
35949 MInt noSubCellsN = 1;
35950 MInt splitCellIdN = -1;
35951 if(a_hasProperty(nghbrId, SolverCell::IsSplitCell)) {
35952 splitCellIdN = splitCellIds[a_bndryId(nghbrId)];
35953 noSubCellsN = m_splitChilds[splitCellIdN].size();
35954 }
35955 MFloat minXDiff = std::numeric_limits<float>::max();
35956 MInt bestFitSrfc = -1;
35957 MInt bestFitCell = -1;
35958 MInt* bestFitSplitFacePart = (MInt*)nullptr;
35959
35960 for(MInt count = 0; count < noSubCellsN; count++) {
35961 if(splitCellIdN > -1) {
35962 splitChildIdN = m_splitChilds[splitCellIdN][count];
35963 }
35964
35965 MInt srfcIdNghbr = m_cellSurfaceMapping[splitChildIdN][m_revDir[dir]];
35966 if(srfcIdNghbr > -1) { // neighbor has no split surface in this direction...
35967 MFloat xDiff = checkCentroidDiff(srfcId, srfcIdNghbr);
35968 if(xDiff < minXDiff) {
35969 minXDiff = xDiff;
35970 bestFitSrfc = srfcIdNghbr;
35971 bestFitCell = splitChildIdN;
35972 bestFitSplitFacePart = (MInt*)nullptr;
35973 }
35974 } else {
35975 MInt splitFaceCellNghbrId = splitFaceCellIds[a_bndryId(splitChildIdN)];
35976 if(splitFaceCellNghbrId < 0) continue;
35977 for(MInt sfn = 0; (unsigned)sfn < splitFaceCells[splitFaceCellNghbrId].splitFaces.size(); sfn++) {
35978 if(m_revDir[dir] == splitFaceCells[splitFaceCellNghbrId].splitFaces[sfn].direction) {
35979 for(MInt s = 0; (unsigned)s < splitFaceCells[splitFaceCellNghbrId].splitFaces[sfn].srfcIds.size();
35980 s++) {
35981 srfcIdNghbr = splitFaceCells[splitFaceCellNghbrId].splitFaces[sfn].srfcIds[s];
35982 ASSERT(srfcIdNghbr > -1, "");
35983 MFloat xDiff = checkCentroidDiff(srfcId, srfcIdNghbr);
35984 if(xDiff < minXDiff) {
35985 minXDiff = xDiff;
35986 bestFitSrfc = srfcIdNghbr;
35987 bestFitCell = splitChildIdN;
35988 bestFitSplitFacePart = &splitFaceCells[splitFaceCellNghbrId].splitFaces[sfn].srfcIds[s];
35989 }
35990 }
35991 }
35992 }
35993 }
35994 }
35995
35996 // ensure that we found at least one matching surface and set everything else accordingly...
35997 if(bestFitSrfc < 0) mTerm(1, AT_, "did not find a matching surface at all...");
35998 MFloat aDiff = checkAreaDiff(srfcId, bestFitSrfc);
35999 if(minXDiff > maxXdiff || aDiff > maxAdiff) {
36000 cerr << " [" << domainId() << "] - split surface connection - "
36001 << " sfId: " << sfId << " nghbr: " << nghbrId
36002 << " aDiff: " << aDiff / POW2(c_cellLengthAtLevel(a_cutCellLevel(sfId)))
36003 << " minXDiff: " << minXDiff / c_cellLengthAtLevel(a_cutCellLevel(sfId)) << " " << a_isHalo(sfId) << " "
36004 << noSplitFaceCells << " " << noSubCellsN << endl;
36005 cerr << sfId << " -> " << a_surfaceArea(srfcId) << " / "
36006 << " / " << a_surfaceCoordinate(srfcId, 0) - a_coordinate(sfId, 0) << " "
36007 << a_surfaceCoordinate(srfcId, 1) - a_coordinate(sfId, 1) << " "
36008 << a_surfaceCoordinate(srfcId, 2) - a_coordinate(sfId, 2) << " / " << a_coordinate(sfId, 0) << " "
36009 << a_coordinate(sfId, 1) << " " << a_coordinate(sfId, 2) << endl;
36010 cerr << sfId << " => " << a_surfaceArea(bestFitSrfc) << " / " << a_associatedBodyIds(bestFitCell, 0) << " / "
36011 << a_surfaceCoordinate(bestFitSrfc, 0) - a_coordinate(sfId, 0) << " "
36012 << a_surfaceCoordinate(bestFitSrfc, 1) - a_coordinate(sfId, 1) << " "
36013 << a_surfaceCoordinate(bestFitSrfc, 2) - a_coordinate(sfId, 2) << " / " << a_coordinate(bestFitCell, 0)
36014 << " " << a_coordinate(bestFitCell, 1) << " " << a_coordinate(bestFitCell, 2) << endl;
36015 mTerm(1, AT_, "split cell connection failed");
36016 }
36017
36018 // ok, can connect surface and delete nghbrSrfc
36019 a_surfaceNghbrCellId(srfcId, dir % 2) = bestFitCell;
36020 a_surfaceNghbrCellId(bestFitSrfc, dir % 2) = -1;
36021 a_surfaceArea(bestFitSrfc) = F0;
36022 // m_isActiveSurface[ bestFitSrfc ] = false;
36023 deleteSurface(bestFitSrfc);
36024 if(bestFitSplitFacePart == (MInt*)nullptr) {
36025 m_cellSurfaceMapping[bestFitCell][m_revDir[dir]] = srfcId;
36026 ASSERT(a_bndryId(bestFitCell) > -1, " ");
36027 m_fvBndryCnd->m_bndryCells->a[a_bndryId(bestFitCell)].m_associatedSrfc[m_revDir[dir]] = srfcId;
36028 } else {
36029 *bestFitSplitFacePart = srfcId;
36030 }
36031 }
36032 }
36033 }
36034
36035 // now run over all split cells and try to connect them to neighboring cells if they do not have a split face in the
36036 // respective direction! all split faces have already been connected, thus only split cell/split cell and split cell/
36037 // regular cell connections have to be established!
36038 for(MInt sc = 0; sc < noSplitCells; sc++) {
36039 const MInt scId = m_splitCells[sc];
36040
36041 const MFloat maxXdiff = 1e-4 * c_cellLengthAtLevel(a_cutCellLevel(scId));
36042 const MFloat maxAdiff =
36044
36045 for(MInt ssc = 0; (unsigned)ssc < m_splitChilds[sc].size(); ssc++) {
36046 MInt splitChildId = m_splitChilds[sc][ssc];
36047 for(MInt dir = 0; dir < m_noDirs; dir++) {
36048 MInt srfcId = m_cellSurfaceMapping[splitChildId][dir];
36049 if(srfcId > -1) {
36050 MInt srfcNeighbor = a_surfaceNghbrCellId(srfcId, dir % 2);
36051 if(srfcNeighbor > -1) // surface has already been corrected, continue...
36052 continue;
36053
36054 MInt nghbrId = c_neighborId(scId, dir);
36055 if(nghbrId < 0) mTerm(1, AT_, "split cell has no valid neighbor in direction of cut surface...");
36056 // two possibilities - nghbrId can be normal cell (easy), or split cell (a bit more difficult)
36057 // find the correct connectivity to the neighbor, set cellsurfacemapping and associatedsrfc, and delete other
36058 // surface...
36059 MInt splitChildIdN = nghbrId;
36060 MInt noSubCellsN = 1;
36061 MInt splitCellIdN = -1;
36062 if(a_hasProperty(nghbrId, SolverCell::IsSplitCell)) {
36063 splitCellIdN = splitCellIds[a_bndryId(nghbrId)];
36064 noSubCellsN = m_splitChilds[splitCellIdN].size();
36065 }
36066 MFloat minXDiff = std::numeric_limits<float>::max();
36067 MInt bestFitSrfc = -1;
36068 MInt bestFitCell = -1;
36069
36070 for(MInt count = 0; count < noSubCellsN; count++) {
36071 if(splitCellIdN > -1) {
36072 splitChildIdN = m_splitChilds[splitCellIdN][count];
36073 }
36074 MInt srfcIdNghbr = m_cellSurfaceMapping[splitChildIdN][m_revDir[dir]];
36075 if(srfcIdNghbr > -1) { // neighbor has a valid surface in this direction (no non-fluid side)
36076 MFloat xDiff = checkCentroidDiff(srfcId, srfcIdNghbr);
36077 if(xDiff < minXDiff) {
36078 minXDiff = xDiff;
36079 bestFitSrfc = srfcIdNghbr;
36080 bestFitCell = splitChildIdN;
36081 }
36082 }
36083 }
36084
36085 // ensure that we found at least one matching surface and set everything else accordingly...
36086 if(bestFitSrfc < 0) mTerm(1, AT_, "did not find a matching surface at all...");
36087 MFloat aDiff = checkAreaDiff(srfcId, bestFitSrfc);
36088 if(minXDiff > maxXdiff || aDiff > maxAdiff) {
36089 cerr << domainId() << ": split " << splitChildId << " " << splitCellIdN << " " << splitChildIdN << " "
36090 << nghbrId << " " << dir << " " << m_cellSurfaceMapping[splitChildId][dir] << " "
36091 << m_cellSurfaceMapping[splitChildIdN][m_revDir[dir]] << " " << srfcNeighbor << endl;
36092 cerr << " [" << domainId() << "] - split cell connection - "
36093 << " splitChildId: " << splitChildId << " nghbr: " << splitChildIdN << " aDiff: " << aDiff << " ("
36094 << maxAdiff << ") minXDiff: " << minXDiff << " (" << maxXdiff << ")" << endl;
36095 cerr << a_coordinate(scId, 0) << " " << a_coordinate(scId, 1) << " " << a_coordinate(scId, 2) << " "
36096 << endl;
36097 cerr << a_level(scId) << " " << a_isHalo(scId) << " " << endl;
36098 mTerm(1, AT_, "split cell connection failed (2)");
36099 }
36100
36101 // ok, can connect surface and delete nghbrSrfc
36102 a_surfaceNghbrCellId(srfcId, dir % 2) = bestFitCell;
36103 a_surfaceNghbrCellId(bestFitSrfc, dir % 2) = -1;
36104 a_surfaceArea(bestFitSrfc) = F0;
36105 // m_isActiveSurface[ bestFitSrfc ] = false;
36106 deleteSurface(bestFitSrfc);
36107 m_cellSurfaceMapping[bestFitCell][m_revDir[dir]] = srfcId;
36108 if(a_bndryId(bestFitCell) > -1) {
36109 m_fvBndryCnd->m_bndryCells->a[a_bndryId(bestFitCell)].m_associatedSrfc[m_revDir[dir]] = srfcId;
36110 }
36111 }
36112 }
36113 }
36114 }
36115
36116 // Final check - all surfaces attached to a split cell or to a split surface should have two valid neighbors
36117 for(MInt sc = 0; sc < noSplitCells; sc++) {
36118 MInt scId = m_splitCells[sc];
36119 MInt scBndryId = a_bndryId(scId);
36120 for(MInt d = 0; d < m_noDirs; d++) {
36121 if(m_cellSurfaceMapping[scId][d] > -1)
36122 mTerm(1, AT_, "splitParent cell has a valid surface attached to it after split connection...");
36123 if(m_fvBndryCnd->m_bndryCells->a[scBndryId].m_associatedSrfc[d] > -1)
36124 mTerm(1, AT_, "splitParent cell has a valid surface attached to its boundary cell after split connection...");
36125 }
36126 // now check split children
36127 for(MInt ssc = 0; (unsigned)ssc < m_splitChilds[sc].size(); ssc++) {
36128 MInt splitChildId = m_splitChilds[sc][ssc];
36129 MInt splitChildBndryId = a_bndryId(splitChildId);
36130 for(MInt d = 0; d < m_noDirs; d++) {
36131 MInt srfcId = m_cellSurfaceMapping[splitChildId][d];
36132 if(srfcId > -1) {
36133 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
36134 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
36135 if(m_fvBndryCnd->m_bndryCells->a[splitChildBndryId].m_associatedSrfc[d] != srfcId)
36136 mTerm(1, AT_, "splitChild cell no consistent surface information...");
36137 if(nghbr0 == splitChildId) {
36138 if(nghbr1 < 0)
36139 mTerm(1, AT_,
36140 "splitChild cell has a surface with no valid neighbor attached to it after split connection...");
36141 } else if(nghbr1 == splitChildId) {
36142 if(nghbr0 < 0)
36143 mTerm(1, AT_,
36144 "splitChild cell has a surface with no valid neighbor attached to it after split connection...");
36145 } else
36146 mTerm(1, AT_,
36147 "splitChild cell has a surface attached to it which does not point to the cell itself after split "
36148 "connection...");
36149 } else { // this side should be either a non-fluid side or a split face! do not check now, let's check....
36150 MBool suspicious = true;
36151 if(m_fvBndryCnd->m_bndryCells->a[splitChildBndryId].m_externalFaces[d] || a_isHalo(scId)) {
36152 suspicious = false;
36153 break;
36154 }
36155 // if still suspicious, check split face state...
36156 if(!suspicious) continue;
36157 MInt sfId = splitFaceCellIds[splitChildBndryId];
36158 if(sfId > -1) {
36159 cellWithSplitFace* sfCell = &splitFaceCells[sfId];
36160 for(MInt sff = 0; (unsigned)sff < sfCell->splitFaces.size(); sff++) {
36161 splitCartesianFace* splitFace = &sfCell->splitFaces[sff];
36162 MInt dir = splitFace->direction;
36163 if(dir == d) {
36164 suspicious = false;
36165 break;
36166 }
36167 }
36168 }
36169 if(suspicious)
36170 mTerm(1, AT_,
36171 "split cell child has a fluid side which is not split but has no valid surface attached to it "
36172 "after split connection!");
36173 }
36174 }
36175 }
36176 }
36177 for(MInt sf = 0; sf < noSplitFaceCells; sf++) {
36178 cellWithSplitFace* sfCell = &splitFaceCells[sf];
36179 MInt sfId = sfCell->cellId;
36180 MInt sfBndryId = a_bndryId(sfId);
36181 MInt noSplitFaces = sfCell->splitFaces.size();
36182 for(MInt sff = 0; sff < noSplitFaces; sff++) {
36183 splitCartesianFace* splitFace = &sfCell->splitFaces[sff];
36184 MInt dir = splitFace->direction;
36185 MInt srfcId = m_cellSurfaceMapping[sfId][dir];
36186 if(srfcId > -1) mTerm(1, AT_, "split face has a valid surface attached to it after split connection...");
36187 if(m_fvBndryCnd->m_bndryCells->a[sfBndryId].m_associatedSrfc[dir] > -1)
36188 mTerm(1, AT_, "split face has a valid surface attached to its boundary cell after split connection...");
36189 for(MInt srfc = 0; (unsigned)srfc < splitFace->srfcIds.size(); srfc++) {
36190 srfcId = splitFace->srfcIds[srfc];
36191 if(srfcId < 0) mTerm(1, AT_, "split face part has no surface attached to it after split connection...");
36192 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
36193 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
36194 if(nghbr0 == sfId) {
36195 if(nghbr1 < 0)
36196 mTerm(1, AT_, "splitface has a surface with no valid neighbor attached to it after split connection...");
36197 } else if(nghbr1 == sfId) {
36198 if(nghbr0 < 0)
36199 mTerm(1, AT_, "splitface has a surface with a valid neighbor attached to it after split connection...");
36200 } else
36201 mTerm(1, AT_,
36202 "splitface has a surface attached to it which does not point to the cell itself after split "
36203 "connection...");
36204 }
36205 }
36206 }
36207
36208 RECORD_TIMER_STOP(tCutFace_9);
36209 RECORD_TIMER_START(tCutFace_10);
36210
36212
36213 // repeat final check: run over all surfaces and check if they have two valid neighbors if they are active!
36214 for(MInt srfcId = 0; srfcId < a_noSurfaces(); srfcId++) {
36215 MInt nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
36216 MInt nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
36217 if((nghbr0 < 0 || nghbr1 < 0)) { //&& m_isActiveSurface[srfcId] )
36218 cerr << nghbr0 << " " << nghbr1 << " " << m_freeSurfaceIndices.count(srfcId) << endl;
36219 mTerm(1, "active surface has not two neighbors 4...", AT_);
36220 }
36221 }
36222
36223 for(MInt bndryId = m_noOuterBndryCells; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
36224 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
36225 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
36226 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
36227 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_bndryCndId < 0) {
36228 mTerm(1, AT_,
36229 "error in createCutFaceMb_MGC(): m_bndryCndId not set: " + to_string(cellId) + " " + to_string(bndryId)
36230 + " " + to_string(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId) + "/"
36231 + to_string(m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs) + " "
36232 + to_string(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area));
36233 }
36234 }
36235 }
36236
36238
36239 RECORD_TIMER_STOP(tCutFace_10);
36240}
36241
36242
36247template <MInt nDim, class SysEqn>
36249 TRACE();
36250
36251 MFloat recCoord[3];
36252 if(mode == 0) {
36253 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36254 for(MUint j = 0; j < m_azimuthalMaxLevelWindowCells[i].size(); j++) {
36255 MInt offset = m_azimuthalMaxLevelWindowMap[i][j];
36256 MInt cellId = m_azimuthalMaxLevelWindowCells[i][j];
36257 if(m_azimuthalWasNearBndryIds[offset] <= -1) {
36258 continue;
36259 }
36260 for(MInt d = 0; d < nDim; d++) {
36261 recCoord[d] = m_azimuthalCutRecCoord[offset * nDim + d];
36262 }
36263 rebuildAzimuthalReconstructionConstants(cellId, offset, recCoord, mode);
36264 }
36265 }
36266 } else if(mode == 1) {
36267 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36268 for(MUint j = 0; j < m_azimuthalMaxLevelWindowCells[i].size(); j++) {
36269 MInt offset = m_azimuthalMaxLevelWindowMap[i][j];
36270 MInt cellId = m_azimuthalMaxLevelWindowCells[i][j];
36271 if(m_azimuthalWasNearBndryIds[offset] > -1) {
36272 for(MInt d = 0; d < nDim; d++) {
36273 recCoord[d] = m_azimuthalCutRecCoord[offset * nDim + d];
36274 }
36275 rebuildAzimuthalReconstructionConstants(cellId, offset, recCoord, mode);
36276 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
36277 MBool rebuild = false;
36278 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36280 if(a_bndryId(recId) > -1) {
36281 rebuild = true;
36282 break;
36283 }
36284 }
36285 if(!rebuild) {
36286 // If stencil does not contain bndry cells, reconstruction constants do not have to be recomputed
36287 m_azimuthalWasNearBndryIds[offset] = -1;
36288 }
36289 }
36290 }
36291 }
36292 }
36293}
36294
36299template <MInt nDim, class SysEqn>
36301 TRACE();
36302
36303 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36304 for(MUint j = 0; j < m_azimuthalMaxLevelWindowCells[i].size(); j++) {
36305 MInt cellId = m_azimuthalMaxLevelWindowCells[i][j];
36306 MInt offset = m_azimuthalMaxLevelWindowMap[i][j];
36307 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
36308 MBool rebuild = false;
36309 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36311 if(a_bndryId(recId) > -1) {
36312 rebuild = true;
36313 break;
36314 }
36315 }
36316 if(a_levelSetValuesMb(cellId, 0) <= F0 && m_azimuthalHaloActive[offset]) {
36317 rebuild = true;
36318 }
36319 if(rebuild) {
36320 // Rebuild reconstruction constants if stencil contains bndry cells
36321 m_azimuthalWasNearBndryIds[offset] = cellId;
36322 } else {
36323 if(m_azimuthalWasNearBndryIds[offset] > -1) {
36324 // Reset reconstruction constants if stencil does not contain bndry cells anymore
36325 m_azimuthalWasNearBndryIds[offset] = cellId;
36326 } else {
36327 // Else keep old reconstruction constants
36328 m_azimuthalWasNearBndryIds[offset] = -1;
36329 }
36330 }
36331 }
36332 }
36333}
36334
36340template <MInt nDim, class SysEqn>
36342 TRACE();
36343
36344 if(grid().noAzimuthalNeighborDomains() == 0) return;
36345
36347 MFloatScratchSpace windowData(rcvSize * (nDim + 1), AT_, "windowData");
36348 windowData.fill(0);
36350 MFloatScratchSpace haloData(sndSize * (nDim + 1), AT_, "haloData");
36351 haloData.fill(0);
36352
36353 MInt sndCnt = 0;
36354 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36355 for(MUint j = 0; j < m_azimuthalMaxLevelHaloCells[i].size(); j++) {
36356 MInt cellId = m_azimuthalMaxLevelHaloCells[i][j];
36357 for(MInt d = 0; d < nDim; d++) {
36358 haloData[sndCnt++] = a_coordinate(cellId, d);
36359 }
36360 haloData[sndCnt++] = (MFloat)a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel);
36361 }
36362 }
36363
36365 m_azimuthalMaxLevelHaloCells, mpiComm(), haloData.getPointer(), windowData.getPointer(),
36366 nDim + 1);
36367
36368 MFloat angle = grid().azimuthalAngle();
36369 MFloat recCoord[3];
36370 MInt rcvCnt = 0;
36371 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36372 for(MUint j = 0; j < m_azimuthalMaxLevelWindowCells[i].size(); j++) {
36373 MInt offset = m_azimuthalMaxLevelWindowMap[i][j];
36374 for(MInt d = 0; d < nDim; d++) {
36375 recCoord[d] = windowData[rcvCnt++];
36376 }
36377
36378 MInt side = m_azimuthalBndrySide[offset];
36379 grid().rotateCartesianCoordinates(recCoord, (side * angle));
36380
36381 for(MInt d = 0; d < nDim; d++) {
36382 m_azimuthalCutRecCoord[offset * nDim + d] = recCoord[d];
36383 }
36384 m_azimuthalHaloActive[offset] = (MInt)windowData[rcvCnt++];
36385 }
36386 }
36387
36388 MInt offset = 0;
36389 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36390 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
36391 MInt cellId = grid().azimuthalWindowCell(i, j);
36392 if(m_azimuthalHaloActive[offset] > 0) {
36393 // m_azimuthalWasNearBndryIds[offset] = cellId;
36394 } else {
36396 m_noAzimuthalReconstNghbrs[offset] = 1;
36398 m_azimuthalWasNearBndryIds[offset] = -1;
36399 }
36400 offset++;
36401 }
36402 }
36403}
36404
36405
36410template <MInt nDim, class SysEqn>
36412 TRACE();
36413
36414 MFloat recCoord[nDim];
36415
36416 MInt offset = 0;
36417 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36418 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
36419 MInt cellId = grid().azimuthalWindowCell(i, j);
36420
36421 if(a_levelSetValuesMb(cellId, 0) < F0) {
36423 m_noAzimuthalReconstNghbrs[offset] = 1;
36425 offset++;
36426 continue;
36427 }
36428
36429 std::copy_n(&m_azimuthalCutRecCoord[offset * nDim], nDim, &recCoord[0]);
36430
36431 rebuildAzimuthalReconstructionConstants(cellId, offset, recCoord, mode);
36432
36433 offset++;
36434 }
36435 }
36436
36437 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36438 for(MUint j = 0; j < m_azimuthalRemappedWindowCells[i].size(); j++) {
36439 MInt cellId = m_azimuthalRemappedWindowCells[i][j];
36440
36441 if(a_levelSetValuesMb(cellId, 0) < F0) {
36443 m_noAzimuthalReconstNghbrs[offset] = 1;
36445 continue;
36446 }
36447
36448 std::copy_n(&m_azimuthalCutRecCoord[offset * nDim], nDim, &recCoord[0]);
36449
36450 rebuildAzimuthalReconstructionConstants(cellId, offset, recCoord, mode);
36451
36452 offset++;
36453 }
36454 }
36455}
36456
36460template <MInt nDim, class SysEqn>
36462 TRACE();
36463
36465 if(grid().noAzimuthalNeighborDomains() > 0) {
36466 MInt noFloatData = (mode == 0 ? m_noFloatDataAdaptation : m_noFloatDataBalance);
36467 MInt noIntData = m_noLongData;
36468
36469 MUint sndSize = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
36470 MFloatScratchSpace windowFData(sndSize * noFloatData, AT_, "windowIData");
36471 windowFData.fill(-1.0);
36472 ScratchSpace<MUlong> windowIData(sndSize * noIntData, AT_, "windowIData");
36473 windowIData.fill(0);
36474 MUint rcvSize = maia::mpi::getBufferSize(grid().azimuthalHaloCells());
36475 MFloatScratchSpace haloFData(rcvSize * noFloatData, AT_, "haloFData");
36476 haloFData.fill(-1.0);
36477 ScratchSpace<MUlong> haloIData(rcvSize * noIntData, AT_, "haloIData");
36478 haloIData.fill(0);
36479
36480 MInt sndCnt = 0;
36481 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36482 for(MInt j = 0; j < grid().noAzimuthalHaloCells(i); j++) {
36483 MInt cellId = grid().azimuthalHaloCell(i, j);
36484 if(m_oldBndryCells.count(cellId) != 0 || mode == 1) {
36485 auto it = m_oldBndryCells.find(cellId);
36486 haloFData[sndCnt * noFloatData] = a_cellVolume(cellId);
36487 haloFData[sndCnt * noFloatData + 1] = m_cellVolumesDt1[cellId];
36488 haloFData[sndCnt * noFloatData + 2] = it != m_oldBndryCells.end() ? it->second : F0;
36489 if(mode == 1) {
36490 for(MInt v = 0; v < CV->noVariables; v++) {
36491 haloFData[sndCnt * noFloatData + 3 + v] = a_variable(cellId, v);
36492 }
36493 }
36494
36495 haloIData[sndCnt * noIntData] = (unsigned)m_oldBndryCells.count(cellId);
36496 haloIData[sndCnt * noIntData + 1] = (a_properties(cellId)).to_ulong();
36497 }
36498
36499 sndCnt++;
36500 }
36501 }
36502
36503 // Exchange
36504 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), grid().azimuthalWindowCells(),
36505 grid().azimuthalHaloCells(), mpiComm(), haloFData.getPointer(), windowFData.getPointer(),
36506 noFloatData);
36507 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), grid().azimuthalWindowCells(),
36508 grid().azimuthalHaloCells(), mpiComm(), haloIData.getPointer(), windowIData.getPointer(),
36509 noIntData);
36510
36511 MInt rcvCnt = 0;
36512 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36513 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
36514 MInt cellId = grid().azimuthalWindowCell(i, j);
36515 if(windowIData[rcvCnt * noIntData] > 0 || mode == 1) {
36516 MBool isEqual = false;
36517 MLong gCellId = cellId;
36518 if(mode == 1) gCellId = c_globalId(cellId);
36519 if(m_azimuthalNearBoundaryBackup.count(gCellId) > 0) {
36520 MFloat recCoord[nDim];
36521 MFloat cellLength = c_cellLengthAtCell(cellId);
36522 auto range = m_azimuthalNearBoundaryBackup.equal_range(gCellId);
36523 for(auto it = range.first; it != range.second; ++it) {
36524 for(MInt d = 0; d < nDim; d++) {
36525 recCoord[d] = (it->second).first[d];
36526 }
36527 if(approx(this->m_azimuthalCartRecCoord[rcvCnt * nDim + 0], recCoord[0],
36528 (m_azimuthalCornerEps * cellLength))
36529 && approx(this->m_azimuthalCartRecCoord[rcvCnt * nDim + 1], recCoord[1],
36530 (m_azimuthalCornerEps * cellLength))
36531 && approx(this->m_azimuthalCartRecCoord[rcvCnt * nDim + (nDim - 1)], recCoord[nDim - 1],
36532 (m_azimuthalCornerEps * cellLength))) {
36533 isEqual = true;
36534 }
36535 }
36536 }
36537 if(isEqual) {
36538 rcvCnt++;
36539 continue;
36540 }
36541
36542 vector<MFloat> tmpF(mMax(noFloatData + nDim, nDim + 3));
36543 vector<MUlong> tmpI(noIntData);
36544 tmpF[0] = this->m_azimuthalCartRecCoord[rcvCnt * nDim];
36545 tmpF[1] = this->m_azimuthalCartRecCoord[rcvCnt * nDim + 1];
36546 if(nDim == 3) {
36547 tmpF[2] = this->m_azimuthalCartRecCoord[rcvCnt * nDim + 2];
36548 }
36549 tmpF[nDim] = windowFData[rcvCnt * noFloatData]; // cellVol
36550 tmpF[nDim + 1] = windowFData[rcvCnt * noFloatData + 1]; // cellVolDt1
36551 tmpF[nDim + 2] = windowFData[rcvCnt * noFloatData + 2]; // sweptVol
36552
36553 if(mode == 1) {
36554 for(MInt v = 0; v < CV->noVariables; v++) {
36555 tmpF[nDim + 3 + v] = windowFData[rcvCnt * noFloatData + 3 + v]; // a_variables
36556 }
36557 }
36558
36559 tmpI[0] = windowIData[rcvCnt * noIntData]; // oldBndryCnt
36560 tmpI[1] = windowIData[rcvCnt * noIntData + 1]; // cell properties
36561
36562 m_azimuthalNearBoundaryBackup.insert(make_pair(gCellId, make_pair(tmpF, tmpI)));
36563 }
36564
36565 rcvCnt++;
36566 }
36567 }
36568 }
36569
36570#ifndef NDEBUG
36571 MInt cntMax = 0;
36572 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36573 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
36574 MInt cellId = grid().azimuthalWindowCell(i, j);
36575 MLong gCellId = cellId;
36576 if(mode == 1) gCellId = c_globalId(cellId);
36577 if(cntMax < (signed)m_azimuthalNearBoundaryBackup.count(gCellId))
36578 cntMax = m_azimuthalNearBoundaryBackup.count(gCellId);
36579 if(mode == 0 && m_azimuthalNearBoundaryBackup.count(gCellId) > 2) {
36580 MFloat recCoord[nDim];
36581 auto range = m_azimuthalNearBoundaryBackup.equal_range(gCellId);
36582 for(auto it = range.first; it != range.second; ++it) {
36583 for(MInt d = 0; d < nDim; d++) {
36584 recCoord[d] = (it->second).first[d];
36585 }
36586 cerr << "W:" << domainId() << " " << cellId << "/" << c_globalId(cellId) << " " << gCellId << " "
36587 << c_level(cellId) << " " << mode << " " << m_azimuthalNearBoundaryBackup.count(gCellId) << " " << j
36588 << "/" << grid().noAzimuthalWindowCells(i) << " " << grid().azimuthalNeighborDomain(i) << " "
36589 << c_coordinate(cellId, 0) << " " << c_coordinate(cellId, 1) << " " << c_coordinate(cellId, 2) << " "
36590 << recCoord[0] << " " << recCoord[1] << " " << recCoord[nDim - 1] << endl;
36591 }
36592 }
36593 }
36594 }
36595 MPI_Allreduce(MPI_IN_PLACE, &cntMax, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "cntMax");
36596 if(domainId() == 0) cerr << "cntMax: " << cntMax << endl;
36597#endif
36598}
36599
36603template <MInt nDim, class SysEqn>
36605 TRACE();
36606
36607 if(grid().noAzimuthalNeighborDomains() == 0) return;
36608
36609 MInt noFloatData = (mode == 0 ? m_noFloatDataAdaptation : m_noFloatDataBalance);
36610 MInt noIntData = m_noLongData;
36611
36612 MUint sndSize = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
36613 MFloatScratchSpace windowFData(sndSize * noFloatData, AT_, "windowFData");
36614 windowFData.fill(-1.0);
36615 ScratchSpace<MUlong> windowIData(sndSize * noIntData, AT_, "windowIData");
36616 windowFData.fill(0);
36617 MUint rcvSize = maia::mpi::getBufferSize(grid().azimuthalHaloCells());
36618 MFloatScratchSpace haloFData(rcvSize * noFloatData, AT_, "haloFData");
36619 haloFData.fill(-1.0);
36620 ScratchSpace<MUlong> haloIData(rcvSize * noIntData, AT_, "haloIData");
36621 haloIData.fill(0);
36622
36623 MInt sndCnt = 0;
36624 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36625 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
36626 MInt cellId = grid().azimuthalWindowCell(i, j);
36627 MLong gCellId = cellId;
36628 if(mode == 1) gCellId = c_globalId(cellId);
36629 if(m_azimuthalNearBoundaryBackup.count(gCellId) != 0) {
36630 MFloat recCoord[nDim];
36631 for(MInt d = 0; d < nDim; d++) {
36632 recCoord[d] = this->m_azimuthalCartRecCoord[sndCnt * nDim + d];
36633 }
36634 MFloat cellLength = c_cellLengthAtCell(cellId);
36635 MFloat tmp[nDim];
36636 auto range = m_azimuthalNearBoundaryBackup.equal_range(gCellId);
36637 for(auto it = range.first; it != range.second; ++it) {
36638 for(MInt d = 0; d < nDim; d++) {
36639 tmp[d] = (it->second).first[d];
36640 }
36641 MBool isEqual = true;
36642 for(MInt d = 0; d < nDim; d++) {
36643 if(!approx(tmp[d], recCoord[d], 0.01 * cellLength)) isEqual = false;
36644 }
36645 if(isEqual) {
36646 ASSERT((it->second).second[0] > 0 || mode == 1, "WRONG!");
36647 windowFData[sndCnt * noFloatData] = (it->second).first[nDim]; // cellVolume
36648 windowFData[sndCnt * noFloatData + 1] = (it->second).first[nDim + 1]; // cellVolumeDt1
36649 windowFData[sndCnt * noFloatData + 2] = (it->second).first[nDim + 2]; // sweptVolume
36650 if(mode == 1) {
36651 for(MInt v = 0; v < CV->noVariables; v++) {
36652 windowFData[sndCnt * noFloatData + 3 + v] = (it->second).first[nDim + 3 + v];
36653 }
36654 }
36655
36656 windowIData[sndCnt * noIntData] = (it->second).second[0]; // oldBndryCnt
36657 windowIData[sndCnt * noIntData + 1] = (it->second).second[1]; // cell properties
36658
36659 break;
36660 }
36661 }
36662 }
36663
36664 sndCnt++;
36665 }
36666 }
36667
36669
36670 // Exchange
36671 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), grid().azimuthalHaloCells(),
36672 grid().azimuthalWindowCells(), mpiComm(), windowFData.getPointer(), haloFData.getPointer(),
36673 noFloatData);
36674 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), grid().azimuthalHaloCells(),
36675 grid().azimuthalWindowCells(), mpiComm(), windowIData.getPointer(), haloIData.getPointer(),
36676 noIntData);
36677
36678 MInt rcvCnt = 0;
36679 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36680 for(MInt j = 0; j < grid().noAzimuthalHaloCells(i); j++) {
36681 MInt cellId = grid().azimuthalHaloCell(i, j);
36682
36683 if(mode == 1) {
36684 maia::fv::cell::BitsetType props = (haloIData[rcvCnt * noIntData + 1]);
36685 a_hasProperty(cellId, SolverCell::WasInactive) = props[maia::fv::cell::p(SolverCell::WasInactive)];
36686 } else {
36687 if(a_levelSetValuesMb(cellId, 0) < F0) {
36688 a_hasProperty(cellId, SolverCell::WasInactive) = true;
36689 } else {
36690 a_hasProperty(cellId, SolverCell::WasInactive) = false;
36691 }
36692 }
36693 a_hasProperty(cellId, SolverCell::WasGapCell) = false;
36694 if(m_closeGaps) mTerm(1, AT_, "AzimuthalPer adaptation not working with gap closing!");
36695
36696 if(mode == 1) {
36697 for(MInt v = 0; v < CV->noVariables; v++) {
36698 a_variable(cellId, v) = haloFData[rcvCnt * noFloatData + 3 + v];
36699 a_oldVariable(cellId, v) = a_variable(cellId, v);
36700 }
36701 setPrimitiveVariables(cellId);
36702 }
36703 if(haloIData[rcvCnt * noIntData] > 0) {
36704 a_cellVolume(cellId) = haloFData[rcvCnt * noFloatData];
36705 m_cellVolumesDt1[cellId] = haloFData[rcvCnt * noFloatData + 1];
36706
36707 m_oldBndryCells.insert(make_pair(cellId, haloFData[rcvCnt * noFloatData + 2]));
36708
36709 maia::fv::cell::BitsetType props = (haloIData[rcvCnt * noIntData + 1]);
36710 a_hasProperty(cellId, SolverCell::IsMovingBnd) = props[maia::fv::cell::p(SolverCell::IsMovingBnd)];
36711 a_hasProperty(cellId, SolverCell::NearWall) = props[maia::fv::cell::p(SolverCell::NearWall)];
36712 a_hasProperty(cellId, SolverCell::IsInactive) = props[maia::fv::cell::p(SolverCell::IsInactive)];
36713 a_hasProperty(cellId, SolverCell::WasInactive) = a_hasProperty(cellId, SolverCell::WasInactive);
36714 a_hasProperty(cellId, SolverCell::WasGapCell) = props[maia::fv::cell::p(SolverCell::WasGapCell)];
36715 } else {
36716 a_cellVolume(cellId) = grid().gridCellVolume(a_level(cellId));
36717 m_cellVolumesDt1[cellId] = grid().gridCellVolume(a_level(cellId));
36718 }
36719
36720 if((a_level(cellId) >= m_lsCutCellMinLevel)
36723 vector<MFloat> tmp(max(m_noCVars + m_noFVars, 0) + 1);
36724 tmp[0] = m_cellVolumesDt1[cellId];
36725 for(MInt v = 0; v < m_noCVars; v++) {
36726 tmp[1 + v] = std::numeric_limits<MFloat>::lowest();
36727 }
36728 for(MInt v = 0; v < m_noFVars; v++) {
36729 tmp[1 + m_noCVars + v] = std::numeric_limits<MFloat>::lowest();
36730 }
36731 m_nearBoundaryBackup.insert(make_pair(cellId, tmp));
36732 }
36733
36734 rcvCnt++;
36735 }
36736 }
36737}
36738
36742template <MInt nDim, class SysEqn>
36744 TRACE();
36745
36746 // Nothing to do if solver is not active
36747 if(!isActive()) {
36748 return;
36749 }
36750
36751 if(grid().azimuthalPeriodicity()) {
36755 "m_azimuthalNearBoundaryBackupBalFloat", AT_);
36756 mAlloc(m_azimuthalNearBoundaryBackupBalLong, maxNoGridCells() * noLongData, "m_azimuthalNearBoundaryBackupBalLong",
36757 AT_);
36758
36759 m_azimuthalRecConstSet = false;
36762
36763 MInt maxCount = 0;
36764 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
36765 MInt gCellId = c_globalId(cellId);
36766 if((MInt)m_azimuthalNearBoundaryBackup.count(gCellId) > maxCount) {
36767 maxCount = (MInt)m_azimuthalNearBoundaryBackup.count(gCellId);
36768 }
36769 }
36770 MPI_Allreduce(MPI_IN_PLACE, &maxCount, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "maxCount");
36772 mTerm(1, "This is a problem! " + to_string(maxCount) + " " + to_string(m_azimuthalNearBoundaryBackupMaxCount));
36773 }
36774
36775 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
36776 MInt gCellId = c_globalId(cellId);
36777 for(MInt i = 0; i < noLongData; i++) {
36778 m_azimuthalNearBoundaryBackupBalLong[cellId * noLongData + i] = -1;
36779 }
36780 for(MInt i = 0; i < noFloatData; i++) {
36781 m_azimuthalNearBoundaryBackupBalFloat[cellId * noFloatData + i] = -1;
36782 }
36783 if(m_azimuthalNearBoundaryBackup.count(gCellId) != 0) {
36784 MInt indexL = 0;
36785 MInt indexF = 0;
36786 auto range = m_azimuthalNearBoundaryBackup.equal_range(gCellId);
36787 for(auto it_ = range.first; it_ != range.second; ++it_) {
36788 m_azimuthalNearBoundaryBackupBalLong[cellId * noLongData + indexL++] = (MUlong)gCellId;
36789 m_azimuthalNearBoundaryBackupBalLong[cellId * noLongData + indexL++] = (MUlong)(it_->second).second[0];
36790 m_azimuthalNearBoundaryBackupBalLong[cellId * noLongData + indexL++] = (MUlong)(it_->second).second[1];
36791
36792 for(MInt f = 0; f < (nDim + m_noFloatDataBalance); f++) {
36793 m_azimuthalNearBoundaryBackupBalFloat[cellId * noFloatData + indexF++] = (it_->second).first[f];
36794 }
36795 }
36796 }
36797 }
36798 }
36799}
36800
36804template <MInt nDim, class SysEqn>
36806 TRACE();
36807
36808 set<MInt> needsExc;
36809 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36810 for(MUint j = 0; j < m_azimuthalMaxLevelWindowCells[i].size(); j++) {
36811 MInt offset = m_azimuthalMaxLevelWindowMap[i][j];
36812 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
36813 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36815 if(a_isHalo(recId)) {
36816 needsExc.insert(recId);
36817 }
36818 }
36819 }
36820 }
36821
36824
36825 for(MInt i = 0; i < noNeighborDomains(); i++) {
36826 m_azimuthalLinkedHaloCells[i].clear();
36828 }
36829
36830 MUint sndSize = maia::mpi::getBufferSize(grid().haloCells());
36831 MIntScratchSpace haloBuff(sndSize, AT_, "haloBuff");
36832 haloBuff.fill(0);
36833 MUint rcvSize = maia::mpi::getBufferSize(grid().windowCells());
36834 MIntScratchSpace windowBuff(rcvSize, AT_, "windowBuff");
36835 windowBuff.fill(0);
36836
36837 MInt sndCnt = 0;
36838 for(MInt i = 0; i < noNeighborDomains(); i++) {
36839 for(MInt j = 0; j < m_noMaxLevelHaloCells[i]; j++) {
36840 const MInt haloCell = m_maxLevelHaloCells[i][j];
36841 if(needsExc.find(haloCell) != needsExc.end()) {
36842 haloBuff[sndCnt] = 1;
36844 } else {
36845 haloBuff[sndCnt] = 0;
36846 }
36847 sndCnt++;
36848 }
36849 }
36850
36851 ScratchSpace<MPI_Request> sndReq(noNeighborDomains(), AT_, "sndReq");
36852 ScratchSpace<MPI_Request> rcvReq(noNeighborDomains(), AT_, "rcvReq");
36853 MInt rcvOffset = 0;
36854 MInt sndOffset = 0;
36855 for(MInt i = 0; i < noNeighborDomains(); i++) {
36856 MPI_Irecv(&windowBuff[rcvOffset], m_noMaxLevelWindowCells[i], MPI_INT, neighborDomain(i), 2, mpiComm(), &rcvReq[i],
36857 AT_, "windowBuff[rcvOffset]");
36858 rcvOffset += m_noMaxLevelWindowCells[i];
36859 }
36860 for(MInt i = 0; i < noNeighborDomains(); i++) {
36861 MPI_Isend(&haloBuff[sndOffset], m_noMaxLevelHaloCells[i], MPI_INT, neighborDomain(i), 2, mpiComm(), &sndReq[i], AT_,
36862 "haloBuff[i]");
36863 sndOffset += m_noMaxLevelHaloCells[i];
36864 }
36865 MPI_Waitall(noNeighborDomains(), &rcvReq[0], MPI_STATUSES_IGNORE, AT_);
36866 MPI_Waitall(noNeighborDomains(), &sndReq[0], MPI_STATUSES_IGNORE, AT_);
36867
36868 MInt rcvCnt = 0;
36869 for(MInt i = 0; i < noNeighborDomains(); i++) {
36870 for(MInt j = 0; j < m_noMaxLevelWindowCells[i]; j++) {
36872 if(windowBuff[rcvCnt] > 0) {
36874 }
36875 rcvCnt++;
36876 }
36877 }
36878}
36879
36883template <MInt nDim, class SysEqn>
36885 TRACE();
36886
36888 MFloatScratchSpace windowData(sndSize * m_noCVars, AT_, "windowData");
36889 windowData.fill(0);
36891 MFloatScratchSpace haloData(rcvSize * m_noCVars, AT_, "haloData");
36892 haloData.fill(0);
36893
36894 MInt sndCnt = 0;
36895 for(MInt i = 0; i < noNeighborDomains(); i++) {
36896 for(MInt j = 0; j < (signed)m_azimuthalLinkedWindowCells[i].size(); j++) {
36897 MInt cellId = m_azimuthalLinkedWindowCells[i][j];
36898 std::copy_n(&a_variable(cellId, 0), m_noCVars, &windowData[sndCnt]);
36899 sndCnt += m_noCVars;
36900 }
36901 }
36902
36903 // Exchange
36905 mpiComm(), windowData.getPointer(), haloData.getPointer(), m_noCVars);
36906
36907 // Extract
36908 MInt rcvCnt = 0;
36909 for(MInt i = 0; i < noNeighborDomains(); i++) {
36910 for(MInt j = 0; j < (signed)m_azimuthalLinkedHaloCells[i].size(); j++) {
36911 MInt cellId = m_azimuthalLinkedHaloCells[i][j];
36912 std::copy_n(&haloData[rcvCnt], m_noCVars, &a_variable(cellId, 0));
36913 rcvCnt += m_noCVars;
36914 }
36915 }
36916}
MLong allocatedBytes()
Return the number of allocated bytes.
Definition: alloc.cpp:121
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
void append()
Definition: collector.h:153
MInt size()
Definition: collector.h:29
static MInt propertyLength(const MString &name, MInt solverId=m_noSolvers)
Returns the number of elements of a property.
Definition: context.cpp:538
static T getSolverProperty(const MString name, const MInt solverId, const MString &nameOfCallingFunction, const T *default_value, MInt pos=0)
Definition: context.h:168
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
BodySurface ** m_srfcs
MFloat * m_coordinates
std::vector< std::vector< MInt > > m_splitChilds
MInt c_level(const MInt cellId) const
Returns the grid level of the cell cellId.
void resetSolver() override
Reset the solver prior to load balancing.
std::vector< std::vector< MInt > > m_azimuthalMaxLevelWindowCells
virtual void LSReconstructCellCenter()
Dispatch the reconstruction computation to the appropiate loop.
MLong c_neighborId(const MInt cellId, const MInt dir, const MBool assertNeighborState=true) const
Returns the grid neighbor id of the grid cell cellId dir.
MInt a_noSurfaces()
Returns the number of surfaces.
static constexpr const MInt m_noCorners
Collector< FvBndryCell< nDim, SysEqn > > * m_bndryCells
void balance(const MInt *const noCellsToReceiveByDomain, const MInt *const noCellsToSendByDomain, const MInt *const targetDomainsByCell, const MInt oldNoCells) override
Balance the solver.
MLong c_childId(const MInt cellId, const MInt pos) const
Returns the grid child id of the grid cell cellId at position pos.
std::vector< std::vector< MInt > > m_azimuthalRemappedWindowCells
MFloat & a_rightHandSide(const MInt cellId, MInt const varId)
Returns the right hand side of the cell cellId for the variable varId.
MFloat c_cellLengthAtCell(const MInt cellId) const
Returns the length of the cell for level.
MFloat c_cellLengthAtLevel(const MInt level) const
Returns the length of the cell for level.
MFloat & a_slope(const MInt cellId, MInt const varId, const MInt dir) override
Returns the slope of the cell cellId for the variable varId in direction dir.
MFloat & a_oldVariable(const MInt cellId, const MInt varId)
Returns oldVariablesv of the cell cellId variables varId.
MBool a_isBndryCell(const MInt cellId) const override
Returns isBndryCell of the cell cellId.
void finalizeAdaptation() override
void swapCells(const MInt, const MInt) override
virtual void resetBoundaryCells(const MInt offset=0)
virtual void resetSolverFull()
MBool a_isHalo(const MInt cellId) const
Returns IsHalo of the cell cellId.
void prepareAdaptation() override
maia::fv::cell::BitsetType & a_properties(const MInt cellId)
Returns properties of the cell cellId.
MFloat crankAngle(const MFloat, const MInt)
help-function for engine calculations which returns the crank-angle for a given time mode = 0: return...
MFloat & a_surfaceArea(const MInt srfcId)
Returns the area of surface srfcId.
MInt a_cutCellLevel(const MInt cellId) const
Returns the level for cutCells, this can either be the maxRefinementLevel or the level of the current...
MFloat & a_variable(const MInt cellId, const MInt varId)
Returns conservative variable v of the cell cellId for variables varId.
MLong c_parentId(const MInt cellId) const
Returns the grid parent id of the cell cellId.
Collector< CartesianGridPoint< nDim > > * m_gridPoints
std::vector< std::vector< MInt > > m_azimuthalMaxLevelHaloCells
MFloat & a_levelSetValuesMb(const MInt cellId, const MInt set)
Returns the levelSetMb-value for fv-CellId cellId and set.
SysEqn::ConservativeVariables * CV
virtual void saveRestartFile(const MBool)
void finalizeBalance() override
Reinitialize solver after all data structures have been recreated.
MFloat & a_surfaceCoordinate(const MInt srfcId, const MInt dir)
Returns the coordinate of surface srfcId in direction dir.
virtual MBool maxResidual(MInt mode=0)
Computes the global root-mean-square residual. The residual is defined as time derivative of conserva...
virtual void Ausm()
Dispatches the AUSM flux computation for different number of species.
MInt & a_associatedBodyIds(const MInt cellId, const MInt set)
Returns the associatedBodyIds for fv-CellId cellId and set.
MInt a_noCells() const
Returns the number of cells.
MBool a_hasProperty(const MInt cellId, const Cell p) const
Returns grid cell property p of the cell cellId.
static constexpr MFloat m_volumeThreshold
std::vector< std::vector< MInt > > m_azimuthalMaxLevelWindowMap
static constexpr const MInt m_noDirs
void setSensors(std::vector< std::vector< MFloat > > &sensors, std::vector< MFloat > &sensorWeight, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MInt > &sensorSolverId) override
set the sensors for the adaptation (i.e. which cell should be refined/removed?)
void preTimeStep() override
void refineCell(const MInt) override
MInt c_noChildren(const MInt cellId) const
Returns the number of children of the cell cellId.
MFloat c_coordinate(const MInt cellId, const MInt dir) const
Returns the coordinate of the cell from the grid().tree() cellId for dimension dir.
virtual void updateSpongeLayer()
computes the additional rhs of all cells lying inside the sponge layer to dissipate outgoing waves.
void removeChilds(const MInt) override
MFloat & a_coordinate(const MInt cellId, const MInt dir)
Returns the coordinate of the cell from the fvcellcollector cellId for dimension dir.
virtual void applyInitialCondition()
Initializes the entire flow field.
MLong c_globalId(const MInt cellId) const
Returns the global grid id of the grid cell cellId.
MInt & a_surfaceNghbrCellId(const MInt srfcId, const MInt dir)
Returns the neighbor cell id of surface srfcId in direction dir.
virtual void distributeFluxToCells()
Distributes the surface fluxes to the cell RHS.
MFloat & a_spongeFactor(const MInt cellId)
Returns the spongeFactor of the cell cellId.
maia::fv::cell::BitsetType::reference a_wasGapCell(const MInt cellId)
Returns wasGapCell of the cell cellId.
MBool c_isLeafCell(const MInt cellId) const
MFloat & a_cellVolume(const MInt cellId)
Returns the cell volume of the cell from the fvcellcollector cellId.
void setPrimitiveVariables(MInt cellId)
computes primitive from primitive variables for given cell id. This is the version for all SysEqn.
virtual void resetRHSCutOffCells()
virtual void setCellProperties()
virtual MFloat entropy(MInt cellId)
static constexpr const MInt m_noEdges
Collector< PointBasedCell< nDim > > * m_extractedCells
MInt & a_level(const MInt cellId)
Returns the level of the cell from the fvcellcollector cellId.
MInt a_hasNeighbor(const MInt cellId, const MInt dir, const MBool assertNeighborState=true) const
Returns noNeighborIds of the cell CellId for direction dir.
MFloat timeStep(MBool canSolver=false) noexcept
virtual void updateMultiSolverInformation(MBool fullReset=false)
virtual MBool gridPointIsInside(MInt, MInt)
MInt & a_bndryId(const MInt cellId)
Returns the bndryId of the cell cellId.
void rebuildAzimuthalReconstructionConstants(MInt cellId, MInt offset, MFloat *recCoord, MInt mode=0)
std::vector< MInt > m_azimuthalRemappedNeighborDomains
MFloat & a_pvariable(const MInt cellId, const MInt varId)
Returns primitive variable v of the cell cellId for variables varId.
void balancePre() override
Reinitialize solver for DLB prior to setting solution data.
MBool checkNeighborActive(const MInt cellId, const MInt dir) const
Cecks wether the cell cellId has a valid neighbor in direction dir.
MFloat & a_FcellVolume(const MInt cellId) override
Returns the inverse cell volume of the cell from the fvcellcollector cellId.
const MInt & getAssociatedInternalCell(const MInt &cellId) const
Returns the Id of the split cell, if cellId is a split child.
void build(std::vector< CsgPolygon > _polygons)
void splitPolygon(CsgPolygon *polygon, std::vector< CsgPolygon > *coplanarFront, std::vector< CsgPolygon > *coplanarBack, std::vector< CsgPolygon > *front, std::vector< CsgPolygon > *back) const
void insertCoplanarPolygon(CsgPolygon *polygon, std::vector< CsgPolygon > *coplanarFront, std::vector< CsgPolygon > *coplanarBack) const
CsgVector minus(const CsgVector &a) const
CsgVertex interpolate(CsgVertex *other, MFloat t) const
void logBoundaryData(const MChar *fileName, MBool forceOutput)
logs several boundary values to the given output file
void resetMbBoundaryCells()
resets all moving boundary cells - STL boundary remains intact
void printDynamicCoefficients(MBool firstRun, MFloat *pressureForce)
void reInitSolutionStep(const MInt mode)
Re-initializes the solver.
MInt returnNoActiveCorners(MInt)
returns the numer of active Corners for an arbitrary cell (the cell is not a bndryCandidate yet and t...
void copyVarsToSmallCells() override
calls m_fvBndryCnd->copyVarsToSmallCells()
void sensorPatch(std::vector< std::vector< MFloat > > &, std::vector< std::bitset< 64 > > &, std::vector< MFloat > &, MInt, MInt) override
MFloat getLevelSetValueNaca00XX(const MFloat *const, const MFloat sign)
void initPointParticleProperties()
void initGField()
initializes the level-set data at startup
static void computeNormal(const MFloat *p0, const MFloat *p1, MFloat *res, MFloat &w)
returns the normal corresponding to the triangle abc and returns the result in res
void leastSquaresReconstruction()
Least squares reconstruction.
MInt getAdjacentGridCells(MInt cellId, MInt *adjacentCells)
retrieves all direct and diagonal fluid cell neighbours of the given cell
void storeAzimuthalPeriodicData(MInt mode=0)
Stored azimuthal periodic data from halo rank on window rank.
void checkCellState()
checks the cell state of the inactive cells based on the nodal ls values if a cell is inactive (level...
MInt broadcastSignal(const MInt sender, const MInt signal)
hijacked function to compute gradients in intial condition 122 for pressure poisson equation
static void matrixProduct(MFloatScratchSpace &C, MFloatScratchSpace &A, MFloatScratchSpace &B)
C=A*B.
MInt writeGeometryToVtkXmlFile(const MString &fileName)
Writes VTK file for the embedded geometry.
void loadRestartFile() override
Loads the restart files.
void computeFlowStatistics(MBool force)
MFloat updateCellVolumeGCL(MInt bndryId)
static void matrixProductTranspose(MFloatScratchSpace &C, MFloatScratchSpace &A, MFloatScratchSpace &B)
C=A*B^t.
std::map< MInt, std::vector< MFloat > > m_nearBoundaryBackup
void initAzimuthalLinkedHaloExc()
Create exchange for all window/halo cells which are used for the azimuthal periodic interpolation.
static void computeRotationMatrix(MFloatScratchSpace &, MFloat *q)
rotation matrix co-rotating(~inertial) frame -> body-fixed frame
void computeSlipStatistics(const MIntScratchSpace &nearestBodies, const MFloatScratchSpace &nearestDist, const MFloat maxDistConstructed)
void gapCellExchange(MInt)
exchanges variables and wasInactive for gapCells
std::vector< std::vector< MInt > > m_azimuthalLinkedWindowCells
void setBoundaryVelocity()
Sets the boundry velocity at the moving cut-cells. sets: m_primVars[PV->VV[i]] to m_bodyVelocity[i] f...
void buildAdditionalAzimuthalReconstructionStencil(MInt mode=0)
Rebuild azimuthal reconstruction constants for moving boundary cells.
std::vector< MInt > m_refOldBndryCells
void computeBodySurfaceData(MFloat *pressureForce=nullptr)
computes relevant variables at the moving boundary surface and determines the resulting body force
void recordBodyData(const MBool &firstRun)
void saveRestartFile(const MBool) override
Saves the restart file.
void finalizeInitSolver() override
Initializes the solver afer the initialRefinement!
void updateInfinityVariables()
update infinity state for certain testcases with constructed level-set field!
void writeVtkDebug(const MString suffix)
MString getConservativeVarName(MInt i)
returns the name of the conservative variable at the given index i
MFloat filterFloat(MFloat number)
filter nan's
void applyExternalOldSource() override
remove external sources from tho old RHS for new-RungeKutta-scheme for moving boundaries
FvMbCartesianSolverXD(MInt, MInt, const MBool *, maia::grid::Proxy< nDim > &gridProxy_, Geometry< nDim > &geometry_, const MPI_Comm comm)
MFloat * m_azimuthalNearBoundaryBackupBalFloat
void initSolutionStep(MInt mode) override
Initializes the solver.
MFloat getDistanceSplitSphere(const MInt, const MInt)
determines the level-set value for the given cell provided that the embedded body is spherical
void correctRefinedBndryCell()
correct old-BndryCells which are no-longer leaf-Cells after the adaptation NOTE: mas-conservative upd...
void updateViscousFluxComputation()
corrects the cell-surface distances at the boundary needed for the viscous flux computation
void updateAzimuthalNearBoundaryExchange()
Reset former azimuthal nearBoundaryCells.
void Muscl(MInt timerId=-1) override
Reconstructs the flux on the surfaces.
void setupBoundaryCandidatesAnalytical()
determine all possible fluid boundary cells for a spherical embedded body
void swapCells(const MInt, const MInt) override
MInt getFacingNghbrs(const MInt cellId, const MBool includeAllChilds)
determines the neighbors sharing a face with the given cell
void computeGhostCellsMb()
creates a ghost cell for all cells near(!) the moving boundary
void saveSolverSolution(const MBool forceOutput=false, const MBool finalTimeStep=false) override
Manages solver-specific output.
std::multimap< MLong, std::pair< std::vector< MFloat >, std::vector< MUlong > > > m_azimuthalNearBoundaryBackup
void initSolver() override
Initializes the solution.
void getBodyRotationDt1(const MInt bodyId, MFloat *bodyRotation)
void setSensors(std::vector< std::vector< MFloat > > &sensors, std::vector< MFloat > &sensorWeight, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MInt > &sensorSolverId) override
MInt inverseGJ()
computes the Gauss Jordan matrix inversion of the first DxD-solver of m_A. The inverse A^-1 is stored...
std::vector< MInt > m_bndryCandidateIds
void linkBndryCells()
Links bndryCells.
void correctSrfcsMb()
correct surfaces intersected by the moving boundary
void correctMasterSlaveSurfaces()
Removes surfaces between master-slave pairs and reassigns slave cell surfaces required in order to ma...
void setParticleFluidVelocities(MFloat *=nullptr)
void restoreNeighbourLinks()
restores previously deleted neighbour information and reactivates cells
void saveBodyRestartFile(const MBool backup)
save restart body file
void setAdditionalActiveFlag(MIntScratchSpace &) override
void generateBndryCellsMb(const MInt mode)
call all routines necessary for the generation of boundary cells mode = -1: default argument,...
std::set< MInt > m_freeSurfaceIndices
void computeAzimuthalReconstructionConstants(MInt mode=0) override
Compute the reconstruction constants for azimuthal periodic exchange using a weighted least squares a...
void preSolutionStep(const MInt=-1) override
step before the solver solution Step
void transferBodyState(MInt k, MInt b)
void commAzimuthalPeriodicData(MInt mode=0)
Send stored azimuthal periodic data from window to halo.
void removeSurfaces(MInt cellId)
removes the surfaces of the given cell
void resetRHSNonInternalCells() override
void initializeMb()
called by the constructor 1) read additional fvmb properties 2) allocate fvmb specific memory 3) init...
void updateMultiSolverInformation(MBool fullReset=false) override
void buildAdditionalReconstructionStencil()
correct reconstruction stencil for all cells near moving boundaries
MFloat getDistance(const MFloat *const, const MInt)
void allocateBodyMemory(MInt mode=0)
void exchangeAzimuthalOuterNodalValues(std::vector< CutCandidate< nDim > > &candidates, std::vector< MInt > &candidateIds)
Exchange of nodal values of azimuthal periodic halo cells.
void correctCoarsenedBndryCellVolume()
correct BndryCells volume of bndryCells which were a bndryCell on a coarser level before
void deleteNeighbourLinks()
deletes links to neighbours tagged inactive
void updateSpongeLayer() override
computes the additional rhs of all cells lying inside the sponge layer to dissipate outgoing waves.
void initBndryLayer()
initializes the bndryLayer data and is/was inactive at solver initialisation
GeometryIntersection< nDim > * m_geometryIntersection
void createCutFaceMb_MGC()
determines the geometric cut-cell data
MInt getAdjacentCellsAllLevels(MInt cellId, MInt *adjacentCells)
retrieves all direct and diagonal fluid cell neighbours of the given cell
void moveSurface(const MInt toSrfcId, const MInt fromSrfcId)
void updateBodyProperties()
update properties of the embedded body (mainly forced structural motion)
void initializeRungeKutta() override
This function loads all terms used by Runge Kutta.
void writeListOfActiveFlowCells() override
stores all cells and surfaces needed for the flux computation
void writeVTKFileOfCell(MInt, const std::vector< polyEdge2D > *, const std::vector< polyVertex > *, MInt)
void computeNearBodyFluidVelocity(const MIntScratchSpace &nearestBodies, const MFloatScratchSpace &nearestDist, MFloat *vel, MFloat *velGrad, MFloat *rotation, const std::vector< MFloat > &setup=std::vector< MFloat >(), MInt *skipBodies=nullptr, MFloat *meanBodyState=nullptr, MFloat *pressure=nullptr, MFloat *velDt=nullptr, MFloat *rotationDt=nullptr, MFloat *nearestFac=nullptr)
Mean parameters: near body data estimated by weighted filtering procedure All parameters after "setup...
void setGapCellId()
set the gapCellId for gapInitMethod = 0, otherwise handeled in gapHandling!
MFloat temperature(MInt cellId)
temperature
void initializeMaxLevelExchange() override
update window/halo cell collectors
FvBndryCndXD< nDim, SysEqn > * m_fvBndryCnd
void compVolumeIntegrals(std::vector< polyCutCell > *, std::vector< polyEdge2D > *, const std::vector< polyVertex > *)
void getBodyRotation(const MInt bodyId, MFloat *bodyRotation)
void writeVtkXmlFiles(const MString fileName, const MString GFileName, MBool regularOutput, MBool diverged) override
write flow variables as XML VTK files
void resetSolver() override
Reset the solver prior to load balancing.
void writeVtkXmlOutput(const MString &fileName, MBool debugOutput=false)
write flow variables as XML VTK
void determineNearBndryCells()
determines cells at the boundary (i.e. boundary cells and their direct neighbors)
MBool rungeKuttaStep() override
calls a Runge Kutta substep
void updateCellSurfaceDistanceVectors()
correct the cell-surface distance vectors for cells near the moving boundary
void balancePre() override
Reinitialize solver for DLB prior to setting solution data.
void readStlFile(const MChar *fileName, MBool readNormals)
read specified STL file
void balancePost() override
Reinitialize solver after setting solution data in DLB.
void computeBodyVolume(MFloatScratchSpace &partVol)
void loadBodyRestartFile(MInt)
load restart body file readMode = 0 : do not read the cellVolume from file (read only bodyData) readM...
void adaptTimeStep()
computes the time step
void createSurfaceSplit(MInt srfcId, MInt cellId, MInt splitChildId, MInt direction)
restores the surfaces of the given cell
void restoreSurfaces(const MInt cellId)
restores the surfaces of the given cell
void applyExternalSource() override
Add external sources to the RHS for new-RungeKutta-scheme for moving boundaries differs from the base...
void checkBoundaryCells()
performs an integrety check of the boundary cells
MBool test_face(MInt, MInt, MInt)
Test a face (MarchingCubes helper routine) receives MAIA face if face>0 return true if the face conta...
static MFloat distancePointEllipseSpecial(const MFloat e[2], const MFloat y[2], MFloat x[2])
MInt getEqualLevelNeighbors(MInt cellId, MInt(&nghbrs)[27])
retrieves all direct and diagonal fluid cell neighbours of the given cell
void checkGapCells()
determines Gap-state, and organises GapCells
void getNormalSphere(const MInt, const MInt, MFloat[])
MBool constructGFieldCorrector()
determine the displacement of the embedded body – corrector step
void initGapCellExchange()
creates the gap-cell exchange communicators based on initializeMaxLevelExchange
static void setAdditionalCellProperties()
set the properties of cells and determines the state of halo cells
void initEmergingGapCells()
initializes variables of cells which occur in a freshly opened gap (valve gap etc....
void updateSplitParentVariables() override
void localToGlobalIds() override
Change local into global ids.
void advanceBodies()
advances the time and stores the flow variables
void resetSolverFull() override
resets the solver
void initializeEmergedCells()
initializes variables of cells which recently became active and therefore have no up-to-date history ...
void finalizeBalance() override
Reinitialize solver after all data structures have been recreated.
MBool solutionStep() override
Performs the solutionStep of the FVMB solver the loop over the different RK-steps is done in the exec...
void resetSolverMb()
resets the solver to an empty domain without moving boundary
MFloat checkAreaDiff(MInt srfcId1, MInt srfcId2)
void setCellWeights(MFloat *) override
set static cell weights for solver cells, which are used for the domain decomposition
void getNormalEllipsoid(const MInt, const MInt, MFloat[])
void setOldGeomBndryCellVolume()
set bndryCell volume from m_oldGeomBndryCells which is read from bodyRestartFile at initSolver and th...
void setGapOpened()
sets the global-Trigger m_gapOpened, to determine if Gap-Cells are opened! old and incorrect version!...
MInt getAdjacentCellsExtended(MInt cellId, MInt *adjacentCells)
retrieves the first two layers of direct and diagonal fluid cell neighbours of the given cell
static void crossProduct(MFloat *c, MFloat *a, MFloat *b)
computes the cross product c <- (a x b) for a, b, c in R^3
void checkHaloBndryCells(MBool sweptVol)
void compFaceIntegrals(polyCutCell *, std::vector< polyEdge2D > *, const std::vector< polyVertex > *, MInt, MInt)
void computeNodalLSValues()
compute the level-set values at the mesh vertices
void constructGField(MBool updateBody=true)
manually constructs the level-set field after each time step
MFloat getDistanceEllipsoid(const MFloat *const, const MInt)
void correctRefinedBndryCellVolume()
correct BndryCells volume of bndryCells which were a bndryCell on a coarser level before
void compProjectionIntegrals(polyCutCell *, std::vector< polyEdge2D > *, const std::vector< polyVertex > *, MInt, MInt, MFloat *)
compute various integrations over projection of face
MFloat getDistancePiston(const MFloat *const, const MInt)
void setTimeStep() override
calls sets() and stores the time step for all cells
void advanceExternalSource() override
advance external sources
void addBoundarySurfacesMb()
adds a surface for the ghost-boundary cell intersections
MString getPrimitiveVarName(MInt i)
returns the name of the primitive variable at the given index i
void updateGeometry()
Updates the member-variables in the geometry-intersection class.
MInt createSplitCell(MInt cellId, MInt noSplitChilds)
MLong getNumberOfCells(MInt mode)
mode=0: total mode=1: min mode=2: max mode=3: average
MBool fileExists(const MChar *fileName)
MBool gridPointIsInside(MInt, MInt) override
void getBoundaryDistance(MFloatScratchSpace &) override
ATTRIBUTES1(ATTRIBUTE_HOT) void LSReconstructCellCenter() override
MBool maxResidual(MInt mode=0) override
Computes the maxResiduum for all cells.
static constexpr MInt m_noCellNodes
void writeVtkXmlOutput_MGC(const MString &fileName)
write flow variables as XML VTK
void applyBoundaryCondition() override
dummy, since applyBoundaryCondition() it is placed wrong for moving boundary problems,...
MInt createBndryCellMb(MInt cellId)
creates a moving boundary cell for the given cell
void descendDistance(const MInt cellId, const MInt *const bodyIds, const MInt bodyCnt, MIntScratchSpace &nearestBodies, MFloatScratchSpace &nearestDist)
void computeReconstructionConstants() override
computes the reconstruction constants using inverse distance weighted least squares
MFloat CalculateLSV(MInt, MIntScratchSpace &)
Calculate LevelSetValue with an Approximation of the Neighbours for a grid in the NarrowBand.
MInt constructDistance(const MFloat deltaMax, MIntScratchSpace &nearestBodies, MFloatScratchSpace &nearestDist)
void crankAngleSolutionOutput()
save a full solutionOutput at timeSteps closesed to a specified crankAngle Interval save a solution s...
void deleteSurface(MInt srfcId)
removes the surfaces of the given cell
std::set< MInt > m_coarseOldBndryCells
void logOutput()
logs several collector sizes
void advanceSolution()
advances the time and stores the flow variables
MFloat interpolateLevelSet(MInt *, MFloat *, MInt)
interpolates levelset function to a given coordinate
MFloat distancePointEllipsoidSpecial(const MFloat e[3], const MFloat y[3], MFloat x[3])
MInt checkNeighborActivity(MInt)
ckecks that a new bndry-Cell has at least one neighbor which was active before if this is not the cas...
void setRungeKuttaFunctionPointer()
This function sets the function pointers for rungeKutta (also used in splitBalance)
void writeVTKFileOfCutCell(MInt, std::vector< polyCutCell > *, const std::vector< polyEdge2D > *, const std::vector< polyVertex > *, MInt)
void getNormal(const MInt, const MInt, MFloat[])
void refineCell(const MInt) override
void computeCutPointsMb_MGC()
Computes cutpoints of zero level-set with grid edges and creates boundary cells for cut-cells.
MFloat getDistanceTetrahedron(const MFloat *const, const MInt)
void checkDiv() override
Check for divergence in case we use MB_DEBUG or debug.
MBool prepareRestart(MBool, MBool &) override
Prepare the solvers for a grid-restart.
void updateCellSurfaceDistanceVector(MInt srfcId)
correct the cell-surface distance vectors for cells near the moving boundary
void updateLinkedCells()
update the temporarly-linked cells
std::vector< std::vector< MInt > > m_azimuthalLinkedHaloCells
static void matrixProductTranspose2(MFloatScratchSpace &C, MFloatScratchSpace &A, MFloatScratchSpace &B)
C=A^t*B.
void constructGFieldPredictor()
determine the displacement of the embedded body – predictor step
void descendLevelSetValue(const MInt cellId, const MInt *const bodyIds, const MInt bodyCnt)
MFloat getDistanceSphere(const MFloat *const, const MInt)
void computeAzimuthalHaloNodalValues()
init exchange of nodal values of azimuthal periodic halo cells
MInt copyFile(const MChar *fromName, const MChar *toName)
void determineBndryCandidates()
determine all possible fluid boundary cells for a generic embedded body
void setLevelSetMbCellProperties()
determines relevant cell properties
std::vector< MFloat > m_candidateNodeValues
void balance(const MInt *const noCellsToReceiveByDomain, const MInt *const noCellsToSendByDomain, const MInt *const targetDomainsByCell, const MInt oldNoCells) override
Balance the solver.
std::map< MInt, MFloat > m_oldBndryCells
void gapHandling()
determines Gap-state, and organises GapCells
MString printTime(const MFloat t)
MFloat determineCoupling(MFloatScratchSpace &coupling)
void reIntAfterRestart(MBool) override
void updateGapBoundaryCells()
set the velocity at gap-Boundary-Cells due to the irregular movement of the gap-surface during wideni...
MFloat getDistanceNaca00XX(const MInt, const MInt)
static void matrixVectorProduct(MFloat *c, MFloatScratchSpace &A, MFloat *b)
c=A*b
void computeForceCoefficients(MFloat *&)
dummy
std::vector< MInt > m_azimuthalWasNearBndryIds
MInt getAdjacentCells(MInt cellId, MInt *adjacentCells)
retrieves all direct and diagonal fluid cell neighbours of the given cell
void rebuildReconstructionConstants(MInt cellId)
computes the reconstruction constants using inverse distance weighted least squares
MFloat distEllipsoidEllipsoid(const MInt k0, const MInt k1, MFloat *xc0, MFloat *xc1)
Compute the distance between two ellipsoids by iteratively searching the nearest point on the respect...
void setBodyQuaternions(const MInt bodyId, MFloat *bodyRotation)
MInt getNewSurfaceId()
returns a new surface id
void initAnalyticalLevelSet()
This function creats the bodyTree for analytical LevelSets.
void interpolateGapBodyVelocity()
sets the interpolated velocity for a bndryCell NOTE: all neighbors need to be available for levelset-...
void initBodyProperties()
initialize properties of the embedded body at startup
void createSurface(MInt srfcId, MInt nghbrId0, MInt nghbrId1, MInt orientation)
restores the surfaces of the given cell
void applyBoundaryConditionMb()
applies the boundary condition at all boundaries
MBool inside(MFloat x, MFloat a, MFloat b)
void writeStencil(const MInt bndryId)
void updateLevelSetOutsideBand()
computes an approximate level set value for cells outside the level-set computing band
void preTimeStep() override
Performs the preTimeStep of the FVMB solver.
MBool postSolutionStep() override
step after the solver solution Step
MFloat distancePointEllipsoid(const MFloat e[3], const MFloat y[3], MFloat x[3])
void resetSlopes()
does what it says
void prepareNextTimeStep() override
Updates the old Variables, the body positions and the increases the time.
void checkHaloCells(MInt mode=0)
Checks a couple of important properties and variables of halo-cells.
MFloat checkCentroidDiff(MInt srfcId1, MInt srfcId2)
void writeVtkErrorFile()
write flow variables as XML VTK files
void createInitialSrfcs()
computes initial set of internal grid surfaces
MFloat distancePointEllipsoidSpecial2(const MFloat e[3], const MFloat y[3], MFloat x[3])
void outputPolyData(const MInt, const std::vector< polyCutCell > *, const std::vector< polyEdge2D > *, const std::vector< polyVertex > *, MInt)
void postTimeStep() override
Performs the postTimeStep of the FVMB solver.
void setCellProperties() override
set the properties of cells and determines the state of halo cells
void removeChilds(const MInt) override
void computeVolumeFraction()
computes the volume fraction V/h^d and the level-set value in the volumetric center of all boundary c...
void correctBoundarySurfaceVariablesMb()
sets boundary surface variables to their correct values
std::vector< MInt > m_candidateNodeSet
void exchangeLinkedHaloCellsForAzimuthalReconstruction()
Create exchange for all window/halo cells which are used for the azimuthal periodic interpolation.
void updateAzimuthalMaxLevelRecCoords()
Update reconstruction coordinate for azimuthal halo cells on max level This is done because of moving...
static void matrixVectorProductTranspose(MFloat *c, MFloatScratchSpace &A, MFloat *b)
c=A^t*b
void computeCutFaces(std::vector< CutCell< nDim > > &cutCellData, const MInt maxNoSurfaces, const MInt tCutGroup)
const size_t m_memsize
Definition: scratch.h:186
This class is a ScratchSpace.
Definition: scratch.h:758
size_type size() const
Definition: scratch.h:302
pointer data()
Definition: scratch.h:289
MInt size1() const
Definition: scratch.h:299
T * getPointer() const
Deprecated: use begin() instead!
Definition: scratch.h:316
void fill(T val)
fill the scratch with a given value
Definition: scratch.h:311
pointer p
Deprecated: use [] instead!
Definition: scratch.h:315
MInt size0() const
Definition: scratch.h:298
iterator begin()
Definition: scratch.h:273
virtual MInt domainId() const
Return the domainId (rank)
Definition: solver.h:383
MPI_Comm mpiComm() const
Return the MPI communicator used by this solver.
Definition: solver.h:380
MInt solverId() const
Return the solverId.
Definition: solver.h:425
virtual MInt noDomains() const
Definition: solver.h:387
void updateDomainInfo(const MInt domainId, const MInt noDomains, const MPI_Comm mpiComm, const MString &loc)
Set new domain information.
Definition: solver.h:135
MFloat m_Re
the Reynolds number
Definition: solver.h:68
MFloat m_Ma
the Mach number
Definition: solver.h:71
Definition: iovtk.h:24
void writeVtuOutputParallel(const MString fileName, const MString geomFileName, const MInt noSolverSpecificVars=0, const MFloatScratchSpace &solverSpecificVars=MFloatScratchSpace(1, "writeVtuOutputParallel", "defaultParameter1"), const MInt noUserVars=0, const MFloatScratchSpace &userVars=MFloatScratchSpace(1, "writeVtuOutputParallel", "defaultParameter2"))
Definition: iovtk.cpp:2818
const MInt & windowCell(const MInt domainId, const MInt cellId) const
const MInt & haloCell(const MInt domainId, const MInt cellId) const
void patchRefinement(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen)
void exchangeData(T *data, const MInt dataBlockSize=1)
Exchange memory in 'data' assuming a solver size of 'dataBlockSize' per cell.
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ NETCDF
Definition: enums.h:18
SolverType
Definition: enums.h:22
@ LEVELSETMB
Definition: enums.h:275
@ BC_UNSET
Definition: enums.h:334
MInt copyFile(const MString &fromName, const MString &toName)
Copies file fromName to file toName.
Definition: functions.cpp:83
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
MBool fileExists(const MString &fileName)
Returns true if the file fileName exists, false otherwise.
Definition: functions.cpp:73
constexpr Real POW3(const Real x)
Definition: functions.h:123
constexpr Real POW2(const Real x)
Definition: functions.h:119
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
constexpr T mMin(const T &x, const T &y)
Definition: functions.h:90
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
const MInt m_revDir[6]
MInt globalTimeStep
void printAllocatedMemory(const MLong oldAllocatedBytes, const MString &solverName, const MPI_Comm comm)
Prints currently allocated memory.
MInt globalDomainId()
Return global domain id.
MInt g_timeSteps
MBool g_splitMpiComm
MBool g_multiSolverGrid
InfoOutFile m_log
std::ostream cerr0
constexpr MLong IPOW2(MInt x)
constexpr MFloat FPOW2(MInt x)
constexpr MFloat FFPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
uint32_t MUint
Definition: maiatypes.h:63
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
char MChar
Definition: maiatypes.h:56
MInt id
Definition: maiatypes.h:71
uint64_t MUlong
Definition: maiatypes.h:65
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status, const MString &name, const MString &varname)
same as MPI_Recv
int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Isend
int MPI_Barrier(MPI_Comm comm, const MString &name)
same as MPI_Barrier
int MPI_Allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgatherv
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Irecv
int MPI_Issend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Issend
int MPI_Wait(MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Wait
int MPI_Gatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gatherv
int MPI_Waitall(int count, MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Waitall
int MPI_Iallreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Iallreduce
int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Reduce
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_Alltoall(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_Alltoall
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Bcast
int MPI_Gather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Gather
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
void const MInt const MInt const MInt const MInt maxNoCells
Definition: collector.h:240
void const MInt cellId
Definition: collector.h:239
void setBoundaryVelocity(S &src, T &tgt, M &mapping, C conversion)
Setting the boundary velocity from one surface collector to the other.
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.
T cos(const T a, const T b, const T x)
Cosine slope filter.
Definition: filter.h:125
constexpr std::underlying_type< FvCell >::type p(const FvCell property)
Converts property name to underlying integer value.
std::bitset< p(FvCell::NumProperties)> BitsetType
void matrixVectorProduct(MFloat *c, MFloatScratchSpace &A, MFloat *b)
c=A*b
Definition: maiamath.h:561
void invert(MFloat *A, const MInt m, const MInt n)
Definition: maiamath.cpp:171
void computeRotationMatrix(MFloatScratchSpace &R, MFloat *q)
rotation matrix co-rotating(~inertial) frame -> body-fixed frame
Definition: maiamath.h:533
MFloat deltaFun(const MFloat r, const MFloat r0, const MFloat r1)
Definition: maiamath.h:885
void computeEnergySpectrum(MFloatScratchSpace &velocity, MIntScratchSpace &indices, const ptrdiff_t howmany, MInt locSize, MInt nx, MInt ny, MInt nz, MFloat viscosity, const MPI_Comm comm)
Compute energy spectrum on unity cube.
Definition: maiafftw.h:1051
MUint getBufferSize(const std::vector< std::vector< MInt > > &exchangeCells)
Generic exchange of data.
Definition: mpiexchange.h:681
void communicateData(const DataType *const data, const MInt noCells, const MInt *const sortedCellId, const MInt noDomains, const MInt domainId, const MPI_Comm mpiComm, const MInt *const noCellsToSendByDomain, const MInt *const noCellsToReceiveByDomain, const MInt dataBlockSize, DataType *const buffer)
Assemble given data in send buffer and communicate.
Definition: mpiexchange.h:858
void exchangeData(const MInt noNghbrDomains, const MInt *const nghbrDomains, const MInt *const noHaloCells, const MInt **const, const MInt *const noWindowCells, const MInt **const windowCells, const MPI_Comm comm, const U *const data, U *const haloBuffer, const MInt noDat=1)
Generic exchange of data.
Definition: mpiexchange.h:295
void exchangeBuffer(const MInt noExDomains, const MInt *const exDomainId, const MInt *const recvSize, const MInt *const sendSize, const MPI_Comm comm, U *const receiveBuffer, const U *const sendBuffer, const MInt noDat=1)
Generic exchange of data.
Definition: mpiexchange.h:44
void communicateBitsetData(const std::bitset< N > *const data, const MInt noCells, const MInt *const sortedCellId, const MInt noDomains, const MInt domainId, const MPI_Comm mpiComm, const MInt *const noCellsToSendByDomain, const MInt *const noCellsToReceiveByDomain, const MInt dataBlockSize, std::bitset< N > *const buffer)
Definition: mpiexchange.h:873
void reverseExchangeData(const MInt noNghbrDomains, const MInt *const nghbrDomains, const MInt *const noHaloCells, const MInt **const haloCells, const MInt *const noWindowCells, const MInt **const, const MPI_Comm comm, const U *const data, U *const windowBuffer, const MInt noDat=1)
Generic reverse exchange of data.
Definition: mpiexchange.h:400
void exchangeBitset(const std::vector< MInt > &nghbrDomains, const std::vector< std::vector< MInt > > &haloCellVec, const std::vector< std::vector< MInt > > &windowCellVec, const MPI_Comm comm, std::bitset< N > *const data, const MInt noCells, const MInt noDat=1)
Generic exchange of data.
Definition: mpiexchange.h:516
void communicateGlobalyOrderedData(DataType const *const sendData, const MInt noLocIds, const MInt noGlobalIds, const MInt nRows, const MInt nCols, const MInt noDomains, const MInt domainId, const MPI_Comm mpiComm, const MIntScratchSpace &localToGlobal, const MIntScratchSpace &dataOffsets, ScratchSpace< DataType > &recvData)
Communicate (optionally) solver-structured data sorted by a global Id.
Definition: mpiexchange.h:919
const MInt PIO_REPLACE
Definition: parallelio.h:36
const MInt PIO_INT
Definition: parallelio.h:48
const MInt PIO_FLOAT
Definition: parallelio.h:46
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54
Definition: kdtree.h:73
Definition: pointbox.h:20
Definition: contexttypes.h:19
Static indices for accessing primitive variables in nd spatial dimensions.
Definition: variables.h:224
define array structures