Loading [MathJax]/extensions/tex2jax.js
MAIA bb96820c
Multiphysics at AIA
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
fvcartesiansolverxd.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 <chrono>
10#include <cmath>
11#include <cstdio>
12#include <cstring>
13#include <ctime>
14#include <iomanip>
15#include <iostream>
16#include <map>
17#include <random>
18#include <set>
19#include <stack>
20#include <string>
21
22#include "COMM/mpioverride.h"
24#include "GRID/cartesiangrid.h"
26#include "IO/iovtk.h"
27#include "IO/parallelio.h"
28#include "UTIL/hilbert.h"
29#include "UTIL/tensor.h"
34#include "globals.h"
35#include "typetraits.h"
36
37// Required for nDim=3
38#include "UTIL/kdtree.h"
39#include "UTIL/pointbox.h"
40
41#include "fvstg.h"
42
43using namespace std;
44using namespace maia;
45using namespace maia::fv;
46
47// TODO labels:FV fix this!
48#undef RAND_MAX
49#define RAND_MAX 9999999
50
51
52template <MInt nDim_, class SysEqn>
54template <MInt nDim_, class SysEqn>
56template <MInt nDim_, class SysEqn>
58template <MInt nDim_, class SysEqn>
60template <MInt nDim_, class SysEqn>
62template <MInt nDim_, class SysEqn>
64template <MInt nDim_, class SysEqn>
66template <MInt nDim_, class SysEqn>
68template <MInt nDim_, class SysEqn>
70template <MInt nDim_, class SysEqn>
72template <MInt nDim_, class SysEqn>
73constexpr MFloat FvCartesianSolverXD<nDim_, SysEqn>::m_volumeThreshold; // for stupid PGI compiler
74
75using namespace std;
76using namespace maia;
77
78#define SWAP_ENDIAN
79
80
81/* \brief Constructor of the FV Solver: reads properties, allocates solver resources.
82 */
83template <MInt nDim_, class SysEqn>
84FvCartesianSolverXD<nDim_, SysEqn>::FvCartesianSolverXD(MInt solverId_, MInt noSpecies, const MBool* propertiesGroups,
85 maia::grid::Proxy<nDim_>& gridProxy_,
86 Geometry<nDim_>& geometry_, const MPI_Comm comm)
87 : maia::CartesianSolver<nDim, FvCartesianSolverXD<nDim_, SysEqn>>(solverId_, gridProxy_, comm, true),
88 m_geometry(&geometry_),
89 m_eps(std::numeric_limits<MFloat>::epsilon()),
90 m_noSpecies(noSpecies),
91 m_sysEqn(solverId_, noSpecies),
92 m_time(0.0),
93 PV(sysEqn().PV),
94 CV(sysEqn().CV),
95 FV(sysEqn().FV),
96 AV(sysEqn().AV),
97 SC(sysEqn().SC) {
98 TRACE();
99
100 // NOTE: everything in the constructor should be written that also inactive ranks are supported,
101 // i.e., those who do not participate in the computation. For load balancing it is
102 // required that the main initialization of all member variables and properties is performed
103 // globally
104 // const MBool isActive = gridProxy_.isActive();
105
118 m_multilevel = false;
119 m_multilevel = Context::getBasicProperty<MBool>("multilevel", AT_, &m_multilevel);
120
121 m_pressureRatioChannel = F1;
122 if(Context::propertyExists("pressureRatioChannel", m_solverId))
123 m_pressureRatioChannel = Context::getSolverProperty<MFloat>("pressureRatioChannel", m_solverId, AT_);
124 m_pressureRatioStartTimeStep = -1;
125 if(Context::propertyExists("pressureRatioStartTimeStep", m_solverId))
126 m_pressureRatioStartTimeStep = Context::getSolverProperty<MFloat>("pressureRatioStartTimeStep", m_solverId, AT_);
127 m_pressureRatioEndTimeStep = -1;
128 if(Context::propertyExists("pressureRatioEndTimeStep", m_solverId))
129 m_pressureRatioEndTimeStep = Context::getSolverProperty<MFloat>("pressureRatioEndTimeStep", m_solverId, AT_);
130
131
132 m_levelSet = propertiesGroups[LEVELSET];
133 m_levelSetMb = propertiesGroups[LEVELSETMB];
134 m_combustion = propertiesGroups[COMBUSTION];
135 m_LSSolver = propertiesGroups[LS_SOLVER];
136 m_levelSetRans = propertiesGroups[LS_RANS];
137
138 //-------------Initialize Wall Normal Output & set appropriate properties
139 m_wallNormalOutput = false;
140 if(Context::propertyExists("wallNormalOutput", m_solverId)) {
141 m_log << endl << endl << "Reading Wall Normal Output properties ... " << endl;
142 m_wallNormalOutput = Context::getSolverProperty<MBool>("wallNormalOutput", m_solverId, AT_);
143 if(m_wallNormalOutput == true) {
144 if(Context::propertyExists("useWallNormalInterpolation", m_solverId)) {
145 m_useWallNormalInterpolation = Context::getSolverProperty<MBool>("useWallNormalInterpolation", m_solverId, AT_);
146 }
147 // get the target BC Id for the output
148 m_normalBcId = Context::getSolverProperty<MInt>("normalBcId", m_solverId, AT_);
149
150 // Set Output interval
151 if(Context::propertyExists("normalOutputInterval", m_solverId)) {
152 m_normalOutputInterval = Context::getSolverProperty<MInt>("normalOutputInterval", m_solverId, AT_);
153 m_log << "normalOutputInterval = " << m_normalOutputInterval << endl;
154 } else {
155 mTerm(1, "normalOutputInterval not given in property file!");
156 }
157
158 // Set Normal length
159 if(Context::propertyExists("normalLength", m_solverId)) {
160 m_normalLength = Context::getSolverProperty<MFloat>("normalLength", m_solverId, AT_);
161 } else {
162 mTerm(1, "normalLength not given in property file!");
163 }
164
165 // Set Normal point number
166 if(Context::propertyExists("normalNoPoints", m_solverId)) {
167 m_normalNoPoints = Context::getSolverProperty<MInt>("normalNoPoints", m_solverId, AT_);
168 if(m_normalNoPoints < 2) {
169 mTerm(1, "normalNoPoints should be at least 2");
170 }
171 } else {
172 mTerm(1, "normalNoPoints not given in property file");
173 }
174
175 MInt noCoords = Context::propertyLength("normalSamplingCoords", m_solverId);
176 for(MInt c = 0; c < noCoords; c++) {
177 m_normalSamplingCoords.push_back(
178 Context::getSolverProperty<MFloat>("normalSamplingCoords", m_solverId, AT_, c));
179 }
180
181 for(MInt c = 0; c < (noCoords / 2); c++) {
182 m_normalSamplingSide.push_back(Context::getSolverProperty<MInt>("normalSamplingSide", m_solverId, AT_, c));
183 }
184 m_log << "done." << endl;
185 }
186 }
187
188 // spanwise averaged surface probes
189 // only for uniform, uncut cells, otherwise area-weighting is necessary
190 // would generally make more sense to move into postprocessing block
191 m_saSrfcProbeInterval = 0;
192 if(Context::propertyExists("saSrfcProbeInterval", m_solverId)) {
193 m_saSrfcProbeInterval =
194 Context::getSolverProperty<MInt>("saSrfcProbeInterval", m_solverId, AT_, &m_saSrfcProbeInterval);
195 if(m_saSrfcProbeInterval > 0) {
196 Context::getSolverProperty<MInt>("saSrfcProbeStart", m_solverId, AT_, &m_saSrfcProbeStart);
197 }
198 m_saSrfcProbeDir = "";
199 if(Context::propertyExists("saSrfcProbeDir", m_solverId)) {
200 m_saSrfcProbeDir = Context::getSolverProperty<MString>("saSrfcProbeDir", m_solverId, AT_, &m_saSrfcProbeDir);
201 }
202 }
203
204 // Sandpaper Tripping
205 m_useSandpaperTrip = false;
206 if(Context::propertyExists("useSandpaperTrip", m_solverId)) {
207 m_useSandpaperTrip = Context::getSolverProperty<MBool>("useSandpaperTrip", m_solverId, AT_, &m_useSandpaperTrip);
208 }
209
210 // Channel Volume Forcing
211 m_useChannelForce = false;
212 if(Context::propertyExists("useChannelForce", m_solverId)) {
213 m_useChannelForce = Context::getSolverProperty<MBool>("useChannelForce", m_solverId, AT_, &m_useChannelForce);
214 }
215
223 m_isEEGas = Context::getSolverProperty<MBool>("EEGas", m_solverId, AT_, &m_isEEGas);
224
225 // sets detailed chemistry model specific properties
226 IF_CONSTEXPR(isDetChem<SysEqn>) setAndAllocateDetailedChemistryProperties();
227
228 // set the fv-Collector type to reduce fv-Cell memory!
229 MInt fvCollectorMode = 0;
230 IF_CONSTEXPR(isDetChem<SysEqn>) fvCollectorMode = 1;
231 if(m_combustion) {
232 fvCollectorMode = 2;
233 }
234 if(m_isEEGas) {
235 fvCollectorMode = 3;
236 }
237
238 MInt fvTimeStepMode = 0;
250 m_dualTimeStepping = false;
251 m_dualTimeStepping = Context::getSolverProperty<MBool>("dualTimeStepping", m_solverId, AT_, &m_dualTimeStepping);
252
264 m_localTS = false;
265 m_localTS = Context::getSolverProperty<MBool>("localTimeStepping", m_solverId, AT_, &m_localTS);
266
267 if(m_dualTimeStepping) {
268 fvTimeStepMode = 2;
269 }
270 if(m_localTS) {
271 fvTimeStepMode = 1;
272 }
273
274 const MLong oldAllocatedBytes = allocatedBytes();
275 m_cells.setFvCollectorType(fvCollectorMode);
276 m_cells.setFvTimeStepType(fvTimeStepMode);
277 m_cells.setNoCVariables(CV->noVariables, m_noSpecies);
278 m_cells.setNoPVariables(PV->noVariables);
279 m_cells.setNoFVariables(FV->noVariables);
280 m_cells.setNoAVariables(AV->noVariables);
281 m_cells.isMultilevel(m_multilevel);
282 m_cells.reset(grid().maxNoCells());
283 m_cells.append(c_noCells());
284 m_totalnosplitchilds = 0;
285 m_totalnoghostcells = 0;
286
287 for(MInt c = 0; c < a_noCells(); c++) {
288 a_resetPropertiesSolver(c);
289 }
290
291 // Copy grid-properties to the fvcellcollector
292 copyGridProperties();
293
294 initializeFvCartesianSolver(propertiesGroups);
295
296 // Initialize postprocessing
297 // initPostProcessingSolver(&grid().raw());
298
299 // communication:
300 allocateCommunicationMemory();
301
302 // physical and other testcase specific properties:
303 setTestcaseProperties();
304
305 // in/output:
306 setInputOutputProperties();
307
308 // numerical method:
309 setNumericalProperties();
310
311 // adaptation:
312 setAndAllocateAdaptationProperties();
313
314 // sponge layer:
315 setAndAllocateSpongeLayerProperties();
316
317 // jet:
318 setAndAllocateJetProperties();
319
320 // combustion GequPv model (G-equation)
321 setAndAllocateCombustionGequPvProperties();
322
323 // combustion thickened flame (TF)
324 setAndAllocateCombustionTFProperties();
325
326 // zonal and rans properties
327 setAndAllocateZonalProperties();
328
329 // wall-model properties
330 readWallModelProperties();
331
332 // allocate general FvCartesianSolver memory
333 allocateAndInitSolverMemory();
334
335 // creates the FV Solver timers
336 initializeTimers();
337
338 IF_CONSTEXPR(isDetChem<SysEqn>) if(m_heatReleaseDamp) initHeatReleaseDamp();
339
340 if(m_geometry->m_parallelGeometry) {
341 this->receiveWindowTriangles();
342 }
343
344 this->checkNoHaloLayers();
345
346 // old constructor
347 // initialize
348 m_physicalTime = 0.;
349 m_gridConvergence = false;
350 m_counterCx = 0;
351 m_storeNghbrIds = nullptr;
352 m_identNghbrIds = nullptr;
353
354 // set function pointers
355 if(m_limiter) {
356 m_reconstructSurfaceData = &FvCartesianSolverXD::computeLimitedSurfaceValues;
357 m_log << "* Using limited surface data reconstruction." << endl;
358 } else {
359 switch(string2enum(m_surfaceValueReconstruction)) {
360 case HOCD:
361 m_reconstructSurfaceData = &FvCartesianSolverXD::computeSurfaceValues;
362 m_log << "* Using unlimited high-order surface data reconstruction." << endl;
363 break;
364 case HOCD_LIMITED:
365 m_reconstructSurfaceData = &FvCartesianSolverXD::computeSurfaceValuesLimited;
366 m_log << "* Using limited high-order surface data reconstruction." << endl;
367 break;
368 case LOCD:
369 m_reconstructSurfaceData = &FvCartesianSolverXD::computeSurfaceValuesLOCD;
370 m_log << "* Using unlimited low-order (pressure)/high-order surface data reconstruction." << endl;
371 break;
374 m_log << "* Using sensor slope-limited high-order surface data reconstruction." << endl;
375 break;
378 m_log << "* Using manual slope-limited high-order surface data reconstruction." << endl;
379 this->setCellProperties();
380 this->initComputeSurfaceValuesLimitedSlopesMan1();
381 break;
382 default: {
383 stringstream errorMessage;
384 errorMessage << "FvCartesianSolverXD::FvCartesianSolverXD(): switch variable "
385 "'m_surfaceValueReconstruction' with value "
386 << m_surfaceValueReconstruction << " not matching any case." << endl;
387 mTerm(1, AT_, errorMessage.str());
388 }
389 }
390 }
391
392 printAllocatedMemory(oldAllocatedBytes, "FvCartesianSolverXD", this->globalMpiComm());
393
394 m_fvBndryCnd = new FvBndryCndXD<nDim_, SysEqn>(this);
395
396 if(isActive()) {
397 // compute min and max coordinates in the grid
398 computeDomainAndSpongeDimensions();
399 }
400
401 // set infinity variabbles once and for all!
402 setInfinityState();
403
404 // set rotation properties for azimuthal periodic exchange of velocity vector
405 if(grid().azimuthalPeriodicity()) {
406 m_rotIndVarsPV.assign(PV->noVariables, 0);
407 m_rotIndVarsPV[PV->VV[grid().azimuthalDir(0)]] = 1;
408 m_rotIndVarsPV[PV->VV[grid().azimuthalDir(1)]] = 1;
409 m_rotIndVarsCV.assign(CV->noVariables, 0);
410 m_rotIndVarsCV[CV->RHO_VV[grid().azimuthalDir(0)]] = 1;
411 m_rotIndVarsCV[CV->RHO_VV[grid().azimuthalDir(1)]] = 1;
412 }
413}
414
415/* Computes heat release for OUTPUT-File
416Author: Pedro, Borja, Betreuer: Herff, Sohel
417Contact: borja.pedro@rwth-aachen.de
418*/
419template <MInt nDim_, class SysEqn>
421 MFloatScratchSpace& cSquared,
422 MFloatScratchSpace& drhodt) {
423 for(MInt cellId = 0; cellId < a_noCells(); ++cellId) {
424 QeI[cellId] = F0;
425 QeIII[cellId] = F0;
426 cSquared[cellId] = F0;
427 drhodt[cellId] = F0;
428
429 IF_CONSTEXPR(isDetChem<SysEqn>) {
430 const MFloat dt = m_timeStep;
431
432 MFloat oldVelPow2 = F0;
433 for(MInt dim = 0; dim < nDim; dim++)
434 oldVelPow2 += POW2(a_oldVariable(cellId, CV->RHO_VV[dim]) / a_oldVariable(cellId, CV->RHO));
435
436 MFloat oldT = F0;
437#if defined(WITH_CANTERA)
438 sysEqn().iterateTemperature(oldT, &a_oldVariable(cellId, 0), &a_pvariable(cellId, 0), &a_avariable(cellId, 0),
439 oldVelPow2);
440#endif
441
442 const MFloat oldP = a_oldVariable(cellId, CV->RHO) * oldT * m_gasConstant / a_avariable(cellId, AV->W_MEAN);
443 const MFloat curP = a_pvariable(cellId, PV->P);
444 const MFloat dpdt = (curP - oldP) / dt;
445
446 MFloat divU = 0.0;
447 for(MInt dim = 0; dim < nDim; dim++) {
448 divU += a_slope(cellId, PV->VV[dim], dim);
449 }
450
451 MFloat DrhoDt = a_pvariable(cellId, PV->RHO) * divU;
452 MFloat UgradRho = 0.0;
453 MFloat UgradP = 0.0;
454 for(MInt dim = 0; dim < nDim; dim++) {
455 UgradRho = a_pvariable(cellId, PV->VV[dim]) * a_slope(cellId, PV->RHO, dim);
456 UgradP = a_pvariable(cellId, PV->VV[dim]) * a_slope(cellId, PV->P, dim);
457 }
458
459 const MFloat DpDt = dpdt + UgradP;
460
461 drhodt[cellId] = DrhoDt + UgradRho;
462 cSquared[cellId] = a_avariable(cellId, AV->GAMMA) * curP / a_variable(cellId, CV->RHO);
463 QeI[cellId] = DpDt - cSquared[cellId] * DrhoDt;
464 QeIII[cellId] = cSquared[cellId] * UgradRho - UgradP;
465 }
466 }
467}
468
469/* Adds the computed species reaction rates to the LHS of conservation equations.
470Computes the heat release term as:
471w_t = -SUMM(formationEnthalpy * reactionRate)
472and adds it to the energy conservation equation
473Author: Pedro, Borja, Betreuer: Herff, Sohel
474Contact: borja.pedro@rwth-aachen.de
475*/
476template <MInt nDim_, class SysEqn>
478 const MUint noSpecies = m_noSpecies;
479
480 calculateHeatRelease();
481
482 for(MInt cellId = 0; cellId < a_noCells(); ++cellId) {
483 if(a_isBndryGhostCell(cellId)) continue;
484 if(a_isHalo(cellId)) continue;
485
486 const MFloat dampeningFactor = m_heatReleaseDamp ? m_dampFactor[cellId] : F1;
487
488 // Add species reaction rates to species transport equation
489 for(MUint s = 0; s < noSpecies; ++s) {
490 a_rightHandSide(cellId, CV->RHO_Y[s]) -=
491 dampeningFactor * a_cellVolume(cellId) * a_speciesReactionRate(cellId, s);
492 }
493
494 a_rightHandSide(cellId, CV->RHO_E) -= a_cellVolume(cellId) * m_heatRelease[cellId];
495 }
496}
497
498template <MInt nDim_, class SysEqn>
500 MInt dampDist = 9;
501 if(Context::propertyExists("dampDist", m_solverId))
502 dampDist = Context::getSolverProperty<MInt>("dampDist", m_solverId, AT_, &dampDist);
503
504 MInt noDampedWalls = 0;
505 if(Context::propertyExists("noDampedWalls", m_solverId))
506 noDampedWalls = Context::getSolverProperty<MInt>("noDampedWalls", m_solverId, AT_, &noDampedWalls);
507
508 if(noDampedWalls == 0)
509 mTerm(1, "initHeatReleaseDamp() has been called, but noDampedWalls = 0. Check properties file.");
510
511 std::vector<MString> filename;
512 for(MInt Id = 0; Id < noDampedWalls; Id++) {
513 stringstream name;
514 name << "dampedWall." << Id;
515 filename.push_back(name.str());
516 }
517
518 m_dampFactor.assign(a_noCells(), F1);
519
520 for(MUint Id = 0; Id < filename.size(); Id++) {
521 vector<MInt> markedCells;
522 MIntScratchSpace propDist(grid().raw().treeb().size(), AT_, "propDist");
523 propDist.fill(numeric_limits<MInt>::max());
524
525 IF_CONSTEXPR(nDim == 2) {
526 Geometry2D* auxGeom = new Geometry2D(0, filename[Id], mpiComm());
527 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
528 const MFloat cellHalfLength = c_cellLengthAtLevel(a_level(cellId) + 1);
529 if(!c_noChildren(cellId) && auxGeom->isOnGeometry(cellHalfLength, &a_coordinate(cellId, 0), "SAT"))
530 if(grid().tree().solver2grid(cellId) > -1) markedCells.push_back(grid().tree().solver2grid(cellId));
531 }
532 }
533 IF_CONSTEXPR(nDim == 3) {
534 Geometry3D* auxGeom = new Geometry3D(0, filename[Id], mpiComm());
535 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
536 const MFloat cellHalfLength = c_cellLengthAtLevel(a_level(cellId) + 1);
537 if(!c_noChildren(cellId) && auxGeom->isOnGeometry(cellHalfLength, &a_coordinate(cellId, 0), "SAT"))
538
539 if(grid().tree().solver2grid(cellId) > -1) markedCells.push_back(grid().tree().solver2grid(cellId));
540 }
541 }
542
543 MLong tmp = markedCells.size();
544 MPI_Allreduce(MPI_IN_PLACE, &tmp, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "tmp");
545 m_log << " overall cells on damping region: " << tmp << endl;
546 tmp = 0;
547
548 grid().raw().propagateDistance(markedCells, propDist, dampDist);
549
550 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
551 if(a_isBndryGhostCell(cellId)) continue;
552 const MInt gridCellId = grid().tree().solver2grid(cellId);
553 if(gridCellId < 0) continue;
554 if(propDist[gridCellId] != numeric_limits<MInt>::max()) {
555 m_dampFactor[cellId] = (MFloat)propDist[gridCellId] / ((MFloat)dampDist);
556 tmp++;
557 }
558 }
559
560 MPI_Allreduce(MPI_IN_PLACE, &tmp, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "tmp");
561 m_log << " overall damped cells: " << tmp << endl;
562 }
563}
564
565
566//-----------------------------------------------------------------------------
567/* Set and allocates all important values and properties concerning the detailed chemistry model
568Author: Pedro, Borja, Betreuer: Herff, Sohel
569Contact: borja.pedro@rwth-aachen.de
570*/
571template <MInt nDim_, class SysEqn>
572template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
574 TRACE();
575
576 if(domainId() == 0) cout << "Starting a full detailed chemistry simulation." << endl;
577
578 m_detChemExtendedOutput = true;
579 m_detChemExtendedOutput =
580 Context::getSolverProperty<MBool>("detChemExtendedOutput", m_solverId, AT_, &m_detChemExtendedOutput);
581
582 m_acousticAnalysis = false;
583 m_acousticAnalysis = Context::getSolverProperty<MBool>("acousticAnalysis", m_solverId, AT_, &m_acousticAnalysis);
584
585 m_YInfinity = nullptr;
586 m_molarMass = nullptr;
587 m_fMolarMass = nullptr;
588 m_standardHeatFormation = nullptr;
589
590 m_detChem.infSpeciesName = nullptr;
591 m_detChem.infSpeciesMassFraction = nullptr;
592
593
594 m_heatReleaseDamp = true;
595 m_heatReleaseDamp = Context::getSolverProperty<MBool>("heatReleaseDamp", m_solverId, AT_, &m_heatReleaseDamp);
596
597 m_detChem.hasChemicalReaction =
598 Context::getSolverProperty<MBool>("hasChemicalReaction", m_solverId, AT_, &m_detChem.hasChemicalReaction);
599
600 // Infinity Values
601 m_detChem.infTemperature =
602 Context::getSolverProperty<MFloat>("infTemperature", m_solverId, AT_, &m_detChem.infTemperature);
603 m_detChem.infVelocity = Context::getSolverProperty<MFloat>("infVelocity", m_solverId, AT_, &m_detChem.infVelocity);
604 m_detChem.infPressure = Context::getSolverProperty<MFloat>("infPressure", m_solverId, AT_, &m_detChem.infPressure);
605
606 m_detChem.laminarFlameSpeedFactor = 1.0;
607 m_detChem.laminarFlameSpeedFactor = Context::getSolverProperty<MFloat>("laminarFlameSpeedFactor", m_solverId, AT_,
608 &m_detChem.laminarFlameSpeedFactor);
609
610 const MInt speciesArrayLength = Context::propertyLength("infSpeciesName", m_solverId);
611 const MInt massFractionArrayLength = Context::propertyLength("infSpeciesMassFraction", m_solverId);
612
613 ASSERT(speciesArrayLength == massFractionArrayLength,
614 "Check speciesArrayLength and massFractionArrayLength. Unequal.");
615
616 mAlloc(m_detChem.infSpeciesName, speciesArrayLength, "infSpeciesName", AT_);
617 mAlloc(m_detChem.infSpeciesMassFraction, massFractionArrayLength, "infSpeciesMassFraction", AT_);
618
619 // Array containing species mass fractions at infinity (uniform)
620 mAlloc(m_YInfinity, PV->m_noSpecies, "m_YInfinity", F0, AT_);
621 mAlloc(m_molarMass, PV->m_noSpecies, "m_molarMass", 0.0, AT_);
622 mAlloc(m_fMolarMass, PV->m_noSpecies, "m_fMolarMass", 0.0, AT_);
623 mAlloc(m_standardHeatFormation, PV->m_noSpecies, "m_standardHeatFormation", 0.0, AT_);
624
625 MFloat summSpecies = F0;
626 for(MInt i = 0; i < speciesArrayLength; ++i) {
627 m_detChem.infSpeciesName[i] = Context::getSolverProperty<MString>("infSpeciesName", m_solverId, AT_, i);
628 m_detChem.infSpeciesMassFraction[i] =
629 Context::getSolverProperty<MFloat>("infSpeciesMassFraction", m_solverId, AT_, i);
630 summSpecies += m_detChem.infSpeciesMassFraction[i];
631 }
632
633 ASSERT(summSpecies - F1 < m_eps,
634 "Initial species mass fraction composition does not equal 1. Check properties file.");
635
636 m_detChem.infPhi = Context::getSolverProperty<MFloat>("infPhi", m_solverId, AT_, &m_detChem.infPhi);
637
638 // Get the name of the reaction mechanism for detailed chemistry computation
639 m_detChem.reactionMechanism =
640 Context::getSolverProperty<MString>("reactionMechanism", m_solverId, AT_, &m_detChem.reactionMechanism);
641
642 m_detChem.phaseName = Context::getSolverProperty<MString>("phaseName", m_solverId, AT_, &m_detChem.phaseName);
643
644 m_detChem.transportModel =
645 Context::getSolverProperty<MString>("transportModel", m_solverId, AT_, &m_detChem.transportModel);
646
647 for(MUint s = 0; s < PV->m_noSpecies; ++s) {
648 m_speciesName.push_back(sysEqn().m_species->speciesName[s]);
649 m_molarMass[s] = sysEqn().m_species->molarMass[s];
650 m_fMolarMass[s] = sysEqn().m_species->fMolarMass[s];
651 m_standardHeatFormation[s] = sysEqn().m_species->standardHeatFormation[s];
652 }
653
654 // Fill m_YInfinity with non-zero values given in the properties file
655 for(MInt i = 0; i < speciesArrayLength; ++i) {
656 const MString species = m_detChem.infSpeciesName[i];
657 const MInt speciesNameFound = sysEqn().m_species->speciesMap.count(species);
658 if(speciesNameFound == true) {
659 const MInt speciesIndex = sysEqn().m_species->speciesMap[species];
660 m_YInfinity[speciesIndex] = m_detChem.infSpeciesMassFraction[i];
661 } else {
662 mTerm(1, AT_, "Species name given in the properties file could not be found in the reaction mechanism.");
663 }
664 }
665
666 if(domainId() == 0) cout << "Allocation of detailed chemistry primary values done." << endl;
667
668 initCanteraObjects();
669
670 m_oneDimFlame = std::make_unique<OneDFlame>(m_detChem.infTemperature, m_detChem.infPressure, m_YInfinity, domainId(),
671 m_solverId, m_speciesName);
672
673#if defined(WITH_CANTERA)
674 m_oneDimFlame->setCanteraObjects(m_canteraSolution, m_canteraThermo, m_canteraKinetics, m_canteraTransport);
675#endif
676
677 m_oneDimFlame->run();
678
679 m_oneDimFlame->log(c_cellLengthAtLevel(maxRefinementLevel()));
680}
681
687template <MInt nDim_, class SysEqn>
688template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
690#if defined(WITH_CANTERA)
691 m_canteraSolution = Cantera::newSolution(m_detChem.reactionMechanism, m_detChem.phaseName, m_detChem.transportModel);
692 m_canteraThermo = m_canteraSolution->thermo();
693 m_canteraTransport = m_canteraSolution->transport();
694 m_canteraKinetics = m_canteraSolution->kinetics();
695#endif
696}
697
698
703#if defined(WITH_CANTERA)
704template <MInt nDim_, class SysEqn>
705template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
707 const MInt noSurfaces = a_noSurfaces();
708
709 const MFloat* const RESTRICT surfaceVars = ALIGNED_F(&a_surfaceVariable(0, 0, 0));
710 MFloat* const RESTRICT surfaceCoefficients = hasSC ? ALIGNED_F(&a_surfaceCoefficient(0, 0)) : nullptr;
711
712 const MInt noPVars = PV->noVariables;
713 const MUint noSurfaceCoefficients = hasSC ? SC->m_noSurfaceCoefficients : 0;
714 const MInt surfaceVarMemory = 2 * PV->noVariables;
715
716 for(MInt srfcId = 0; srfcId < noSurfaces; ++srfcId) {
717 const MInt offset = srfcId * surfaceVarMemory;
718 const MFloat* const RESTRICT vars0 = ALIGNED_F(surfaceVars + offset);
719 const MFloat* const RESTRICT vars1 = ALIGNED_F(vars0 + noPVars);
720
721 const MInt coefficientOffset = srfcId * noSurfaceCoefficients;
722 MFloat* const RESTRICT srfcCoeff = hasSC ? ALIGNED_F(surfaceCoefficients + coefficientOffset) : nullptr;
723 // MFloat* const RESTRICT srfcCoeff = hasSC ? ALIGNED_F(&a_srfcCoeffs(srfcId, 0)) : nullptr;
724
725 sysEqn().computeSurfaceCoefficients(m_RKStep, vars0, vars1, srfcCoeff, m_canteraThermo, m_canteraTransport);
726 }
727}
728#endif
729
734#if defined(WITH_CANTERA)
735template <MInt nDim_, class SysEqn>
736template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
738 Cantera::IdealGasReactor zeroD_reactor;
739 zeroD_reactor.insert(m_canteraSolution);
740
741 Cantera::ReactorNet zeroD_reactorNet;
742 zeroD_reactorNet.setVerbose(false);
743 zeroD_reactorNet.addReactor(zeroD_reactor);
744 zeroD_reactorNet.setTolerances(1e-9, 1e-9);
745
746 const MUint noCells = a_noCells();
747 const MUint noPVars = PV->noVariables;
748 const MUint noAVars = hasAV ? AV->noVariables : 0;
749
750 MFloat* const RESTRICT pvars = &a_pvariable(0, 0);
751 MFloat* const RESTRICT reactionRates = &a_speciesReactionRate(0, 0);
752 MFloat* const RESTRICT avars = hasAV ? &a_avariable(0, 0) : nullptr;
753
754 for(MUint cellId = 0; cellId < noCells; ++cellId) {
755 // Skip halo cells
756 if(a_isHalo(cellId)) {
757 for(MUint s = 0; s < PV->m_noSpecies; ++s) {
758 a_speciesReactionRate(cellId, s) = F0;
759 }
760 continue;
761 }
762
763 const MUint cellPVarOffset = cellId * noPVars;
764 const MUint cellAVarOffset = hasAV ? cellId * noAVars : 0;
765 const MUint reactionRateOffset = cellId * PV->m_noSpecies;
766
767 const MFloat* const RESTRICT pvarsCell = pvars + cellPVarOffset;
768 const MFloat* const RESTRICT avarsCell = hasAV ? avars + cellAVarOffset : nullptr;
769 MFloat* const RESTRICT reactionRatesCell = reactionRates + reactionRateOffset;
770
771 sysEqn().computeSpeciesReactionRates(m_timeStep, a_cellVolume(cellId), pvarsCell, avarsCell, reactionRatesCell,
772 &zeroD_reactor, &zeroD_reactorNet, m_canteraSolution, m_canteraThermo);
773 }
774}
775#endif
776
777/* Computation of relevant detailed chemistry values in the main integration loop
778Author: Pedro, Borja, Betreuer: Herff, Sohel
779Contact: borja.pedro@rwth-aachen.de
780*/
781template <MInt nDim_, class SysEqn>
782template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
784#if defined(WITH_CANTERA)
785 computeSurfaceCoefficients();
786#endif
787}
788
789
794#if defined(WITH_CANTERA)
795template <MInt nDim_, class SysEqn>
796template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
798 const MUint noCells = a_noCells();
799 const MUint noPVars = PV->noVariables;
800 const MUint noAVars = hasAV ? AV->noVariables : 0;
801
802 const MFloat* const RESTRICT pvars = &a_pvariable(0, 0);
803 MFloat* const RESTRICT avars = hasAV ? &a_avariable(0, 0) : nullptr;
804
805 for(MUint cellId = 0; cellId < noCells; ++cellId) {
806 const MUint cellPVarOffset = cellId * noPVars;
807 const MUint cellAVarOffset = hasAV ? cellId * noAVars : 0;
808
809 const MFloat* const RESTRICT pvarsCell = pvars + cellPVarOffset;
810 MFloat* const RESTRICT avarsCell = hasAV ? avars + cellAVarOffset : nullptr;
811
812 sysEqn().computeGamma(pvarsCell, avarsCell, m_canteraThermo);
813 }
814}
815#endif
816
822template <MInt nDim_, class SysEqn>
823template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
825 const MUint noCells = a_noCells();
826 const MUint noCVars = CV->noVariables;
827 const MUint noAVars = hasAV ? AV->noVariables : 0;
828
829 MFloat* const RESTRICT cvars = &a_variable(0, 0);
830 MFloat* const RESTRICT avars = hasAV ? &a_avariable(0, 0) : nullptr;
831
832 for(MUint cellId = 0; cellId < noCells; ++cellId) {
833 const MUint cellCVarOffset = cellId * noCVars;
834 const MUint cellAVarOffset = hasAV ? cellId * noAVars : 0;
835
836 const MFloat* const RESTRICT cvarsCell = cvars + cellCVarOffset;
837 MFloat* const RESTRICT avarsCell = hasAV ? avars + cellAVarOffset : nullptr;
838
839 sysEqn().computeMeanMolarWeight_CV(cvarsCell, avarsCell);
840 }
841}
842
848template <MInt nDim_, class SysEqn>
849template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
851 const MUint noCells = a_noCells();
852 const MUint noPVars = PV->noVariables;
853 const MUint noAVars = hasAV ? AV->noVariables : 0;
854
855 MFloat* const RESTRICT pvars = &a_pvariable(0, 0);
856 MFloat* const RESTRICT avars = hasAV ? &a_avariable(0, 0) : nullptr;
857
858 for(MUint cellId = 0; cellId < noCells; ++cellId) {
859 const MUint cellPVarOffset = cellId * noPVars;
860 const MUint cellAVarOffset = hasAV ? cellId * noAVars : 0;
861
862 const MFloat* const RESTRICT pvarsCell = pvars + cellPVarOffset;
863 MFloat* const RESTRICT avarsCell = hasAV ? avars + cellAVarOffset : nullptr;
864
865 sysEqn().computeMeanMolarWeight_PV(pvarsCell, avarsCell);
866 }
867}
868
873template <MInt nDim_, class SysEqn>
874template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
876 const MFloat* const cvarsCell = &a_variable(cellId, 0);
877 MFloat* const avarsCell = hasAV ? &a_avariable(cellId, 0) : nullptr;
878
879 sysEqn().computeMeanMolarWeight_CV(cvarsCell, avarsCell);
880}
881
882template <MInt nDim_, class SysEqn>
883template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
885 const MFloat* const pvarsCell = &a_pvariable(cellId, 0);
886 MFloat* const avarsCell = hasAV ? &a_avariable(cellId, 0) : nullptr;
887
888 sysEqn().computeMeanMolarWeight_PV(pvarsCell, avarsCell);
889}
890
894template <MInt nDim_, class SysEqn>
895template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
897 const MInt majorSpeciesIndex = sysEqn().m_species->majorSpeciesIndex;
898
899 for(MInt cellId = 0; cellId < a_noCells(); ++cellId) {
900 MFloat massFractionSum = F0;
901 for(MInt s = 0; s < m_noSpecies; ++s) {
902 if(s == majorSpeciesIndex) {
903 continue;
904 }
905 massFractionSum += a_variable(cellId, CV->RHO_Y[s]);
906 }
907 a_variable(cellId, CV->RHO_Y[majorSpeciesIndex]) = a_variable(cellId, CV->RHO) - massFractionSum;
908 }
909}
910
913template <MInt nDim_, class SysEqn>
915 TRACE();
916
917 // Deallocate all previous communication buffers
918 mDeallocate(m_maxLevelHaloCells);
919 mDeallocate(m_maxLevelWindowCells);
920 mDeallocate(m_noMaxLevelHaloCells);
921 mDeallocate(m_noMaxLevelWindowCells);
922 mDeallocate(m_sendBuffers);
923 mDeallocate(m_receiveBuffers);
924 mDeallocate(m_mpi_request);
925 mDeallocate(m_sendBuffersNoBlocking);
926 mDeallocate(m_receiveBuffersNoBlocking);
927 mDeallocate(m_mpi_sendRequest);
928 mDeallocate(m_mpi_receiveRequest);
929
930 // Init all communication properties to false
931 m_nonBlockingComm = false;
932
933 // Allocate memory and really initialize communication properties
934 if(noNeighborDomains() > 0 && isActive()) {
935 ScratchSpace<MInt> haloCellsCnt(noNeighborDomains(), AT_, "noHaloCells");
936 ScratchSpace<MInt> windowCellsCnt(noNeighborDomains(), AT_, "noWindowCells");
937 MInt totalNoWindowCells = 0;
938 MInt totalNoHaloCells = 0;
939 for(MInt d = 0; d < noNeighborDomains(); d++) {
940 haloCellsCnt[d] = noHaloCells(d);
941 totalNoHaloCells += noHaloCells(d);
942 windowCellsCnt[d] = noWindowCells(d);
943 totalNoWindowCells += noWindowCells(d);
944 }
945
946 MPI_Allreduce(MPI_IN_PLACE, &totalNoWindowCells, 1, type_traits<MInt>::mpiType(), MPI_MAX, mpiComm(), AT_,
947 "MPI_IN_PLACE", "totalNoWindowCells");
948 MPI_Allreduce(MPI_IN_PLACE, &totalNoHaloCells, 1, type_traits<MInt>::mpiType(), MPI_MAX, mpiComm(), AT_,
949 "MPI_IN_PLACE", "totalNoHaloCells");
950
951 stringstream message;
952 message << "Solver #" << solverId() << " - maximum number of window cells among ranks: " << totalNoWindowCells
953 << std::endl;
954 message << "Solver #" << solverId() << " - maximum number of halo cells among ranks: " << totalNoHaloCells
955 << std::endl;
956 m_log << message.str();
957 cerr0 << message.str();
958
959 mAlloc(m_maxLevelHaloCells, noNeighborDomains(), &haloCellsCnt[0], "m_maxLevelHaloCells", AT_);
960 mAlloc(m_maxLevelWindowCells, noNeighborDomains(), &windowCellsCnt[0], "m_maxLevelWindowCells", AT_);
961 mAlloc(m_noMaxLevelHaloCells, noNeighborDomains(), "m_noMaxLevelHaloCells", 0, AT_);
962 mAlloc(m_noMaxLevelWindowCells, noNeighborDomains(), "m_noMaxLevelWindowCells", 0, AT_);
963
964 mAlloc(m_sendBuffers, noNeighborDomains(), &windowCellsCnt[0], m_dataBlockSize, "m_sendBuffers", AT_);
965 mAlloc(m_receiveBuffers, noNeighborDomains(), &haloCellsCnt[0], m_dataBlockSize, "m_receiveBuffers", AT_);
966 mAlloc(m_mpi_request, noNeighborDomains(), "m_mpi_request", AT_);
967
968 m_nonBlockingComm = Context::getSolverProperty<MBool>("nonBlockingComm", m_solverId, AT_, &m_nonBlockingComm);
969
970 if(g_splitMpiComm && !m_nonBlockingComm) {
971 mTerm(1, "Activate nonBlockingComm to make split MPI communication work (splitMpiComm).");
972 }
973
974 // Allocate space for non-blocking send and receive buffers:
975 if(m_nonBlockingComm) {
976 mAlloc(m_sendBuffersNoBlocking, noNeighborDomains(), &windowCellsCnt[0], m_dataBlockSize,
977 "m_sendBuffersNoBlocking", AT_);
978 mAlloc(m_receiveBuffersNoBlocking, noNeighborDomains(), &haloCellsCnt[0], m_dataBlockSize,
979 "m_receiveBuffersNoBlocking", AT_);
980 mAlloc(m_mpi_receiveRequest, noNeighborDomains(), "m_mpi_receiveRequest ", AT_);
981 mAlloc(m_mpi_sendRequest, noNeighborDomains(), "m_mpi_sendRequest", AT_);
982 for(MInt i = 0; i < noNeighborDomains(); i++) {
983 m_mpi_receiveRequest[i] = MPI_REQUEST_NULL;
984 m_mpi_sendRequest[i] = MPI_REQUEST_NULL;
985 }
986 }
987 }
988}
989
990/* \brief copies grid-properties to the fvcellcollector
991 * This includes the coordinates, the level, IsHalo and IsPeriodic-properties
992 */
993template <MInt nDim_, class SysEqn>
995 // a) Copy coordinates from grid-tree to fvcellcollector
996 for(MInt id = 0; id < a_noCells(); ++id) {
997 assertValidGridCellId(id);
998 for(MInt dir = 0; dir < nDim; ++dir) {
999 a_coordinate(id, dir) = c_coordinate(id, dir);
1000 }
1001 }
1002
1003 // b) Copy level from grid-tree to fvcellcollector
1004 for(MInt id = 0; id < a_noCells(); ++id) {
1005 a_level(id) = c_level(id);
1006 }
1007
1008 // c) Initialize Properties
1009 for(MInt c = 0; c < a_noCells(); c++) {
1010 a_isHalo(c) = false;
1011 a_isWindow(c) = false;
1012 a_isPeriodic(c) = false;
1013 }
1014
1015 // d) Set Properties for valid-grid-cells
1016 for(MInt i = 0; i < noNeighborDomains(); i++) {
1017 for(MInt c = 0; c < noHaloCells(i); c++) {
1018 a_isHalo(haloCellId(i, c)) = true;
1019 }
1020 }
1021 // Azimuthal periodicity exchange halos
1022 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
1023 for(MInt c = 0; c < grid().noAzimuthalHaloCells(i); c++) {
1024 a_isHalo(grid().azimuthalHaloCell(i, c)) = true;
1025 }
1026 }
1027 for(MInt c = 0; c < grid().noAzimuthalUnmappedHaloCells(); c++) {
1028 a_isHalo(grid().azimuthalUnmappedHaloCell(c)) = true;
1029 }
1030
1031 // e) Set Properties for valid-grid-cells
1032 for(MInt i = 0; i < noNeighborDomains(); i++) {
1033 for(MInt c = 0; c < noWindowCells(i); c++) {
1034 a_isWindow(windowCellId(i, c)) = true;
1035 }
1036 }
1037 // Azimuthal periodicity exchange windows
1038 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
1039 for(MInt c = 0; c < grid().noAzimuthalWindowCells(i); c++) {
1040 a_isWindow(grid().azimuthalWindowCell(i, c)) = true;
1041 }
1042 }
1043
1044 // Inactive can only have halo cells, however noNeighborDomains=-1
1045 if(!isActive()) {
1046 for(MInt c = 0; c < a_noCells(); c++) {
1047 a_isHalo(c) = true;
1048 }
1049 }
1050
1051 for(MInt id = 0; id < a_noCells(); ++id) {
1052 // if (a_hasProperty( id , SolverCell::IsSplitChild )) continue;
1053 assertValidGridCellId(id);
1054 a_isPeriodic(id) = grid().isPeriodic(id);
1055 }
1056}
1057
1058
1059/* \brief Initializes the properties of the FvCartesianSolver.
1060 */
1061template <MInt nDim_, class SysEqn>
1063 TRACE();
1064
1065 // Output FVSubSolvers status:
1066 m_log << endl << "------------Properties Groups----------" << endl;
1067 m_log << "Levelset is " << (m_levelSet ? "on" : "off") << "!" << endl;
1068 m_log << "Mb is " << (m_levelSetMb ? "on" : "off") << "!" << endl;
1069 m_log << "Combustion is " << (m_combustion ? "on" : "off") << "!" << endl;
1070 m_log << "LS with RANS is " << (m_levelSetRans ? "on" : "off") << "!" << endl;
1071 m_log << endl << "-------------Other Switches-----------" << endl;
1072 m_log << "Thickened Flame is " << (m_thickenedFlame ? "on" : "off") << "!" << endl;
1073 m_log << endl;
1074
1075 m_hasExternalSource = false;
1076 m_hasExternalSource =
1077 m_hasExternalSource
1078 || Context::getSolverProperty<MBool>("particleMomentumCoupling", m_solverId, AT_, &m_hasExternalSource)
1079 || Context::getSolverProperty<MBool>("particleHeatCoupling", m_solverId, AT_, &m_hasExternalSource)
1080 || Context::getSolverProperty<MBool>("particleMassCoupling", m_solverId, AT_, &m_hasExternalSource);
1081
1082
1083 // initialize externalSource data which is added to the right hand side
1084 if(m_hasExternalSource) {
1085 mAlloc(m_externalSource, maxNoGridCells(), CV->noVariables, "m_externalForces", 0.0, AT_);
1086 m_log << "Allocated memory for external sources." << endl;
1087 }
1088
1089 // initialize external mass flux
1090 if(m_sensorParticle) {
1091 ASSERT(this->m_adaptation, "");
1092 mAlloc(m_noParts, grid().maxNoCells(), "m_noParts", 0, AT_);
1093 }
1094
1095 m_bndryGhostCellsOffset = a_noCells();
1096
1097 // Memory parameters:
1098 m_maxNoSurfaces = Context::getSolverProperty<MInt>("maxNoSurfaces", m_solverId, AT_);
1099
1100 m_dataBlockSize = mMax(CV->noVariables, PV->noVariables);
1101 m_slopeMemory = PV->noVariables * nDim; // slope offsets
1102 m_surfaceVarMemory = 2 * PV->noVariables; // surface offsets
1103
1104 // Post-processing parameters:
1105 m_oldMomentOfVorticity = F0; // only required if m_recordLandA is true
1106 m_oldNegativeMomentOfVorticity = F0; // only required if m_recordLandA is true
1107 m_oldPositiveMomentOfVorticity = F0; // only required if m_recordLandA is true
1108
1109 // Array for MB use - will be allocated in fvmbsolver2d/3d construcors
1110 m_associatedBodyIds = (MInt*)nullptr;
1111 m_internalBodyId = (MInt*)nullptr;
1112
1113 // Basic initialization of m_timeStep -> will be done correctly later in computeTimeStep()
1114 forceTimeStep(0);
1133 m_calcSlopesAfterStep = false;
1134 m_calcSlopesAfterStep =
1135 Context::getSolverProperty<MBool>("calcSlopesAfterStep", m_solverId, AT_, &m_calcSlopesAfterStep);
1137 m_lsCutCellBaseLevel = maxRefinementLevel();
1138}
1139
1148template <MInt nDim_, class SysEqn>
1150 TRACE();
1152 const MInt maxNoCells = maxNoGridCells();
1165 // Periodic bc recources (azimuthal periodicity concept)
1166 if(m_periodicCells == 1 || m_periodicCells == 2 || m_periodicCells == 3) {
1167 MInt m_maxNoPeriodicCells = 0;
1179 m_maxNoPeriodicCells =
1180 Context::getSolverProperty<MInt>("maxNoPeriodicCells", m_solverId, AT_, &m_maxNoPeriodicCells);
1181
1182 mAlloc(m_sortedPeriodicCells, m_maxNoPeriodicCells, "m_sortedPeriodicCells", -1, AT_);
1183 mAlloc(m_rotAxisCoord, 2, "rotAxisCoord", F0, AT_);
1184 for(MInt i = 0; i < 2; i++) {
1185 m_rotAxisCoord[i] = 0.0;
1186 m_rotAxisCoord[i] = Context::getSolverProperty<MFloat>("rotAxisCoord", m_solverId, AT_, &m_rotAxisCoord[i], i);
1187 }
1188 }
1189
1190 // Finite volume resources:
1191 MBool bndryRfnJump = false;
1192 bndryRfnJump = Context::getSolverProperty<MBool>("bndryRfnJump", m_solverId, AT_, &bndryRfnJump);
1193 if(bndryRfnJump) {
1194 mAlloc(m_bndryRfnJumpInformation_, maxNoCells, "m_bndryRfnJumpInformation_", -1, AT_);
1195 mAlloc(m_bndryRfnJumpInformation, maxNoCells * 4, "m_bndryRfnJumpInformation", -1, AT_);
1196 }
1197
1198 m_surfaces.setNoSpecies(m_noSpecies);
1199 m_surfaces.setNoMaxSrfcs(m_maxNoSurfaces);
1200 m_surfaces.setNoVariables(PV->noVariables);
1201 m_surfaces.setNoFVariables(FV->noVariables);
1202 const MInt noSurfaceCoefficients = hasSC ? SC->m_noSurfaceCoefficients : 0;
1203 m_surfaces.setNoSurfaceCoefficients(noSurfaceCoefficients);
1204 m_surfaces.setSolverType(string2enum(Context::getSolverProperty<MString>("solvertype", m_solverId, AT_)));
1205 m_surfaces.reset(m_maxNoSurfaces);
1207 m_noActiveCells = 0;
1208 m_reconstructionConstants.reserve(2 * nDim * a_noCells() * nDim);
1209 m_reconstructionCellIds.reserve(2 * nDim * a_noCells());
1210 m_reconstructionNghbrIds.reserve(2 * nDim * a_noCells());
1211 mAlloc(m_A, m_cells.noRecNghbrs(), m_cells.noRecNghbrs(), "m_A", F0, AT_);
1212 mAlloc(m_ATA, m_cells.noRecNghbrs(), m_cells.noRecNghbrs(), "m_ATA", F0, AT_);
1213 mAlloc(m_ATAi, m_cells.noRecNghbrs(), m_cells.noRecNghbrs(), "m_ATAi", F0, AT_);
1214 mAlloc(m_cellSurfaceMapping, maxNoGridCells(), m_noDirs, "m_cellSurfaceMapping", -1, AT_);
1216 // Allocate memory for vorticity if vorticity averaging is enabled, otherwise
1217 // make sure that MAIA fails fast if the m_vorticity member variable is used
1218 if(m_averageVorticity) {
1219 mAlloc(m_vorticity, noInternalCells(), m_vorticitySize, "m_vorticity", AT_);
1220 for(MInt i = 0; i < noInternalCells(); i++) {
1221 for(MInt j = 0; j < m_vorticitySize; j++) {
1222 m_vorticity[i][j] = 0.0;
1224 }
1225 } else {
1226 m_vorticity = nullptr;
1227 }
1229 // domain sizes:
1230 mAlloc(m_domainBoundaries, 2 * nDim, "m_domainBoundaries", F0, AT_);
1232 // Kronecker delta:
1233 mAlloc(m_kronecker, nDim, nDim, "m_kronecker", F0, AT_);
1234 for(MInt i = 0; i < nDim; i++) {
1235 m_kronecker[i][i] = F1;
1237
1238 m_bodyCenter = nullptr;
1239 m_bodyVelocity = nullptr;
1240 m_bodyVelocityDt1 = nullptr;
1241 m_bodyVelocityDt2 = nullptr;
1242 m_bodyTemperature = nullptr;
1249template <MInt nDim_, class SysEqn>
1251 TRACE();
1252 MBool tmpFalse = false;
1253
1265 m_maxIterations = 1;
1266 m_maxIterations = Context::getSolverProperty<MInt>("maxIterations", m_solverId, AT_, &m_maxIterations);
1267
1281 m_periodicCells = 0;
1282 m_periodicCells = Context::getSolverProperty<MInt>("periodicCells", m_solverId, AT_, &m_periodicCells);
1283
1284 m_referenceLength = F1;
1295 m_referenceLength = Context::getSolverProperty<MFloat>("referenceLength", m_solverId, AT_, &m_referenceLength);
1296
1297 if(fabs(m_referenceLength - F1) > m_eps) {
1298 m_log << "WARNING: referenceLength != 1.0. The correct implementation of this is not checked. Don't use it "
1299 "unless you REALLY know what you are doing."
1300 << endl;
1320 m_Re = Context::getSolverProperty<MFloat>("Re", m_solverId, AT_) / m_referenceLength;
1334 m_Pr = 0.72;
1335 m_Pr = Context::getSolverProperty<MFloat>("Pr", m_solverId, AT_, &m_Pr);
1336 m_rPr = 1. / m_Pr;
1337
1349 m_Ma = Context::getSolverProperty<MFloat>("Ma", m_solverId, AT_);
1350
1362 mAlloc(m_angle, nDim, "m_angle", F0, AT_);
1363 m_angle[0] = 0;
1364 m_angle[1] = 0.;
1365 if(Context::propertyExists("angle", m_solverId)) {
1366 for(MInt i = 0; i < (nDim - 1); i++) {
1367 m_angle[i] = Context::getSolverProperty<MFloat>("angle", m_solverId, AT_, i);
1368 m_angle[i] *= PI / 180.0;
1369 }
1370 }
1371
1372 m_gamma = 1.4;
1384 m_gamma = Context::getSolverProperty<MFloat>("gamma", m_solverId, AT_, &m_gamma);
1385
1386 m_considerVolumeForces = false;
1397 m_considerVolumeForces = Context::getSolverProperty<MBool>("considerVolumeForces", m_solverId, AT_, &tmpFalse);
1398
1411 m_considerRotForces = false;
1412 m_considerRotForces = Context::getSolverProperty<MBool>("considerRotForces", m_solverId, AT_, &tmpFalse);
1413
1414 mAlloc(m_volumeAcceleration, nDim, "m_volumeAcceleration", F0, AT_);
1415
1416 if(m_considerVolumeForces) {
1417 // NOTE: the volume acceleration in the property file needs to be non-dimensionalised
1418 // as the entire fv-code, i.e. by * L_ref / (a_ref^2)
1419 // with L_ref as the physical reference length and a_ref as the reference speed of sound!
1420 for(MInt i = 0; i < nDim; i++) {
1421 m_volumeAcceleration[i] =
1422 Context::getSolverProperty<MFloat>("volumeForce", m_solverId, AT_, &m_volumeAcceleration[i], i);
1423 }
1424 }
1425
1437 m_initialCondition = Context::getSolverProperty<MInt>("initialCondition", m_solverId, AT_);
1438
1449 MString govEqs = "NAVIER_STOKES";
1450 govEqs = Context::getSolverProperty<MString>("govEqs", m_solverId, AT_, &govEqs);
1451
1452 m_euler = false;
1453 if(string2enum(govEqs) == EULER) {
1454 m_euler = true;
1455 }
1456
1457 m_gasConstant = 8.314472; // J/K/mol
1469 m_gasConstant = Context::getSolverProperty<MFloat>("gasConstant", m_solverId, AT_, &m_gasConstant);
1470
1471 m_referenceTemperature = 273.15;
1485 m_referenceTemperature =
1486 Context::getSolverProperty<MFloat>("referenceTemperature", m_solverId, AT_, &m_referenceTemperature);
1487
1488 m_sutherlandConstant = 110.4;
1500 m_sutherlandConstant =
1501 Context::getSolverProperty<MFloat>("sutherlandConstant", m_solverId, AT_, &m_sutherlandConstant);
1502
1503 m_sutherlandConstantThermal = m_sutherlandConstant; // default value assumes a constant Prandtl number
1515 m_sutherlandConstantThermal =
1516 Context::getSolverProperty<MFloat>("sutherlandConstantThermal", m_solverId, AT_, &m_sutherlandConstantThermal);
1517
1518 m_sutherlandConstant /= m_referenceTemperature;
1519 m_sutherlandPlusOne = m_sutherlandConstant + F1;
1520 m_sutherlandConstantThermal /= m_referenceTemperature;
1521 m_sutherlandPlusOneThermal = m_sutherlandConstantThermal + F1;
1522
1523
1524 m_changeMa = false;
1537 m_changeMa = Context::getSolverProperty<MBool>("changeMa", m_solverId, AT_, &m_changeMa);
1538
1539
1540 m_previousMa = m_Ma;
1553 m_previousMa = Context::getSolverProperty<MFloat>("previousMa", m_solverId, AT_, &m_previousMa);
1554
1555
1556 m_useCreateCutFaceMGC = false;
1568 m_useCreateCutFaceMGC =
1569 Context::getSolverProperty<MBool>("useCreateCutFaceMGC", m_solverId, AT_, &m_useCreateCutFaceMGC);
1570
1571
1583 m_strouhal = F2 * PI;
1584 m_strouhal = Context::getSolverProperty<MFloat>("Strouhal", m_solverId, AT_, &m_strouhal);
1585
1586 // Parameters for flow forcing:
1587 m_forcing = false;
1588 m_forcingAmplitude = F1B2;
1589 m_noForcingCycles = 5;
1590
1591 m_forcing = Context::getSolverProperty<MBool>("forcing", m_solverId, AT_, &m_forcing);
1592 if(m_forcing) {
1604 m_forcingAmplitude = Context::getSolverProperty<MFloat>("forcingAmplitude", m_solverId, AT_, &m_forcingAmplitude);
1605
1617 m_noForcingCycles = Context::getSolverProperty<MInt>("noForcingCycles", m_solverId, AT_, &m_noForcingCycles);
1618 }
1619
1631 if(Context::propertyExists("cutOffInterface", m_solverId)) {
1632 MInt noCutOffInterface = Context::propertyLength("cutOffInterface", m_solverId);
1633 for(MInt i = 0; i < noCutOffInterface; i++) {
1634 m_cutOffInterface.insert(Context::getSolverProperty<MInt>("cutOffInterface", m_solverId, AT_, i));
1635 }
1636 }
1637
1638 // read test case identifier
1639 // (used for some ugly hardcoded parts of the code, mainly with the MGC Method... (claudia)
1647 m_testCaseName = "NONE";
1648 m_testCaseName = Context::getSolverProperty<MString>("testCaseName", m_solverId, AT_, &m_testCaseName);
1649
1650
1658 m_weightBndryCells = true;
1659 m_weightBndryCells = Context::getSolverProperty<MBool>("weightFvBndryCells", m_solverId, AT_, &m_weightBndryCells);
1660
1668 m_weightCutOffCells = true;
1669 m_weightCutOffCells = Context::getSolverProperty<MBool>("weightFvCutOffCells", m_solverId, AT_, &m_weightCutOffCells);
1670
1678 m_weightBc1601 = true;
1679 m_weightBc1601 = Context::getSolverProperty<MBool>("weightFvBc1601", m_solverId, AT_, &m_weightBc1601);
1680
1688 m_weightInactiveCell = false;
1689 m_weightInactiveCell =
1690 Context::getSolverProperty<MBool>("weightFvInactiveCell", m_solverId, AT_, &m_weightInactiveCell);
1691
1699 m_weightLvlJumps = false;
1700 m_weightLvlJumps = Context::getSolverProperty<MBool>("weightFvLvlJumps", m_solverId, AT_, &m_weightLvlJumps);
1701
1702
1710 m_weightNearBndryCells = false;
1711 m_weightNearBndryCells =
1712 Context::getSolverProperty<MBool>("weightFvNearBndryCells", m_solverId, AT_, &m_weightNearBndryCells);
1713
1721 m_weightSmallCells = false;
1722 m_weightSmallCells = Context::getSolverProperty<MBool>("weightFvSmallCells", m_solverId, AT_, &m_weightSmallCells);
1723
1732 m_limitWeights = false;
1733 m_limitWeights = Context::getSolverProperty<MBool>("limitDLBWeights", solverId(), AT_, &m_limitWeights);
1742 m_weightBaseCell = 1.0;
1743 m_weightBaseCell = Context::getSolverProperty<MFloat>("weightBaseCell", solverId(), AT_, &m_weightBaseCell);
1752 m_weightLeafCell = 1.0;
1753 m_weightLeafCell = Context::getSolverProperty<MFloat>("weightLeafCell", solverId(), AT_, &m_weightLeafCell);
1762 m_weightActiveCell = 1.0;
1763 m_weightActiveCell = Context::getSolverProperty<MFloat>("weightAvticeCell", solverId(), AT_, &m_weightLeafCell);
1764
1773 m_weightBndryCell = 0.0;
1774 m_weightBndryCell = Context::getSolverProperty<MFloat>("weightBndryCell", solverId(), AT_, &m_weightBndryCell);
1775
1784 m_weightNearBndryCell = 0.0;
1785 m_weightNearBndryCell =
1786 Context::getSolverProperty<MFloat>("weightNearBndryCell", solverId(), AT_, &m_weightNearBndryCell);
1787
1788
1798 m_weightMulitSolverFactor = 1.0;
1799 m_weightMulitSolverFactor =
1800 Context::getSolverProperty<MFloat>("weightMulitSolverFactor", solverId(), AT_, &m_weightMulitSolverFactor);
1801
1802 // EEGas
1803 if(Context::propertyExists("EEGas", m_solverId)) {
1812 m_EEGas.RKSemiImplicitFactor = 0.5;
1813 m_EEGas.RKSemiImplicitFactor =
1814 Context::getSolverProperty<MFloat>("RKSemiImplicitFactor", m_solverId, AT_, &m_EEGas.RKSemiImplicitFactor);
1815 if(m_isEEGas) {
1816 mAlloc(m_EEGas.uOtherPhase, maxNoGridCells(), nDim, "m_EEGas.uOtherPhase", F0, AT_);
1817 mAlloc(m_EEGas.uOtherPhaseOld, maxNoGridCells(), nDim, "m_EEGas.uOtherPhaseOld", F0, AT_);
1818 mAlloc(m_EEGas.gradUOtherPhase, maxNoGridCells(), nDim * nDim, "m_EEGas.gradUOtherPhase", F0, AT_);
1819 mAlloc(m_EEGas.vortOtherPhase, maxNoGridCells(), nDim, "m_EEGas.vortOtherPhase", F0, AT_);
1820 mAlloc(m_EEGas.nuTOtherPhase, maxNoGridCells(), "m_EEGas.nuTOtherPhase", F0, AT_);
1821 mAlloc(m_EEGas.nuEffOtherPhase, maxNoGridCells(), "m_EEGas.nuEffOtherPhase", F0, AT_);
1822
1823 if(m_noSpecies != 1) {
1824 mTerm(1, AT_, "noSpecies has to be 1 for gas-liquid Euler-Euler simulations");
1825 }
1826 if(domainId() == 0) cerr << "FV Solver EEGas!" << endl;
1827 }
1828 }
1829
1844 m_EEGas.dragModel = 0;
1845 m_EEGas.dragModel = Context::getSolverProperty<MInt>("EEGasDragModel", m_solverId, AT_, &m_EEGas.dragModel);
1846
1847 if(m_EEGas.dragModel == 2) {
1856 m_EEGas.CD = 1.0;
1857 m_EEGas.CD = Context::getSolverProperty<MFloat>("EEGasCD", m_solverId, AT_, &m_EEGas.CD);
1858 }
1859
1867 m_EEGas.Eo0 = 2.24;
1868 m_EEGas.Eo0 = Context::getSolverProperty<MFloat>("EEGasEo0", m_solverId, AT_, &m_EEGas.Eo0);
1869
1877 m_EEGas.bubbleDiameter = 0.001;
1878 m_EEGas.bubbleDiameter =
1879 Context::getSolverProperty<MFloat>("bubbleDiameter", m_solverId, AT_, &m_EEGas.bubbleDiameter);
1880
1888 m_EEGas.liquidDensity = 774;
1889 m_EEGas.liquidDensity =
1890 Context::getSolverProperty<MFloat>("EEGasLiquidDensity", m_solverId, AT_, &m_EEGas.liquidDensity);
1891
1899 m_EEGas.eps = 1.0e-10;
1900 m_EEGas.eps = Context::getSolverProperty<MFloat>("EEGasEps", m_solverId, AT_, &m_EEGas.eps);
1901
1909 m_EEGas.CL = 0.288; // C_L = 0.288 used by Mohammadi19
1910 m_EEGas.CL = Context::getSolverProperty<MFloat>("EEGasCL", m_solverId, AT_, &m_EEGas.CL);
1911
1921 m_EEGas.gasSource = 0;
1922 m_EEGas.gasSource = Context::getSolverProperty<MInt>("EEGasGasSource", m_solverId, AT_, &m_EEGas.gasSource);
1923
1931 m_EEGas.gasSourceMassFlow = 0.0;
1932 m_EEGas.gasSourceMassFlow =
1933 Context::getSolverProperty<MFloat>("EEGasGasSourceMassFlow", m_solverId, AT_, &m_EEGas.gasSourceMassFlow);
1935 if(m_EEGas.gasSource > 1 && m_EEGas.gasSourceMassFlow < 1.0e-16) {
1936 mTerm(1, AT_, "EEGasGasSourceMassFlow needed!");
1937 }
1938
1939 if(m_EEGas.gasSource == 9) {
1940 const MInt l_noElements = Context::propertyLength("EEGasGasSourceBox");
1941 if(l_noElements % nDim * 2 != 0) {
1942 mTerm(1, AT_, "number of elements in EEGasGasSourceBox has to be a multiple of 2*nDim");
1943 }
1944 m_EEGas.noGasSourceBoxes = l_noElements / (nDim * 2);
1945 if(domainId() == 0) cerr << "number of gasSourceBoxes detected: " << m_EEGas.noGasSourceBoxes << endl;
1946 for(MInt i = 0; i < m_EEGas.noGasSourceBoxes * nDim * 2; i++) {
1953 m_EEGas.gasSourceBox.push_back(Context::getSolverProperty<MFloat>("EEGasGasSourceBox", m_solverId, AT_, i));
1964 m_EEGas.bubblePathDispersion = true;
1965 m_EEGas.bubblePathDispersion =
1966 Context::getSolverProperty<MBool>("bubblePathDispersion", m_solverId, AT_, &m_EEGas.bubblePathDispersion);
1967
1975 m_EEGas.initialAlpha = 0.0;
1976 m_EEGas.initialAlpha = Context::getSolverProperty<MFloat>("initialAlpha", m_solverId, AT_, &m_EEGas.initialAlpha);
1977
1985 m_EEGas.alphaInf = m_EEGas.initialAlpha;
1986 m_EEGas.alphaInf = Context::getSolverProperty<MFloat>("alphaInf", m_solverId, AT_, &m_EEGas.alphaInf);
1987
1995 m_EEGas.alphaIn = m_EEGas.initialAlpha;
1996 m_EEGas.alphaIn = Context::getSolverProperty<MFloat>("alphaIn", m_solverId, AT_, &m_EEGas.alphaIn);
1997
2005 m_EEGas.schmidtNumber = 1.0;
2006 m_EEGas.schmidtNumber = Context::getSolverProperty<MFloat>("schmidtNumber", m_solverId, AT_, &m_EEGas.schmidtNumber);
2007
2015 m_EEGas.uDLimiter = true;
2016 m_EEGas.uDLimiter = Context::getSolverProperty<MBool>("uDLimiter", m_solverId, AT_, &m_EEGas.uDLimiter);
2017
2025 m_EEGas.uDLim = 0.2;
2026 m_EEGas.uDLim = Context::getSolverProperty<MFloat>("uDLim", m_solverId, AT_, &m_EEGas.uDLim);
2027
2036 m_EEGas.interpolationFactor = 0.5;
2037 m_EEGas.interpolationFactor = Context::getSolverProperty<MFloat>("EEMultiphaseInterpolationFactor", m_solverId, AT_,
2038 &m_EEGas.interpolationFactor);
2039
2050 m_EEGas.depthCorrection = m_isEEGas;
2051 m_EEGas.depthCorrection =
2052 Context::getSolverProperty<MBool>("depthCorrection", m_solverId, AT_, &m_EEGas.depthCorrection);
2053
2054 if(m_EEGas.depthCorrection) {
2055 if(!Context::propertyExists("gravityRefCoords", m_solverId)
2056 || !Context::propertyExists("depthCorrectionCoefficients", m_solverId)) {
2057 mTerm(1, AT_, "gravityRefCoords and depthCorrectionCoefficients are required for depthCorrection!");
2058 }
2059
2060 for(MInt i = 0; i < nDim; i++) {
2067 m_EEGas.gravityRefCoords.push_back(Context::getSolverProperty<MFloat>("gravityRefCoords", m_solverId, AT_, i));
2077 m_EEGas.depthCorrectionCoefficients.push_back(
2078 Context::getSolverProperty<MFloat>("depthCorrectionCoefficients", m_solverId, AT_, i));
2079 }
2080 }
2081
2082 if(m_isEEGas && !Context::propertyExists("EEGasGravity", m_solverId)) {
2083 mTerm(1, AT_, "EEGasGravity required for EEGas!");
2084 } else if(m_isEEGas) {
2085 for(MInt i = 0; i < nDim; i++) {
2092 m_EEGas.gravity.push_back(Context::getSolverProperty<MFloat>("EEGasGravity", m_solverId, AT_, i));
2093 }
2094 }
2095}
2096
2101template <MInt nDim_, class SysEqn>
2103 TRACE();
2104 // initially set all pointers to nullptr pointer
2105 m_molecularWeight = nullptr;
2106 m_FmolecularWeight = nullptr;
2107 m_molarFormationEnthalpy = nullptr;
2108 m_formationEnthalpy = nullptr;
2109 m_referenceComposition = nullptr;
2110 m_secondaryReferenceComposition = nullptr;
2113 if(m_combustion && m_thickenedFlame) {
2114 mAlloc(m_molecularWeight, m_noSpecies, "m_molecularWeight", F1, AT_);
2115 mAlloc(m_FmolecularWeight, m_noSpecies, "m_FmolecularWeight", F1, AT_);
2118 for(MInt s = 0; s < m_noSpecies; s++) {
2130 m_molecularWeight[s] =
2131 Context::getSolverProperty<MFloat>("molecularWeight", m_solverId, AT_, &m_molecularWeight[s], s);
2132 m_FmolecularWeight[s] = F1 / m_molecularWeight[s];
2133 }
2157 mAlloc(m_molarFormationEnthalpy, m_noSpecies, "m_molarFormationEnthalpy", F1, AT_);
2158 mAlloc(m_formationEnthalpy, m_noSpecies, "m_formationEnthalpy", F1, AT_);
2159 mAlloc(m_referenceComposition, m_noSpecies, "m_referenceComposition", F1, AT_);
2160 mAlloc(m_secondaryReferenceComposition, m_noSpecies, "m_secondaryReferenceComposition", F0, AT_);
2161
2162 for(MInt s = 0; s < m_noSpecies; s++) {
2163 m_molarFormationEnthalpy[s] = Context::getSolverProperty<MFloat>("molarFormationEnthalpy", m_solverId, AT_,
2164 &m_molarFormationEnthalpy[s], s);
2165 m_referenceComposition[s] =
2166 Context::getSolverProperty<MFloat>("referenceComposition", m_solverId, AT_, &m_referenceComposition[s], s);
2167 m_secondaryReferenceComposition[s] = Context::getSolverProperty<MFloat>(
2168 "secondaryReferenceComposition", m_solverId, AT_, &m_secondaryReferenceComposition[s], s);
2169 m_formationEnthalpy[s] = m_molarFormationEnthalpy[s] / m_molecularWeight[s];
2172 m_referenceDensityTF = 1.25;
2184 m_referenceDensityTF =
2185 Context::getSolverProperty<MFloat>("referenceDensity", m_solverId, AT_, &m_referenceDensityTF);
2186
2198 m_heatReleaseReductionFactor = F1;
2199 m_heatReleaseReductionFactor = Context::getSolverProperty<MFloat>("heatReleaseReductionFactor", m_solverId, AT_,
2200 &m_heatReleaseReductionFactor);
2201 m_thickeningFactor = F1;
2214 m_thickeningFactor = Context::getSolverProperty<MFloat>("thickeningFactor", m_solverId, AT_, &m_thickeningFactor);
2226 m_reactionScheme =
2227 "METHANE_2_STEP";
2228 m_reactionScheme = Context::getSolverProperty<MString>("reactionScheme", m_solverId, AT_, &m_reactionScheme);
2229 }
2230}
2231
2235template <MInt nDim_, class SysEqn>
2237 TRACE();
2238 // initialize sponge variables
2239 m_spongeLayerThickness = F0;
2240 m_createSpongeBoundary = false;
2241 m_spongeLayerLayout = 0;
2242 m_spongeLayerType = 0;
2243 m_targetDensityFactor = F1;
2244 m_noSpongeFactors = 0;
2245 m_sigmaSponge = F0;
2246 m_sigmaSpongeInflow = F0;
2247 m_noSpongeBndryCndIds = 0;
2248 m_spongeTimeDep = false;
2249 m_noMaxSpongeBndryCells = 0;
2250 m_velocitySponge = 0;
2251
2266 m_spongeLayerThickness =
2267 Context::getSolverProperty<MFloat>("spongeLayerThickness", m_solverId, AT_, &m_spongeLayerThickness);
2268
2279 if(Context::propertyExists("spongeLayerThickness_int", m_solverId)) {
2280 MFloat cellLength = c_cellLengthAtLevel(maxUniformRefinementLevel());
2281 m_spongeLayerThickness =
2282 (MFloat)Context::getSolverProperty<MInt>("spongeLayerThickness_int", m_solverId, AT_) * cellLength;
2283
2284 cerr << " m_spongeLayerThickness is: " << m_spongeLayerThickness << endl;
2285 }
2286
2287 // check if sponge variables should be read
2288 if(m_spongeLayerThickness > 0) {
2300 m_createSpongeBoundary =
2301 Context::getSolverProperty<MBool>("createSpongeBoundary", m_solverId, AT_, &m_createSpongeBoundary);
2302
2303 if(m_createSpongeBoundary) {
2304 // read in sponge variables for specific cartesian boundaries (only 2D implemented) and add the additional memory
2305 setAndAllocateSpongeBoundaryProperties();
2306 } else {
2307 // read in sponge variables for the domain boundaries and add the additional memory
2308 setAndAllocateSpongeDomainProperties(F0);
2309 }
2310 }
2311
2312 mDeallocate(m_cellsInsideSpongeLayer);
2313 // Allocate sponge cell array - must be allocated even if no sponge layer is applied! Size of array is different
2314 m_noCellsInsideSpongeLayer = 0;
2315 if(!m_createSpongeBoundary) {
2316 mAlloc(m_cellsInsideSpongeLayer, maxNoGridCells(), "m_cellsInsideSpongeLayer", -1, AT_);
2317 } else {
2318 mAlloc(m_cellsInsideSpongeLayer, m_noMaxSpongeBndryCells, "m_cellsInsideSpongeLayer", -1, AT_);
2319 }
2320}
2321
2325template <MInt nDim_, class SysEqn>
2327 TRACE();
2328 // initialization of limited vars
2329 m_noLimitedSlopesVar = 0;
2330 m_limitedSlopesVar = nullptr;
2331
2345 m_cfl = Context::getSolverProperty<MFloat>("cfl", m_solverId, AT_);
2346
2361 m_cflViscous = F1B4;
2362 m_cflViscous = Context::getSolverProperty<MFloat>("cflViscous", m_solverId, AT_, &m_cflViscous);
2363
2375 m_orderOfReconstruction = 1;
2376 m_orderOfReconstruction =
2377 Context::getSolverProperty<MInt>("orderOfReconstruction", m_solverId, AT_, &m_orderOfReconstruction);
2378
2379 m_RKalpha = nullptr;
2380 m_RKStep = 0;
2381
2382 m_limiter = 0;
2394 m_limiter = Context::getSolverProperty<MInt>("limiter", m_solverId, AT_, &m_limiter);
2395
2396 m_surfaceValueReconstruction = "HOCD";
2410 m_surfaceValueReconstruction =
2411 Context::getSolverProperty<MString>("surfaceValueReconstruction", m_solverId, AT_, &m_surfaceValueReconstruction);
2412
2413 if(string2enum(m_surfaceValueReconstruction) == HOCD_LIMITED_SLOPES
2414 || string2enum(m_surfaceValueReconstruction) == HOCD_LIMITED_SLOPES_MAN) {
2415 m_noLimitedSlopesVar = 0;
2416 MInt tmp = Context::propertyLength("limitedSlopesVar", m_solverId);
2417 if(tmp != 3) {
2418 mTerm(1, AT_, "no limited variables is wrong");
2419 }
2420
2421 mAlloc(m_limitedSlopesVar, PV->noVariables - m_noSpecies, "m_limitedSlopesVar", -1, AT_);
2422 MInt* tmpRead = (MInt*)nullptr;
2423 mAlloc(tmpRead, tmp, "tmpRead", -1, AT_);
2424
2425 for(MInt i = 0; i < tmp; i++) {
2438 tmpRead[i] = Context::getSolverProperty<MInt>("limitedSlopesVar", m_solverId, AT_, &tmpRead[i], i);
2439 if(tmpRead[i] < 0 || tmpRead[i] > 1) {
2440 mTerm(1, AT_, "ERROR: limitedSlopesVar should be 0 or 1");
2441 }
2442 }
2443
2444 // setting limited slopes for the velocities
2445 for(MInt d = 0; d < nDim; d++) {
2446 if(tmpRead[0] > 0) {
2447 m_limitedSlopesVar[d] = PV->VV[d];
2448 m_noLimitedSlopesVar++;
2449 m_log << "setting variable " << d << " as limited variable" << endl;
2450 } else {
2451 break;
2452 }
2453 }
2454
2455 // setting limited slopes for the density or pressure
2456 for(MInt d = nDim; d < (PV->noVariables - m_noSpecies); d++) {
2457 if(tmpRead[d - nDim + 1] != 0) {
2458 m_limitedSlopesVar[m_noLimitedSlopesVar] = d;
2459 m_noLimitedSlopesVar++;
2460 m_log << "setting variable " << d << " as limited variable" << endl;
2461 }
2462 }
2463 m_log << m_noLimitedSlopesVar << " number of limited variables" << endl;
2464 for(MInt d = 0; d < m_noLimitedSlopesVar; d++) {
2465 m_log << "limited variable is: " << m_limitedSlopesVar[d] << endl;
2466 }
2467 }
2468
2482 m_viscousFluxScheme = "FIVE_POINT";
2483 m_viscousFluxScheme = Context::getSolverProperty<MString>("viscousFluxScheme", m_solverId, AT_, &m_viscousFluxScheme);
2484 m_log << endl << "viscous-flux scheme: " << m_viscousFluxScheme << endl << endl;
2485
2500 if(string2enum(m_viscousFluxScheme) == FIVE_POINT_STABILIZED
2501 && Context::propertyExists("enhanceThreePointViscFluxFactor", m_solverId)) {
2502 m_enhanceThreePointViscFluxFactor = Context::getSolverProperty<MFloat>(
2503 "enhanceThreePointViscFluxFactor", m_solverId, AT_, &m_enhanceThreePointViscFluxFactor);
2504 } else {
2505 m_enhanceThreePointViscFluxFactor = 0.1;
2506 }
2507
2508
2509 m_advectiveFluxScheme = "AUSM";
2510 if(Context::propertyExists("advectiveFluxScheme", m_solverId)) {
2511 m_advectiveFluxScheme =
2512 Context::getSolverProperty<MString>("advectiveFluxScheme", m_solverId, AT_, &m_advectiveFluxScheme);
2513 }
2514
2515
2529 m_gridInterfaceFilter = false;
2530 m_gridInterfaceFilter =
2531 Context::getSolverProperty<MBool>("gridInterfaceFilter", m_solverId, AT_, &m_gridInterfaceFilter);
2532
2545 m_force1DFiltering = false;
2546 m_force1DFiltering = Context::getSolverProperty<MBool>("force1D", m_solverId, AT_, &m_force1DFiltering);
2547
2548
2558 if(m_dualTimeStepping) {
2559 m_physicalTimeStep = Context::getSolverProperty<MFloat>("physicalTimeStep", m_solverId, AT_);
2560 }
2561
2562 m_maxNoTimeSteps = Context::getSolverProperty<MInt>("timeSteps", m_solverId, AT_);
2563
2577 m_timeStepMethod = Context::getSolverProperty<MInt>("timeStepMethod", m_solverId, AT_);
2578
2590 m_timeStepNonBlocking = false;
2591 m_timeStepNonBlocking =
2592 Context::getSolverProperty<MBool>("timeStepNonBlocking", m_solverId, AT_, &m_timeStepNonBlocking);
2593
2594 // Initialize timeStepComputationInterval
2595 // When restarting the default is to read the time-step from the restart file. Otherwise,
2596 // the time-step is computed only once, at the beginning.
2597 m_timeStepComputationInterval = m_restart ? -1 : 0;
2598
2613 m_timeStepComputationInterval =
2614 Context::getSolverProperty<MInt>("timeStepComputationInterval", m_solverId, AT_, &m_timeStepComputationInterval);
2615
2616
2617 m_log << "TimeStepComputationInterval: ";
2618 switch(m_timeStepComputationInterval) {
2619 case 0: {
2620 m_log << "0 (default)";
2621 break;
2622 }
2623 case -1: {
2624 m_log << "-1 (never, using time step from restart file)";
2625 break;
2626 }
2627 default: {
2628 if(m_timeStepComputationInterval < 0) {
2629 mTerm(1, AT_, "timeStepComputationInterval out-of-range [-1, infinity)");
2630 }
2631 m_log << m_timeStepComputationInterval << " (recompute dt every " << m_timeStepComputationInterval
2632 << " time steps)";
2633 break;
2634 }
2635 }
2636 m_log << endl;
2637
2638 if(Context::propertyExists("usePreviousTimeStep", m_solverId)) {
2639 mTerm(-1, "ERROR: usePreviousTimeStep has been removed. Set timeStepComputationInterval instead. If you were using "
2640 "usePreviousTimeStep = 0 you have to set timeStepComputationInterval = 0. If you were using "
2641 "usePreviousTimeStep = 1 you can either set timeStepComputationInterval = -1, or remove the property "
2642 "completely because -1 is the default value of timeStepComputationInterval when restarting. Check the "
2643 "aiawiki for more information.");
2644 }
2645
2646
2647 m_timeStepVolumeWeighted = false;
2656 m_timeStepVolumeWeighted =
2657 Context::getSolverProperty<MBool>("timeStepVolumeWeighted", m_solverId, AT_, &m_timeStepVolumeWeighted);
2658
2659 m_timeStepFixedValue = -1.0;
2660 m_timeStepFixedValue = Context::getSolverProperty<MFloat>("fixedTimeStep", m_solverId, AT_, &m_timeStepFixedValue);
2661
2662 m_log << "Time step computation settings: volumeWeighted = " << m_timeStepVolumeWeighted
2663 << "; fixedTimeStepValue = " << m_timeStepFixedValue << std::endl;
2664
2676 m_globalUpwindCoefficient = F0;
2677 m_globalUpwindCoefficient =
2678 Context::getSolverProperty<MFloat>("globalUpwindCoefficient", m_solverId, AT_, &m_globalUpwindCoefficient);
2679 m_chi = Context::getSolverProperty<MFloat>("upwindCoefficient", m_solverId, AT_);
2680
2681 m_upwindMethod = 0;
2682 m_upwindMethod = Context::getSolverProperty<MInt>("upwindMethod", m_solverId, AT_, &m_upwindMethod);
2683 m_2ndOrderWeights = false;
2684 m_2ndOrderWeights = Context::getSolverProperty<MBool>("weights2ndOrder", m_solverId, AT_, &m_2ndOrderWeights);
2685 m_reExcludeBndryDiagonals = false;
2686 m_reExcludeBndryDiagonals =
2687 Context::getSolverProperty<MBool>("reExcludeBndryDiagonals", m_solverId, AT_, &m_reExcludeBndryDiagonals);
2688
2705 m_reConstSVDWeightMode = 0;
2706 m_reConstSVDWeightMode =
2707 Context::getSolverProperty<MInt>("reConstSVDWeightMode", m_solverId, AT_, &m_reConstSVDWeightMode);
2708 m_relocateCenter = false;
2709 m_relocateCenter = Context::getSolverProperty<MBool>("relocateCenter", m_solverId, AT_, &m_relocateCenter);
2710
2711 if(m_bndryLevelJumps) {
2712 ASSERT(m_reConstSVDWeightMode != 1, "Mode not working for bndry-level-jumps!");
2713 }
2714
2725 // Residual properties - chosen as in 3D sphere Testcase:
2726 m_convergenceCriterion = 1e-12;
2727 m_convergenceCriterion =
2728 Context::getSolverProperty<MFloat>("convergenceCriterion", m_solverId, AT_, &m_convergenceCriterion);
2730 m_timeStepConvergenceCriterion = 1e-6;
2731 m_timeStepConvergenceCriterion = Context::getSolverProperty<MFloat>("timeStepConvergenceCriterion", m_solverId, AT_,
2732 &m_timeStepConvergenceCriterion);
2733
2734 m_useCentralDifferencingSlopes = false;
2735 m_useCentralDifferencingSlopes = Context::getSolverProperty<MBool>("useCentralDifferencingSlopes", m_solverId, AT_,
2736 &m_useCentralDifferencingSlopes);
2737
2738 m_spongeTimeVelocity = 0;
2739 m_spongeTimeVelocity = Context::getSolverProperty<MInt>("spongeTimeVelocity", m_solverId, AT_, &m_spongeTimeVelocity);
2740}
2745template <MInt nDim_, class SysEqn>
2747 TRACE();
2748 MBool tmpFalse = false;
2749 MBool tmpTrue = true;
2762 m_solutionOffset = 0;
2763 m_solutionOffset = Context::getSolverProperty<MInt>("solutionOffset", m_solverId, AT_, &m_solutionOffset);
2772 m_outputPhysicalTime = false;
2773 m_outputPhysicalTime =
2774 Context::getSolverProperty<MBool>("outputPhysicalTime", m_solverId, AT_, &m_outputPhysicalTime);
2775
2787 if(Context::propertyExists("solutionTimeSteps", m_solverId)) {
2788 MInt noSolutionTimeSteps = Context::propertyLength("solutionTimeSteps", m_solverId);
2789 for(MInt i = 0; i < noSolutionTimeSteps; i++) {
2790 MInt sts = Context::getSolverProperty<MInt>("solutionTimeSteps", m_solverId, AT_, i);
2791 m_solutionTimeSteps.insert(sts);
2792 cerr << " inserted time step " << sts << " to solution time steps! " << endl;
2795
2796 m_integratedHeatReleaseOutput = false;
2797 m_integratedHeatReleaseOutput =
2798 Context::getSolverProperty<MBool>("integratedHeatReleaseOutput", m_solverId, AT_, &m_integratedHeatReleaseOutput);
2800 m_integratedHeatReleaseOutputInterval = 0;
2801 m_integratedHeatReleaseOutputInterval = Context::getSolverProperty<MInt>(
2802 "integratedHeatReleaseOutputInterval", m_solverId, AT_, &m_integratedHeatReleaseOutputInterval);
2804 m_dragOutputInterval = 0;
2805 m_dragOutputInterval = Context::getSolverProperty<MInt>("dragOutputInterval", m_solverId, AT_, &m_dragOutputInterval);
2806
2816 m_surfDistParallel = Context::getSolverProperty<MBool>("surfaceDistributionParallel", m_solverId, AT_, &tmpFalse);
2817
2829 m_surfDistCartesian = Context::getSolverProperty<MBool>("surfaceDistributionCartesian", m_solverId, AT_, &tmpFalse);
2843 m_saveVorticityToRestart = false;
2844 m_saveVorticityToRestart =
2845 Context::getSolverProperty<MBool>("saveVorticityToRestart", m_solverId, AT_, &m_saveVorticityToRestart);
2846
2847 m_vorticityOutput = Context::getSolverProperty<MBool>("vorticityOutput", m_solverId, AT_, &tmpTrue);
2848
2860 m_qCriterionOutput = Context::getSolverProperty<MBool>("qCriterionOutput", m_solverId, AT_, &tmpTrue);
2872 m_vtuWritePointData = false;
2873 m_vtuWritePointData = Context::getSolverProperty<MBool>("vtuWritePointData", m_solverId, AT_, &m_vtuWritePointData);
2874 m_log << "m_vtuWritePointData: " << m_vtuWritePointData << endl;
2887 m_vtuCutCellOutput = (nDim == 3);
2888 IF_CONSTEXPR(nDim == 3)
2889 m_vtuCutCellOutput = Context::getSolverProperty<MBool>("vtuCutCellOutput", m_solverId, AT_, &m_vtuCutCellOutput);
2890 m_vtuGeometryOutput.clear();
2891 IF_CONSTEXPR(nDim == 3) {
2892 if(Context::propertyExists("vtuGeometryOutput", m_solverId)) {
2893 m_log << "VTU geometry output for boundaryIds: ";
2901 MInt cnt = Context::propertyLength("vtuGeometryOutput", m_solverId);
2902 for(MInt i = 0; i < cnt; i++) {
2903 MInt bcId = Context::getSolverProperty<MInt>("vtuGeometryOutput", m_solverId, AT_, i);
2904 m_vtuGeometryOutput.insert(bcId);
2905 m_log << bcId << " ";
2906 }
2907 m_log << endl;
2908 }
2909 }
2918 m_vtuGeometryOutputExtended = false;
2919 m_vtuGeometryOutputExtended =
2920 Context::getSolverProperty<MBool>("vtuGeometryOutputExtended", m_solverId, AT_, &m_vtuGeometryOutputExtended);
2921 m_vtuWriteGeometryFile = true;
2922 m_vtuWriteGeometryFile =
2923 Context::getSolverProperty<MBool>("vtuGeometryFile", m_solverId, AT_, &m_vtuWriteGeometryFile);
2924
2925 m_vtuWriteParticleFile = true;
2926 m_vtuWriteParticleFile =
2927 Context::getSolverProperty<MBool>("vtuParticleFile", m_solverId, AT_, &m_vtuWriteParticleFile);
2936 m_vtuGlobalIdOutput = false;
2937 m_vtuGlobalIdOutput = Context::getSolverProperty<MBool>("vtuGlobalIdOutput", m_solverId, AT_, &m_vtuGlobalIdOutput);
2938
2946 m_vtuDomainIdOutput = false;
2947 m_vtuDomainIdOutput = Context::getSolverProperty<MBool>("vtuDomainIdOutput", m_solverId, AT_, &m_vtuDomainIdOutput);
2956 m_vtuDensityOutput = true;
2957 m_vtuDensityOutput = Context::getSolverProperty<MBool>("vtuDensityOutput", m_solverId, AT_, &m_vtuDensityOutput);
2958
2966 m_vtuLevelSetOutput = false;
2967 m_vtuLevelSetOutput = Context::getSolverProperty<MBool>("vtuLevelSetOutput", m_solverId, AT_, &m_vtuLevelSetOutput);
2979 m_vtuQCriterionOutput = false;
2980 m_vtuQCriterionOutput =
2981 Context::getSolverProperty<MBool>("vtuQCriterionOutput", m_solverId, AT_, &m_vtuQCriterionOutput);
2982
2992 m_vtuLambda2Output = false;
2993 m_vtuLambda2Output = Context::getSolverProperty<MBool>("vtuLambda2Output", m_solverId, AT_, &m_vtuLambda2Output);
2994
3002 m_vtuVorticityOutput = false;
3003 m_vtuVorticityOutput =
3004 Context::getSolverProperty<MBool>("vtuVorticityOutput", m_solverId, AT_, &m_vtuVorticityOutput);
3005 IF_CONSTEXPR(nDim == 2) { m_vtuVorticityOutput = false; } // will be stored anyways
3006
3014 m_vtuVelocityGradientOutput = false;
3015 m_vtuVelocityGradientOutput =
3016 Context::getSolverProperty<MBool>("vtuVelocityGradientOutput", m_solverId, AT_, &m_vtuVelocityGradientOutput);
3017
3025 m_vtuSaveHeaderTesting = false;
3026 m_vtuSaveHeaderTesting =
3027 Context::getSolverProperty<MBool>("vtuSaveHeaderTesting", m_solverId, AT_, &m_vtuSaveHeaderTesting);
3028
3040 m_vtuLevelThreshold = maxRefinementLevel();
3041 if(Context::propertyExists("vtuLevelThreshold", m_solverId))
3042 m_vtuLevelThreshold = Context::getSolverProperty<MInt>("vtuLevelThreshold", m_solverId, AT_, &m_vtuLevelThreshold);
3043 if(m_vtuLevelThreshold <= 0) m_vtuLevelThreshold = maxRefinementLevel();
3044 m_log << "m_vtuLevelThreshold: " << m_vtuLevelThreshold << endl;
3045
3057 m_vtuCoordinatesThreshold = nullptr;
3058 if(Context::propertyExists("vtuCoordinatesThreshold", m_solverId)) {
3059 mAlloc(m_vtuCoordinatesThreshold, 6, "m_vtuCoordinatesThreshold", F0, AT_);
3060 for(MInt i = 0; i < 2 * nDim; i++) {
3061 m_vtuCoordinatesThreshold[i] = Context::getSolverProperty<MFloat>("vtuCoordinatesThreshold", m_solverId, AT_,
3062 &m_vtuCoordinatesThreshold[i], i);
3063 }
3064 }
3065 m_log << "m_vtuCoordinatesThreshold: ";
3066 if(m_vtuCoordinatesThreshold == nullptr)
3067 m_log << "nullptr";
3068 else
3069 for(MInt i = 0; i < 2 * nDim; i++) {
3070 m_log << m_vtuCoordinatesThreshold[i] << " ";
3071 }
3072 m_log << endl;
3073
3074
3075 m_variablesName = new const MChar*[PV->noVariables];
3076 for(MInt i = 0; i < PV->noVariables; ++i) {
3077 m_variablesName[i] = new MChar[10];
3078 }
3079
3080 MInt count = 0;
3081 m_variablesName[count] = "u";
3082 count++;
3083 m_variablesName[count] = "v";
3084 count++;
3085 IF_CONSTEXPR(nDim == 3) {
3086 m_variablesName[count] = "w";
3087 count++;
3088 }
3089 m_variablesName[count] = "rho";
3090 count++;
3091 m_variablesName[count] = "p";
3092 count++;
3093 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
3094 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
3095 m_variablesName[count] = "nu";
3096 count++;
3097 }
3098 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
3099 m_variablesName[count] = "k";
3100 count++;
3101 m_variablesName[count] = "omega";
3102 count++;
3103 }
3104 }
3105
3106 if(m_combustion) {
3107 m_variablesName[count] = "c";
3108 count++;
3109 } else {
3110 if(m_noSpecies == 1) {
3111 m_variablesName[count] = "Y";
3112 count++;
3113 }
3114
3115 IF_CONSTEXPR(isDetChem<SysEqn>) {
3116 if(m_noSpecies > 1) {
3117 for(MInt s = 0; s < m_noSpecies; s++) {
3118 MString str = ("Y" + m_speciesName[s]);
3119 MChar* c = new MChar[10];
3120 strcpy(c, str.c_str());
3121 m_variablesName[count] = c;
3122 count++;
3123 }
3124 }
3125 }
3126 }
3127
3128
3129 count = 0;
3130 m_vorticitySize = 0;
3131 if(m_vorticityOutput) {
3132 IF_CONSTEXPR(nDim == 3) {
3133 m_vorticitySize = 3;
3134 m_vorticityName = new const MChar*[m_vorticitySize];
3135 for(MInt i = 0; i < 3; ++i)
3136 m_vorticityName[i] = new MChar[16];
3137
3138 m_vorticityName[0] = "vorticity(x)";
3139 m_vorticityName[1] = "vorticity(y)";
3140 m_vorticityName[2] = "vorticity(z)";
3141 }
3142 else IF_CONSTEXPR(nDim == 2) {
3143 m_vorticitySize = 1;
3144 m_vorticityName = new const MChar*[m_vorticitySize];
3145 for(MInt i = 0; i < 1; ++i)
3146 m_vorticityName[i] = new MChar[16];
3147 m_vorticityName[0] = "vorticity(z)";
3148 }
3149 else {
3150 m_vorticityName = (const MChar**)nullptr;
3151 }
3152 } else {
3153 m_vorticityName = (const MChar**)nullptr;
3154 }
3155
3168 m_outputFormat = m_levelSetMb ? "VTU" : "NETCDF";
3169 m_outputFormat = Context::getSolverProperty<MString>("outputFormat", m_solverId, AT_, &m_outputFormat);
3170
3171 if((string2enum(m_outputFormat) != NETCDF) && (string2enum(m_outputFormat) != VTU)) {
3172 m_log << "WARNING: Output format changed to " << m_outputFormat << " for massive parallel computation! " << endl;
3173 m_outputFormat = "NETCDF";
3174 }
3175 if(noDomains() > 1 && (string2enum(m_outputFormat) == VTK)) {
3176 m_log << "WARNING: Output format changed to " << m_outputFormat << " for massive parallel computation! " << endl;
3177 m_outputFormat = "VTU";
3178 }
3179
3180 m_log << " * Using output format " << m_outputFormat << endl;
3181
3182 m_outputOffset = 0;
3183 m_outputOffset = Context::getSolverProperty<MInt>("outputOffset", m_solverId, AT_, &m_outputOffset);
3184
3185 // set write-out parameters
3198 m_writeOutData = 0;
3199 m_writeOutData = Context::getSolverProperty<MInt>("writeOutData", m_solverId, AT_, &m_writeOutData);
3200
3213 m_recordBodyData = Context::getSolverProperty<MBool>("recordBodyData", m_solverId, AT_, &tmpFalse);
3214 m_recordLandA = Context::getSolverProperty<MBool>("recordLandA", m_solverId, AT_, &tmpFalse);
3215
3229 m_recordWallVorticity = Context::getSolverProperty<MBool>("recordWallVorticity", m_solverId, AT_, &tmpFalse);
3230
3231 // Set parameter for writing out cut-cell information
3245 m_writeCutCellsToGridFile = Context::getSolverProperty<MBool>("writeCutCellsToGridFile", m_solverId, AT_, &tmpFalse);
3246
3247 // set restart properties
3260 m_restartBc2800 = false;
3261 m_restartBc2800 = Context::getSolverProperty<MBool>("restartBc2800", m_solverId, AT_, &m_restartBc2800);
3262
3263 if(m_useNonSpecifiedRestartFile && isMultilevel()) {
3264 mTerm(1, "Error: useNonSpecifiedRestartFile needs to be disables for a multilevel computation");
3265 }
3266
3278 m_restartBackupInterval = 25000;
3279 m_restartBackupInterval =
3280 Context::getSolverProperty<MInt>("restartBackupInterval", m_solverId, AT_, &m_restartBackupInterval);
3281
3294 m_restartOldVariables = false;
3295 m_restartOldVariables =
3296 Context::getSolverProperty<MBool>("restartOldVariables", m_solverId, AT_, &m_restartOldVariables);
3297
3311 m_restartOldVariablesReset = false;
3312 m_restartOldVariablesReset =
3313 Context::getSolverProperty<MBool>("restartOldVariablesReset", m_solverId, AT_, &m_restartOldVariablesReset);
3314
3327 // set surface check parameter
3328 m_checkCellSurfaces = Context::getSolverProperty<MBool>("checkCellSurfaces", m_solverId, AT_, &tmpFalse);
3329 if(m_checkCellSurfaces) m_log << " * Checking cell surfaces for consistency! " << endl;
3330
3331 m_bodyIdOutput = false;
3341 m_bodyIdOutput = Context::getSolverProperty<MBool>("bodyIdOutput", m_solverId, AT_, &m_bodyIdOutput);
3342
3343 m_levelSetOutput = false;
3354 m_levelSetOutput = Context::getSolverProperty<MBool>("levelSetOutput", m_solverId, AT_, &m_levelSetOutput);
3355
3356 m_isActiveOutput = false;
3367 m_isActiveOutput = Context::getSolverProperty<MBool>("isActiveOutput", m_solverId, AT_, &m_isActiveOutput);
3368
3378 m_domainIdOutput = false;
3379 m_domainIdOutput = Context::getSolverProperty<MBool>("domainIdOutput", m_solverId, AT_, &m_domainIdOutput);
3380
3381 setSamplingProperties();
3382}
3383
3388template <MInt nDim_, class SysEqn>
3390 TRACE();
3391
3392 // Sampling properties - used for sample output in writeRestartFile:
3400 m_sampleRate = 0.000001;
3401 m_sampleRate = Context::getSolverProperty<MFloat>("sampleRate", m_solverId, AT_, &m_sampleRate);
3402
3403 m_noSamples = 0;
3411 m_samplingTimeBegin = std::numeric_limits<MFloat>::max();
3412 m_samplingTimeBegin = Context::getSolverProperty<MFloat>("samplingTimeBegin", m_solverId, AT_, &m_samplingTimeBegin);
3413
3421 m_samplingTimeEnd = 0;
3422 m_samplingTimeEnd = Context::getSolverProperty<MFloat>("samplingTimeEnd", m_solverId, AT_, &m_samplingTimeEnd);
3423
3424 // Sampling properties - used for structuredFlameOutput
3425
3433 m_samplingStartCycle = -1;
3434 m_samplingStartCycle = Context::getSolverProperty<MInt>("samplingStartCycle", m_solverId, AT_, &m_samplingStartCycle);
3435
3443 m_samplingEndCycle = -1;
3444 m_samplingEndCycle = Context::getSolverProperty<MInt>("samplingEndCycle", m_solverId, AT_, &m_samplingEndCycle);
3445
3446 // used by computeTimeStep case 17511 used by the 2D_steady_bunsen_flame testcase and in structuredFlameOutput
3447 m_samplesPerCycle = 100.;
3455 m_samplesPerCycle = Context::getSolverProperty<MFloat>("samplesPerCycle", m_solverId, AT_, &m_samplesPerCycle);
3456
3464 m_samplingStartIteration = -99999.0;
3465 m_samplingStartIteration =
3466 Context::getSolverProperty<MInt>("samplingStartIteration", m_solverId, AT_, &m_samplingStartIteration);
3467
3475 m_noSamplingCycles = 2;
3476 m_noSamplingCycles = Context::getSolverProperty<MInt>("noSamplingCycles", m_solverId, AT_, &m_noSamplingCycles);
3477
3478 // initialize number of time steps between samples
3479 m_noTimeStepsBetweenSamples = -1;
3480
3481 // force no time steps -> avoids the adaption of the timeSteps to the required number of timeSteps determined by the
3482 // applied noSamplingCycles
3483 m_forceNoTimeSteps = 0;
3484 m_forceNoTimeSteps = Context::getSolverProperty<MInt>("forceNoTimeSteps", m_solverId, AT_, &m_forceNoTimeSteps);
3485}
3486
3494template <MInt nDim_, class SysEqn>
3496 TRACE();
3497
3498 MBool tmpFalse = false;
3499
3500 // Basic initialization for all variables which belong to GequPv method
3501 m_massFlux = false;
3502 m_plenum = false;
3503 m_confinedFlame = false;
3504 m_plenumWall = false;
3505 m_useCorrectedBurningVelocity = false;
3506 m_totalDamp = false;
3507 m_MaFlameTube = m_Ma;
3508 m_pressureLossFlameSpeed = 1;
3509 m_pressureLossCorrection = F0;
3510 m_recordPressure = false;
3511 m_recordFlameFrontPosition = false;
3512 m_structuredFlameOutput = false;
3513 m_structuredFlameOutputLevel = 0;
3514 m_twoFlames = false;
3515 m_acousticAnalysis = false;
3516 m_ScT = 0;
3517
3518 if(m_combustion) {
3519 m_marksteinLength = 0.1;
3538 m_marksteinLength = Context::getSolverProperty<MFloat>("marksteinLength", m_solverId, AT_);
3539
3540 m_marksteinLengthPercentage = F1;
3551 m_marksteinLengthPercentage =
3552 Context::getSolverProperty<MFloat>("marksteinLengthPercentage", m_solverId, AT_, &m_marksteinLengthPercentage);
3553
3554 m_log << "neutral markstein length is:" << m_marksteinLength << endl;
3555
3556 m_marksteinLength *= m_marksteinLengthPercentage;
3557 m_log << "markstein length is changed to :" << m_marksteinLength << endl;
3558 m_log << "markstein length percentage is :" << m_marksteinLengthPercentage << endl;
3559
3560
3573 m_zeroLineCorrection = Context::getSolverProperty<MBool>("zeroLineCorrection", m_solverId, AT_, &tmpFalse);
3574
3575 m_inletTubeAreaRatio = F1;
3585 m_inletTubeAreaRatio =
3586 Context::getSolverProperty<MFloat>("inletTubeAreaRatio", m_solverId, AT_, &m_inletTubeAreaRatio);
3587
3588 m_inletOutletAreaRatio = F1;
3601 m_inletOutletAreaRatio =
3602 Context::getSolverProperty<MFloat>("inletOutletAreaRatio", m_solverId, AT_, &m_inletOutletAreaRatio);
3603
3604 m_flameOutletAreaRatio = F1;
3615 m_flameOutletAreaRatio =
3616 Context::getSolverProperty<MFloat>("flameOutletAreaRatio", m_solverId, AT_, &m_flameOutletAreaRatio);
3617
3632 m_massFlux = Context::getSolverProperty<MBool>("massFlux", m_solverId, AT_, &tmpFalse);
3633
3644 m_confinedFlame = Context::getSolverProperty<MBool>("confinedFlame", m_solverId, AT_, &tmpFalse);
3645
3656 m_plenum = Context::getSolverProperty<MBool>("plenum", m_solverId, AT_, &tmpFalse);
3657
3668 m_plenumWall = Context::getSolverProperty<MBool>("plenumWall", m_solverId, AT_, &tmpFalse);
3669
3670 if(m_plenumWall) {
3671 m_plenum = m_plenumWall;
3672 }
3673
3685 m_useCorrectedBurningVelocity = Context::getSolverProperty<MBool>("useCorrectedBurningVelocity", m_solverId, AT_,
3686 &m_useCorrectedBurningVelocity);
3687
3698 m_filterFlameTubeEdges = Context::getSolverProperty<MBool>("filterFlameTubeEdges", m_solverId, AT_, &tmpFalse);
3699
3700 m_filterFlameTubeEdgesDistance = -9999.9;
3710 m_filterFlameTubeEdgesDistance = Context::getSolverProperty<MFloat>("filterFlameTubeEdgesDistance", m_solverId, AT_,
3711 &m_filterFlameTubeEdgesDistance);
3712
3722 m_totalDamp = Context::getSolverProperty<MBool>("totalDamp", m_solverId, AT_, &tmpFalse);
3723
3724 m_heatReleaseDamp = 1;
3737 m_heatReleaseDamp = Context::getSolverProperty<MBool>("heatReleaseDamp", m_solverId, AT_, &m_heatReleaseDamp);
3738
3751 m_modelCheck = Context::getSolverProperty<MBool>("modelCheck", m_solverId, AT_, &tmpFalse);
3752
3770 m_flameSpeed = Context::getSolverProperty<MFloat>("flameSpeed", m_solverId, AT_);
3771
3772 m_analyticIntegralVelocity = m_Ma;
3784 m_analyticIntegralVelocity =
3785 Context::getSolverProperty<MFloat>("analyticIntegralVelocity", m_solverId, AT_, &m_analyticIntegralVelocity);
3786
3787 m_meanVelocity = F1B2 * m_Ma;
3799 m_meanVelocity = Context::getSolverProperty<MFloat>("meanVelocity", m_solverId, AT_, &m_meanVelocity);
3800
3801
3802 m_pressureLossFlameSpeed = 0;
3817 m_pressureLossFlameSpeed =
3818 Context::getSolverProperty<MInt>("pressureLossFlameSpeed", m_solverId, AT_, &m_pressureLossFlameSpeed);
3819
3820 m_pressureLossCorrection = F0;
3832 m_pressureLossCorrection =
3833 Context::getSolverProperty<MFloat>("pressureLossCorrection", m_solverId, AT_, &m_pressureLossCorrection);
3834
3835 m_constantFlameSpeed = 0;
3850 m_constantFlameSpeed =
3851 Context::getSolverProperty<MInt>("constantFlameSpeed", m_solverId, AT_, &m_constantFlameSpeed);
3852
3853 m_neutralFlameStrouhal = -F1;
3863 m_neutralFlameStrouhal =
3864 Context::getSolverProperty<MFloat>("neutralFlameStrouhal", m_solverId, AT_, &m_neutralFlameStrouhal);
3865
3866 m_noReactionCells = 0.026367201;
3885 m_noReactionCells = Context::getSolverProperty<MFloat>("noReactionCells", m_solverId, AT_, &m_noReactionCells);
3886
3887 m_MaFlameTube = m_Ma;
3898 m_MaFlameTube = Context::getSolverProperty<MFloat>("MaFlameTube", m_solverId, AT_, &m_MaFlameTube);
3899
3922 m_recordPressure = Context::getSolverProperty<MBool>("recordPressure", m_solverId, AT_, &tmpFalse);
3923
3943 m_recordFlameFrontPosition =
3944 Context::getSolverProperty<MBool>("recordFlameFrontPosition", m_solverId, AT_, &tmpFalse);
3945
3958 m_structuredFlameOutput = Context::getSolverProperty<MBool>("structuredFlameOutput", m_solverId, AT_, &tmpFalse);
3959
3976 m_structuredFlameOutputLevel = 0;
3977 m_structuredFlameOutputLevel =
3978 Context::getSolverProperty<MInt>("structuredFlameOutputLevel", m_solverId, AT_, &m_structuredFlameOutputLevel);
3979
3989 m_twoFlames = Context::getSolverProperty<MBool>("twoFlames", m_solverId, AT_, &tmpFalse);
3990
3991 m_dampingDistanceFlameBaseExtVel = 0.05;
4001 m_dampingDistanceFlameBaseExtVel = Context::getSolverProperty<MFloat>("dampingDistanceFlameBaseExtVel", m_solverId,
4002 AT_, &m_dampingDistanceFlameBaseExtVel);
4003
4004
4005 m_dampingDistanceFlameBase = 0.259;
4015 m_dampingDistanceFlameBase =
4016 Context::getSolverProperty<MFloat>("dampingDistanceFlameBase", m_solverId, AT_, &m_dampingDistanceFlameBase);
4017
4018 m_initialFlameHeight = F1;
4033 m_initialFlameHeight =
4034 Context::getSolverProperty<MFloat>("initialFlameHeight", m_solverId, AT_, &m_initialFlameHeight);
4035
4036 m_radiusFlameTube = 0.5;
4053 m_radiusFlameTube = Context::getSolverProperty<MFloat>("radiusFlameTube", m_solverId, AT_, &m_radiusFlameTube);
4054
4066 m_radiusVelFlameTube =
4067 Context::getSolverProperty<MFloat>("radiusVelFlameTube", m_solverId, AT_, &m_radiusFlameTube);
4068
4080 m_radiusOutlet = Context::getSolverProperty<MFloat>("radiusOutlet", m_solverId, AT_, &m_radiusFlameTube);
4081
4082 m_realRadiusFlameTube = m_radiusFlameTube;
4093 m_realRadiusFlameTube =
4094 Context::getSolverProperty<MFloat>("realRadiusFlameTube", m_solverId, AT_, &m_realRadiusFlameTube);
4095
4109 m_radiusFlameTube2 = Context::getSolverProperty<MFloat>("radiusFlameTube2", m_solverId, AT_, &m_radiusFlameTube);
4110
4111
4112 m_radiusInjector = F2;
4124 m_radiusInjector = Context::getSolverProperty<MFloat>("radiusInjector", m_solverId, AT_, &m_radiusInjector);
4125
4126 m_yOffsetInjector = -12.48535161836571205000;
4138 m_yOffsetInjector = Context::getSolverProperty<MFloat>("yOffsetInjector", m_solverId, AT_, &m_yOffsetInjector);
4139
4140 m_yOffsetFlameTube = 0.04;
4159 m_yOffsetFlameTube = Context::getSolverProperty<MFloat>("yOffsetFlameTube", m_solverId, AT_, &m_yOffsetFlameTube);
4160
4175 m_yOffsetFlameTube2 = Context::getSolverProperty<MFloat>("yOffsetFlameTube2", m_solverId, AT_, &m_yOffsetFlameTube);
4176
4177 m_xOffsetFlameTube = 0.0;
4196 m_xOffsetFlameTube = Context::getSolverProperty<MFloat>("xOffsetFlameTube", m_solverId, AT_, &m_xOffsetFlameTube);
4197
4198 m_xOffsetFlameTube2 = -m_xOffsetFlameTube;
4217 m_xOffsetFlameTube2 = Context::getSolverProperty<MFloat>("xOffsetFlameTube2", m_solverId, AT_, &m_xOffsetFlameTube);
4218
4219 m_tubeLength = 0;
4238 m_tubeLength = Context::getSolverProperty<MFloat>("tubeLength", m_solverId, AT_, &m_tubeLength);
4239
4240 m_outletLength = 0;
4259 m_outletLength = Context::getSolverProperty<MFloat>("outletLength", m_solverId, AT_, &m_outletLength);
4260
4261 m_laminarFlameThickness = c_cellLengthAtLevel(maxRefinementLevel());
4278 m_laminarFlameThickness =
4279 Context::getSolverProperty<MFloat>("laminarFlameThickness", m_solverId, AT_, &m_laminarFlameThickness);
4280
4281 m_subfilterVariance = F1;
4309 m_subfilterVariance =
4310 Context::getSolverProperty<MFloat>("subfilterVariance", m_solverId, AT_, &m_subfilterVariance);
4311
4312 m_c0 = 0.5;
4323 m_c0 = Context::getSolverProperty<MFloat>("c0", m_solverId, AT_, &m_c0);
4324
4325 if(m_restart) {
4326 m_rhoUnburnt = -99999.0;
4337 m_rhoUnburnt = Context::getSolverProperty<MFloat>("rhoUnburnt", m_solverId, AT_, &m_rhoUnburnt);
4338 if(approx(m_rhoUnburnt, -99999.0, MFloatEps)
4339 && (m_initialCondition == 1990 || m_initialCondition == 19901 || m_initialCondition == 1991
4340 || m_initialCondition == 19911)) {
4341 cerr << " rho unburnt should be set in your property file, as well TbTu and marksteinLength, see file "
4342 "HeatChange and MarksteinNeutral files !!!"
4343 << endl;
4344 mTerm(1, AT_, "Error for rhoUnburnt property");
4345 }
4346 }
4347
4348 m_burntUnburntTemperatureRatio = F1;
4360 m_burntUnburntTemperatureRatio = Context::getSolverProperty<MFloat>("burntUnburntTemperatureRatio", m_solverId, AT_,
4361 &m_burntUnburntTemperatureRatio);
4362
4363 m_temperatureChange = 0;
4376 m_temperatureChange = Context::getSolverProperty<MInt>("temperatureChange", m_solverId, AT_, &m_temperatureChange);
4377
4378 if(m_temperatureChange != 0) {
4390 m_burntUnburntTemperatureRatioStart =
4391 Context::getSolverProperty<MFloat>("burntUnburntTemperatureRatioStart", m_solverId, AT_);
4392
4393 m_burntUnburntTemperatureRatioEnd = m_burntUnburntTemperatureRatio;
4405 m_burntUnburntTemperatureRatioEnd = Context::getSolverProperty<MFloat>(
4406 "burntUnburntTemperatureRatioEnd", m_solverId, AT_, &m_burntUnburntTemperatureRatioEnd);
4407 }
4408
4409 m_targetDensityFactor = F1 / m_burntUnburntTemperatureRatio;
4428 m_targetDensityFactor =
4429 Context::getSolverProperty<MFloat>("targetDensityFactor", m_solverId, AT_, &m_targetDensityFactor);
4430 if(!approx(m_targetDensityFactor, (F1 / m_burntUnburntTemperatureRatio), MFloatEps)) {
4431 cerr << "Warning: target density factor is not equal to the inverse of the burnt unburnt temperature ratio!!!"
4432 << endl;
4433 cerr << "targetDensityFactor = " << m_targetDensityFactor << endl;
4434 cerr << "-> change the targetDensityFactor to " << F1 / m_burntUnburntTemperatureRatio << endl;
4435 }
4436
4437 m_deltaXtemperatureProfile = 0.00;
4449 m_deltaXtemperatureProfile =
4450 Context::getSolverProperty<MFloat>("deltaXtemperatureProfile", m_solverId, AT_, &m_deltaXtemperatureProfile);
4451
4452 m_deltaYtemperatureProfile = 0.01;
4464 m_deltaYtemperatureProfile =
4465 Context::getSolverProperty<MFloat>("deltaYtemperatureProfile", m_solverId, AT_, &m_deltaYtemperatureProfile);
4466
4467 m_thermalProfileStartFactor = F1;
4478 m_thermalProfileStartFactor =
4479 Context::getSolverProperty<MFloat>("thermalProfileStartFactor", m_solverId, AT_, &m_thermalProfileStartFactor);
4480
4481 m_flameRadiusOffset = F0;
4493 m_flameRadiusOffset =
4494 Context::getSolverProperty<MFloat>("flameRadiusOffset", m_solverId, AT_, &m_flameRadiusOffset);
4495
4496 m_shearLayerStrength = 50.0;
4507 m_shearLayerStrength =
4508 Context::getSolverProperty<MFloat>("shearLayerStrength", m_solverId, AT_, &m_shearLayerStrength);
4509
4510 m_inflowTemperatureRatio = F1;
4522 m_inflowTemperatureRatio =
4523 Context::getSolverProperty<MFloat>("inflowTemperatureRatio", m_solverId, AT_, &m_inflowTemperatureRatio);
4524
4525 m_lambdaPerturbation = F1;
4537 m_lambdaPerturbation =
4538 Context::getSolverProperty<MFloat>("lambdaPerturbation", m_solverId, AT_, &m_lambdaPerturbation);
4539
4540 m_perturbationAmplitude = 0.001;
4552 m_perturbationAmplitude =
4553 Context::getSolverProperty<MFloat>("perturbationAmplitude", m_solverId, AT_, &m_perturbationAmplitude);
4554
4555 m_perturbationAmplitudeCorr = m_perturbationAmplitude;
4567 m_perturbationAmplitudeCorr =
4568 Context::getSolverProperty<MFloat>("perturbationAmplitudeCorr", m_solverId, AT_, &m_perturbationAmplitudeCorr);
4569
4582 m_divergenceTreatment = Context::getSolverProperty<MBool>("divergenceTreatment", m_solverId, AT_, &tmpFalse);
4583
4596 m_acousticAnalysis = Context::getSolverProperty<MBool>("acousticAnalysis", m_solverId, AT_, &m_acousticAnalysis);
4597
4598 m_ScT = 0.4; // Pitsch et al. 2005 (ScT=0.4) and 2000 (ScT=0.5) -> a constant value can be used
4610 m_ScT = Context::getSolverProperty<MFloat>("ScT", m_solverId, AT_, &m_ScT);
4611
4612 m_NuT = 0.0017169; // computed by cold slot jet with grid refinement r11 at y=-0.5
4624 m_NuT = Context::getSolverProperty<MFloat>("NuT", m_solverId, AT_, &m_NuT);
4625
4626 m_integralAmplitude = 0.015188;
4638 m_integralAmplitude =
4639 Context::getSolverProperty<MFloat>("integralAmplitude", m_solverId, AT_, &m_integralAmplitude);
4640
4641 m_integralLengthScale = 0.3;
4653 m_integralLengthScale =
4654 Context::getSolverProperty<MFloat>("integralLengthScale", m_solverId, AT_, &m_integralLengthScale);
4655 }
4656}
4657
4658
4659//------------------------------------------------------------------------------------------------------------------------------------------
4660
4667template <MInt nDim_, class SysEqn>
4669 TRACE();
4670
4683 m_jet = false;
4684 m_jet = Context::getSolverProperty<MBool>("jet", m_solverId, AT_, &m_jet);
4685
4693 m_chevron = false;
4694 m_chevron = Context::getSolverProperty<MBool>("chevron", m_solverId, AT_, &m_chevron);
4695
4696 if(m_chevron) {
4707 m_maNozzleExit = -1.0;
4708 m_maNozzleExit = Context::getSolverProperty<MFloat>("machNozzleExit", m_solverId, AT_);
4709
4720 m_inletRadius = -1.0;
4721 m_inletRadius = Context::getSolverProperty<MFloat>("inletRadius", m_solverId, AT_);
4722
4733 m_outletRadius = -1.0;
4734 m_outletRadius = Context::getSolverProperty<MFloat>("outletRadius", m_solverId, AT_);
4735
4747 m_normJetTemperature = 1.0;
4748 m_normJetTemperature = Context::getSolverProperty<MFloat>("jetTemperature", m_solverId, AT_);
4749
4750 // Note: also read below for m_jet
4751 m_momentumThickness = 0.05;
4752 m_momentumThickness =
4753 Context::getSolverProperty<MFloat>("momentumThickness", m_solverId, AT_, &m_momentumThickness);
4754 }
4755
4756 if(m_jet) {
4769 m_jetForcing = false;
4770 m_jetForcing = Context::getSolverProperty<MBool>("jetForcing", m_solverId, AT_, &m_jetForcing);
4771
4783 m_shearLayerThickness = F0;
4784 m_shearLayerThickness =
4785 Context::getSolverProperty<MFloat>("shearLayerThickness", m_solverId, AT_, &m_shearLayerThickness);
4786
4798 m_MaCoflow = F0;
4799 m_MaCoflow = Context::getSolverProperty<MFloat>("MaCoflow", m_solverId, AT_, &m_MaCoflow);
4800 m_jetHalfWidth = 0.5;
4801 m_jetCoflowOffset = m_jetHalfWidth + 0.125;
4802 m_jetCoflowEndOffset = m_jetHalfWidth + 2.375;
4803 m_jetHalfLength = 4.165;
4804 m_jetHalfLength = Context::getSolverProperty<MFloat>("jetHalfLength", m_solverId, AT_, &m_jetHalfLength);
4805 m_primaryJetRadius = F1B4;
4806 m_secondaryJetRadius = F1B2;
4807 m_forceCoefficient = F0;
4808 m_densityRatio = F1;
4809 m_targetVelocityFactor = F1;
4810 m_modeNumbers = F0;
4811 m_momentumThickness = F0;
4812 m_jetType = 0;
4813
4827 m_jetHeight = F1B2;
4828 m_jetHeight = Context::getSolverProperty<MFloat>("jetHeight", m_solverId, AT_, &m_jetHeight);
4829
4841 m_primaryJetRadius = Context::getSolverProperty<MFloat>("primaryJetRadius", m_solverId, AT_, &m_primaryJetRadius);
4853 m_secondaryJetRadius =
4854 Context::getSolverProperty<MFloat>("secondaryJetRadius", m_solverId, AT_, &m_secondaryJetRadius);
4866 m_targetVelocityFactor =
4867 Context::getSolverProperty<MFloat>("targetVelocityFactor", m_solverId, AT_, &m_targetVelocityFactor);
4868
4881 m_jetForcingPosition = 0.5;
4882 m_jetForcingPosition =
4883 Context::getSolverProperty<MFloat>("jetForcingPosition", m_solverId, AT_, &m_jetForcingPosition);
4884
4897 m_jetRandomSeed = 1;
4898 m_jetRandomSeed = Context::getSolverProperty<MFloat>("jetRandomSeed", m_solverId, AT_, &m_jetRandomSeed);
4899
4911 m_modeNumbers = Context::getSolverProperty<MInt>("modeNumbers", m_solverId, AT_, &m_modeNumbers);
4912
4923 m_momentumThickness = 0.025;
4924 m_momentumThickness =
4925 Context::getSolverProperty<MFloat>("momentumThickness", m_solverId, AT_, &m_momentumThickness);
4926
4939 m_jetType = Context::getSolverProperty<MInt>("jetType", m_solverId, AT_, &m_jetType);
4940
4951 m_forceCoefficient = 0.007;
4952 m_forceCoefficient = Context::getSolverProperty<MFloat>("forceCoefficient", m_solverId, AT_, &m_forceCoefficient);
4953 m_densityRatio = Context::getSolverProperty<MFloat>("densityRatio", m_solverId, AT_, &m_densityRatio);
4954
4955 if(Context::propertyExists("jetConst", m_solverId)) {
4967 m_noJetConst = Context::propertyLength("jetConst", m_solverId);
4968
4969 mAlloc(m_jetConst, m_noJetConst, "m_jetConst", F0, AT_);
4970 for(MInt i = 0; i < m_noJetConst; i++) {
4971 m_jetConst[i] = Context::getSolverProperty<MFloat>("jetConst", m_solverId, AT_, &m_jetConst[i], i);
4972 m_log << "jet constants a = " << m_jetConst[i] << endl;
4973 }
4974 }
4975 }
4976}
4977
4978
4986template <MInt nDim_, class SysEqn>
4988 TRACE();
4989 MBool tmpFalse = false;
4990
4991 // used for debugging
4992 m_noSpongeBndryCndIds = Context::propertyLength("spongeBndryCndIds", m_solverId);
4993
4994 if(Context::propertyLength("spongeBndryCndIds", m_solverId) != Context::propertyLength("spongeFactor", m_solverId)
4995 || Context::propertyLength("spongeFactor", m_solverId) != Context::propertyLength("spongeDirections", m_solverId)
4996 || Context::propertyLength("spongeDirections", m_solverId) != Context::propertyLength("sigmaSponge", m_solverId)) {
4997 cerr << "ERROR: sponge properties don't have the same size" << endl << endl;
4998 cerr << "check the number of the following properties: " << endl;
4999 cerr << " - spongeBndryCndIds " << endl;
5000 cerr << " - sigmaSponge " << endl;
5001 cerr << " - spongeDirections " << endl;
5002 cerr << " - spongeFactor " << endl;
5003 mTerm(1, AT_, "ERROR: sponge properties don't have the same array size");
5004 }
5005
5006 // Deallocate all previously allocated memory (if not nullptr)
5007 mDeallocate(m_spongeDirections);
5008 mDeallocate(m_spongeBndryCndIds);
5009 mDeallocate(m_spongeFactor);
5010 mDeallocate(m_sigmaSpongeBndryId);
5011 mDeallocate(m_sigmaEndSpongeBndryId);
5012 mDeallocate(m_spongeTimeDependent);
5013 mDeallocate(m_spongeStartIteration);
5014 mDeallocate(m_spongeEndIteration);
5015 mDeallocate(m_spongeCoord);
5016
5017 // allocate space for sponge variables
5018 mAlloc(m_spongeDirections, m_noSpongeBndryCndIds, "m_spongeDirections", -1, AT_);
5019 mAlloc(m_spongeBndryCndIds, m_noSpongeBndryCndIds, "m_spongeBndryCndIds", 1, AT_);
5020 mAlloc(m_spongeFactor, m_noSpongeBndryCndIds, "m_spongeFactor", F1, AT_);
5021 mAlloc(m_sigmaSpongeBndryId, m_noSpongeBndryCndIds, "m_sigmaSpongeBndryId", F0, AT_);
5022 mAlloc(m_sigmaEndSpongeBndryId, m_noSpongeBndryCndIds, "m_sigmaEndSpongeBndryId", 100000.0, AT_);
5023 mAlloc(m_spongeTimeDependent, m_noSpongeBndryCndIds, "m_spongeTimeDependent", 0, AT_);
5024 mAlloc(m_spongeStartIteration, m_noSpongeBndryCndIds, "m_spongeStartIteration", F0, AT_);
5025 mAlloc(m_spongeEndIteration, m_noSpongeBndryCndIds, "m_spongeEndIteration", 100000.0, AT_);
5026 mAlloc(m_spongeCoord, m_noSpongeBndryCndIds, "m_spongeCoord", -100000.0, AT_);
5027
5028 for(MInt i = 0; i < m_noSpongeBndryCndIds; i++) {
5043 m_spongeFactor[i] = Context::getSolverProperty<MFloat>("spongeFactor", m_solverId, AT_, &m_spongeFactor[i], i);
5044
5057 m_spongeDirections[i] =
5058 Context::getSolverProperty<MInt>("spongeDirections", m_solverId, AT_, &m_spongeDirections[i], i);
5059
5070 m_spongeBndryCndIds[i] =
5071 Context::getSolverProperty<MInt>("spongeBndryCndIds", m_solverId, AT_, &m_spongeBndryCndIds[i], i);
5072
5084 m_sigmaSpongeBndryId[i] =
5085 Context::getSolverProperty<MFloat>("sigmaSponge", m_solverId, AT_, &m_sigmaSpongeBndryId[i], i);
5086
5098 m_sigmaEndSpongeBndryId[i] =
5099 Context::getSolverProperty<MFloat>("sigmaEndSponge", m_solverId, AT_, &m_sigmaEndSpongeBndryId[i], i);
5100
5111 m_spongeStartIteration[i] =
5112 Context::getSolverProperty<MFloat>("spongeStartIteration", m_solverId, AT_, &m_spongeStartIteration[i], i);
5113
5114
5125 m_spongeEndIteration[i] =
5126 Context::getSolverProperty<MFloat>("spongeEndIteration", m_solverId, AT_, &m_spongeEndIteration[i], i);
5127
5141 m_spongeTimeDependent[i] =
5142 Context::getSolverProperty<MInt>("spongeTimeDependent", m_solverId, AT_, &m_spongeTimeDependent[i], i);
5143
5144 if(!m_spongeTimeDep && m_spongeTimeDependent[i] >= 1) {
5145 m_spongeTimeDep = true;
5146 }
5147 }
5148
5161 m_noMaxSpongeBndryCells =
5162 Context::getSolverProperty<MInt>("noMaxSpongeBndryCells", m_solverId, AT_, &m_noMaxSpongeBndryCells);
5163
5185 m_spongeLayerLayout = Context::getSolverProperty<MInt>("spongeLayerLayout", m_solverId, AT_, &m_spongeLayerLayout);
5186 if(m_spongeLayerLayout != 0) {
5187 cerr << "WARNING: spongeLayerLayout " << m_spongeLayerLayout
5188 << " not yet implemented for the new create sponge at a specified boundary" << endl;
5189 }
5190
5210 m_spongeLayerType = Context::getSolverProperty<MInt>("spongeLayerType", m_solverId, AT_, &m_spongeLayerType);
5211
5212 if(!m_combustion) {
5230 m_targetDensityFactor =
5231 Context::getSolverProperty<MFloat>("targetDensityFactor", m_solverId, AT_, &m_targetDensityFactor);
5232 }
5233
5234 m_spongeReductionFactor = F1;
5253 m_spongeReductionFactor =
5254 Context::getSolverProperty<MFloat>("spongeReductionFactor", m_solverId, AT_, &m_spongeReductionFactor);
5255
5270 m_velocitySponge = Context::getSolverProperty<MBool>("velocitySponge", m_solverId, AT_, &tmpFalse);
5271
5272 // if(m_velocitySponge){
5273 m_spongeWeight = 1.0;
5286 m_spongeWeight = Context::getSolverProperty<MFloat>("spongeWeight", m_solverId, AT_, &m_spongeWeight);
5287 // }
5288
5289 m_spongeBeta = F1;
5301 m_spongeBeta = Context::getSolverProperty<MFloat>("spongeBeta", m_solverId, AT_, &m_spongeBeta);
5302
5315 m_specialSpongeTreatment = Context::getSolverProperty<MBool>("specialSpongeTreatment", m_solverId, AT_, &tmpFalse);
5316}
5317
5318//----------------------------------------------------------------------------
5319
5320
5327template <MInt nDim_, class SysEqn>
5329 TRACE();
5330
5331 mDeallocate(m_spongeFactor);
5332 mAlloc(m_spongeFactor, 2 * nDim, "m_spongeFactor", F0, AT_);
5333 mDeallocate(m_spongeCoord);
5334 mAlloc(m_spongeCoord, 4 * nDim, "m_spongeFactor", F0, AT_);
5335
5350 m_sigmaSponge = Context::getSolverProperty<MFloat>("sigmaSponge", m_solverId, AT_);
5351
5366 m_sigmaSpongeInflow = Context::getSolverProperty<MFloat>("sigmaSpongeInflow", m_solverId, AT_, &m_sigmaSponge);
5367
5368 if((m_sigmaSponge > F0) || (m_sigmaSpongeInflow > F0)) {
5385 for(MInt i = 0; i < 2 * nDim; i++) {
5386 m_spongeFactor[i] = F1;
5387 }
5388 m_noSpongeFactors = 2 * nDim;
5389 if(Context::propertyExists("spongeFactor", m_solverId))
5390 m_noSpongeFactors = Context::propertyLength("spongeFactor", m_solverId);
5391 if(m_noSpongeFactors != 2 * nDim) {
5392 stringstream errorMessage;
5393 errorMessage << " Error in FvCartesianSolver::FvCartesianSolver Constructor: number of sponge factors is "
5394 "not equal 2 * space "
5395 "dimensions -> please provide "
5396 << 2 * nDim << " sponge factors in property spongeFactor! Exiting!";
5397 mTerm(1, AT_, errorMessage.str());
5398 }
5399 for(MInt i = 0; i < m_noSpongeFactors; i++) {
5400 m_spongeFactor[i] = Context::getSolverProperty<MFloat>("spongeFactor", m_solverId, AT_, &m_spongeFactor[i], i);
5401 }
5402
5429 m_spongeLayerLayout = Context::getSolverProperty<MInt>("spongeLayerLayout", m_solverId, AT_, &m_spongeLayerLayout);
5430
5450 m_spongeLayerType = Context::getSolverProperty<MInt>("spongeLayerType", m_solverId, AT_, &m_spongeLayerType);
5451
5452 if(!m_combustion) {
5470 m_targetDensityFactor =
5471 Context::getSolverProperty<MFloat>("targetDensityFactor", m_solverId, AT_, &m_targetDensityFactor);
5472 }
5473 }
5474
5475 return allocatedBytes;
5476}
5477
5478
5485template <MInt nDim_, class SysEqn>
5487 TRACE();
5488
5489 const MInt maxNoCells = maxNoGridCells();
5490
5491 // the following properties are always used and thus must be initialized!
5492 m_adaptationSinceLastRestart = false; // if no adaptation is used, the grid is never adapted since the last restart!
5493 m_adaptationSinceLastRestartBackup =
5494 false; // if no adaptation is used, the grid is never adapted since the last restart!
5495
5496 m_currentGridFileName = grid().gridInputFileName();
5497
5498 m_forceRestartGrid = false;
5499 m_forceRestartGrid = Context::getSolverProperty<MBool>("forceRestartGrid", m_solverId, AT_, &m_forceRestartGrid);
5500
5501 m_recalcIds = nullptr;
5502
5503
5515 this->m_adaptationInterval = 0;
5516 this->m_adaptationInterval =
5517 Context::getSolverProperty<MInt>("adaptationInterval", m_solverId, AT_, &this->m_adaptationInterval);
5518
5519 m_allowInterfaceRefinement = false;
5520 m_allowInterfaceRefinement =
5521 Context::getSolverProperty<MBool>("allowInterfaceRefinement", m_solverId, AT_, &m_allowInterfaceRefinement);
5522
5523 mAlloc(m_recalcIds, maxNoCells, "m_recalcIds", -1, AT_);
5524
5525 for(MInt i = 0; i < maxNoCells; i++) {
5526 m_recalcIds[i] = i;
5527 }
5528
5529
5530 mAlloc(m_innerBandWidth, maxRefinementLevel(), "m_innerBandWidth", F0, AT_);
5531 mAlloc(m_outerBandWidth, maxRefinementLevel(), "m_outerBandWidth", F0, AT_);
5532 mAlloc(m_bandWidth, maxRefinementLevel(), "m_bandWidth", 0, AT_);
5533 if(m_sensorParticle) {
5534 mAlloc(m_particleWidth, maxRefinementLevel(), "m_particleWidth", 0, AT_);
5535 MInt range[2] = {2, 0};
5536 for(MInt i = 0; i < 2; i++) {
5537 range[i] = Context::getSolverProperty<MInt>("particleAdapRange", solverId(), AT_, &range[i], i);
5538 }
5539 if(range[1] < 2) {
5540 mTerm(1, AT_, "Particle adaptation range in FV solver not set correctly!");
5541 }
5542 m_particleWidth[maxRefinementLevel() - 1] = range[0];
5543 for(MInt i = maxRefinementLevel() - 2; i >= 0; i--) {
5544 m_particleWidth[i] = (m_particleWidth[i + 1] / 2) + 1 + range[1];
5545 }
5546 }
5547
5559 MFloat distFac[2] = {18.0, 9.0};
5560 for(MInt i = 0; i < 2; i++) {
5561 distFac[i] = Context::getSolverProperty<MFloat>("mbBandWidth", m_solverId, AT_, &distFac[i], i);
5562 }
5563 m_outerBandWidth[maxRefinementLevel() - 1] = distFac[0] * c_cellLengthAtLevel(maxRefinementLevel());
5564 m_bandWidth[maxRefinementLevel() - 1] = distFac[0];
5565 for(MInt i = maxRefinementLevel() - 2; i >= 0; i--) {
5566 m_outerBandWidth[i] = m_outerBandWidth[i + 1] + (distFac[1] * c_cellLengthAtLevel(i + 1));
5567 m_bandWidth[i] = (m_bandWidth[i + 1] / 2) + 1 + distFac[1];
5568 }
5569 for(MInt i = 0; i < maxRefinementLevel(); i++) {
5570 m_innerBandWidth[i] = -m_outerBandWidth[i];
5571 m_log << "bandwidth level " << i << ": " << m_innerBandWidth[i] << " " << m_outerBandWidth[i] << endl;
5572 }
5573
5574 m_adaptationDampingDistance = std::numeric_limits<MFloat>::max();
5575
5576
5577 m_refineDiagonals = true;
5589 m_refineDiagonals = Context::getSolverProperty<MBool>("refineDiagonals", m_solverId, AT_, &m_refineDiagonals);
5590}
5591
5592template <MInt nDim_, class SysEqn>
5594 TRACE();
5595
5596 // RANS
5597 MBool fullRANS = false;
5598 m_zonal = false;
5599 m_zonalRestartInterpolationSolverId = 0;
5600 m_rans = false;
5601 m_noRansEquations = 0;
5602 m_turbulenceDegree = F0;
5603
5615 if(Context::propertyExists("fullRANS", m_solverId)) {
5616 fullRANS = Context::getSolverProperty<MBool>("fullRANS", m_solverId, AT_, &fullRANS);
5617 }
5618
5619 if(fullRANS) {
5620 m_log << "Starting a full RANS computation" << endl;
5621 m_rans = true;
5622 }
5623
5624 m_azimuthalAngle = F0;
5625 m_azimuthalAngle = Context::getBasicProperty<MFloat>("azimuthalAngle", AT_, &m_azimuthalAngle);
5626
5634 m_multipleFvSolver = Context::getSolverProperty<MBool>("multipleFv", m_solverId, AT_, &m_multipleFvSolver);
5635
5636 if(Context::propertyExists("zonal")) {
5637 m_zonal = Context::getBasicProperty<MBool>("zonal", AT_, &m_zonal);
5638 }
5639
5640 if(m_zonal) {
5641 if(Context::getBasicProperty<MInt>("noRANSSolvers", AT_) > 0) {
5642 MInt noRANSSolvers = Context::getBasicProperty<MInt>("noRANSSolvers", AT_, &noRANSSolvers);
5643 for(MInt b = 0; b < noRANSSolvers; b++) {
5644 MInt RANSSolver = Context::getBasicProperty<MInt>("RANSSolver", AT_, &RANSSolver, b);
5645
5646 if(m_solverId == RANSSolver) {
5647 m_rans = true;
5648 }
5649 }
5650 }
5651 m_zonalTransferInterval = Context::getSolverProperty<MInt>("zonalTransferInterval", m_solverId, AT_);
5652 m_multipleFvSolver = true;
5653
5654 m_zonalAveragingTimeStep =
5655 Context::getSolverProperty<MInt>("zonalAveragingTimeStep", m_solverId, AT_, &m_zonalAveragingTimeStep);
5656 }
5657
5658 if(Context::propertyExists("calcLESAverage")) {
5659 m_calcLESAverage = Context::getSolverProperty<MBool>("calcLESAverage", m_solverId, AT_, &m_calcLESAverage);
5660 }
5661
5662 if(Context::propertyExists("preliminarySponge")) {
5663 m_preliminarySponge = Context::getSolverProperty<MBool>("preliminarySponge", m_solverId, AT_, &m_preliminarySponge);
5664 }
5665
5666 if(m_zonal || m_preliminarySponge) {
5667 m_STGSponge = Context::getSolverProperty<MBool>("STGSponge", m_solverId, AT_, &m_STGSponge);
5668
5669 if(m_STGSponge) {
5670 m_stgSpongeTimeStep =
5671 Context::getSolverProperty<MInt>("stgSpongeTimeStep", m_solverId, AT_, &m_stgSpongeTimeStep);
5672 m_noStgSpongePositions = Context::propertyLength("stgSpongePositions", m_solverId);
5673 mAlloc(m_stgSpongePositions, m_noStgSpongePositions, "m_stgSpongePositions", FUN_);
5674 for(MInt i = 0; i < m_noStgSpongePositions; i++) {
5675 m_stgSpongePositions[i] =
5676 Context::getSolverProperty<MFloat>("stgSpongePositions", m_solverId, AT_, &m_stgSpongePositions[i], i);
5677 }
5678 if(Context::propertyExists("limitFactor")) {
5679 m_spongeLimitFactor = Context::getBasicProperty<MFloat>("limitFactor", AT_, &m_spongeLimitFactor);
5680 }
5681 }
5682 }
5683
5691 if(m_calcLESAverage) {
5692 m_restartLESAverage = Context::getSolverProperty<MBool>("restartLESAverage", m_solverId, AT_, &m_restartLESAverage);
5693 m_averageStartTimeStep =
5694 Context::getSolverProperty<MInt>("averageStartTimeStep", m_solverId, AT_, &m_averageStartTimeStep);
5695 m_LESNoVarAverage = Context::getSolverProperty<MInt>("noLESAverageVar", m_solverId, AT_, &m_LESNoVarAverage);
5696
5697 m_7901Position = Context::getBasicProperty<MFloat>("bc7901Position", AT_, &m_7901Position);
5698 m_7901faceNormalDir = Context::getBasicProperty<MInt>("bc7901faceNormalDir", AT_, &m_7901faceNormalDir);
5699 m_7901periodicDir = Context::getBasicProperty<MInt>("bc7901periodicDir", AT_, &m_7901periodicDir);
5700 m_7901wallDir = Context::getBasicProperty<MInt>("bc7901wallDir", AT_, &m_7901wallDir);
5701 }
5702
5703 if(m_STGSponge && !m_calcLESAverage) mTerm(1, "calcLESAverage has to be turned on while using STGSponge");
5704
5705 if(Context::propertyExists("stgStartTimeStep")) {
5706 m_stgStartTimeStep = Context::getSolverProperty<MInt>("stgStartTimeStep", m_solverId, AT_, &m_stgStartTimeStep);
5707 }
5708 if(Context::propertyExists("rntStartTimeStep")) {
5709 m_rntStartTimeStep = Context::getSolverProperty<MInt>("rntStartTimeStep", m_solverId, AT_, &m_rntStartTimeStep);
5710 }
5711
5712 m_resetInitialCondition = false;
5713 if(Context::propertyExists("resetInitialCondition")) {
5714 m_resetInitialCondition = Context::getBasicProperty<MBool>("resetInitialCondition", AT_, &m_resetInitialCondition);
5715 } else if(Context::propertyExists("nonZonalRestart")) {
5716 m_resetInitialCondition = Context::getBasicProperty<MBool>("nonZonalRestart", AT_, &m_resetInitialCondition);
5717 }
5718
5719 if(m_resetInitialCondition) {
5720 m_zonalRestartInterpolationSolverId = Context::getSolverProperty<MInt>(
5721 "zonalRestartInterpolationSolverId", m_solverId, AT_, &m_zonalRestartInterpolationSolverId);
5722 }
5723
5724 if(m_resetInitialCondition && domainId() == 0) {
5725 cerr << "Resetting initial Condition and times!" << endl;
5726 }
5727
5728 if(m_rans) {
5729 m_noRansEquations = SysEqn::m_noRansEquations;
5730
5731 if(m_noRansEquations == 0) mTerm(1, "RANS activated, but noRansEquations equal to 0");
5732
5733 m_ransTransPos = -1000000.0;
5734 if(Context::propertyExists("ransTransPos", m_solverId)) {
5735 m_ransTransPos = Context::getSolverProperty<MFloat>("ransTransPos", m_solverId, AT_, &m_ransTransPos);
5736 }
5737 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_FS) {
5738 m_turbulenceDegree = Context::getSolverProperty<MFloat>("turbulenceDegree", m_solverId, AT_, &m_turbulenceDegree);
5739 }
5740 }
5741
5742 // STG
5754 m_stgIsActive = false;
5755 if(Context::propertyExists("useSTG", m_solverId)) {
5756 m_stgIsActive = Context::getSolverProperty<MBool>("useSTG", m_solverId, AT_, &m_stgIsActive);
5757 }
5758
5759 if(m_stgIsActive) {
5767 if(!Context::propertyExists("bc7909RANSSolverType", m_solverId)) {
5768 mTerm(-1, "Property 'bc7909RANSSolverType' required for bc7909, but not found!");
5769 }
5770 m_bc7909RANSSolverType =
5771 Context::getSolverProperty<MString>("bc7909RANSSolverType", m_solverId, AT_, &m_bc7909RANSSolverType);
5772
5773 mAlloc(m_stgEddieCoverage, 3, maxNoGridCells(), "m_stgEddieCoverage", F0, AT_);
5774 }
5775}
5776
5777
5782template <MInt nDim_, class SysEqn>
5784 TRACE();
5785
5786 // Allocate and initialize Runge-Kutta coefficients:
5787 m_noRKSteps = 5;
5799 m_noRKSteps = Context::getSolverProperty<MInt>("noRKSteps", m_solverId, AT_, &m_noRKSteps);
5800
5801 mDeallocate(m_RKalpha);
5802 mAlloc(m_RKalpha, m_noRKSteps, "m_RKalpha", -F1, AT_);
5803
5804 MFloat RK5DefaultCoeffs[5] = {0.25, 0.16666666666, 0.375, 0.5, 1.};
5816 if(m_noRKSteps == 5) { // default only valid m_noRKSteps == 5
5817 for(MInt i = 0; i < m_noRKSteps; i++) {
5818 m_RKalpha[i] = Context::getSolverProperty<MFloat>("rkalpha-step", m_solverId, AT_, &RK5DefaultCoeffs[i], i);
5819 }
5820 } else { // otherwise currently no default is set -> can be extended later
5821 for(MInt i = 0; i < m_noRKSteps; i++) {
5822 m_RKalpha[i] = Context::getSolverProperty<MFloat>("rkalpha-step", m_solverId, AT_, i);
5823 }
5824 }
5825
5826 m_rungeKuttaOrder = 2;
5839 m_rungeKuttaOrder = Context::getSolverProperty<MInt>("rungeKuttaOrder", m_solverId, AT_, &m_rungeKuttaOrder);
5840}
5841
5848template <MInt nDim_, class SysEqn>
5850 TRACE();
5851
5852 MFloat pressureLoss = F0;
5853
5854 m_log << "TbTu = " << m_burntUnburntTemperatureRatio << endl;
5855 // compute the flame strouhal number for forced cases
5856 if(m_forcing || m_structuredFlameOutput) {
5857 const MFloat slOverU = m_flameSpeed / m_MaFlameTube;
5858 const MFloat Lf = m_realRadiusFlameTube * tan(acos(slOverU)); // nominal flame length (measured: 1.57)
5859 m_flameStrouhal = m_strouhal / Lf;
5860 // for slot burner with strouhal number based on length one!!! (otherwise neutral markstein lengths not comparable)
5861 if(m_neutralFlameStrouhal > 0) {
5862 m_flameStrouhal = m_neutralFlameStrouhal;
5863 }
5864 } else {
5865 m_flameStrouhal = F0;
5866 }
5867 // nondimensilization of strouhal to stagnation point
5868 m_flameStrouhal *= m_timeRef;
5869 m_neutralFlameStrouhal *= m_timeRef;
5870
5871 // compute theorethical marksetin length
5872 m_marksteinLengthTh = (F1 - m_rhoInfinity * F1 / m_burntUnburntTemperatureRatio) / (F2 * m_strouhal);
5873
5874 m_log << "neutral markstein length (theory) = " << m_marksteinLengthTh << endl << endl;
5875
5876 // initialize flame tube variables as infinity variables (used also for simulations without plenum, than the flame
5877 // tube variables are the same as the infinity variables)
5878 m_temperatureFlameTube = m_TInfinity;
5879 // m_jetTemperature = m_burntUnburntTemperatureRatio;
5880
5881 m_pressureFlameTube = m_PInfinity;
5882 // m_jetPressure = m_PInfinity;
5883
5884 m_velocityFlameTube = m_VInfinity;
5885
5886 m_rhoFlameTube = m_rhoInfinity;
5887 // m_jetDensity = m_rhoInfinity*m_targetDensityFactor;
5888
5889 if(!(m_initialCondition == 1991 || m_initialCondition == 19911)) {
5890 m_rhoUnburnt = m_rhoInfinity;
5891
5892 m_rhoBurnt = m_rhoInfinity / m_burntUnburntTemperatureRatio;
5893 }
5894 // needed for DL instability, updated in boundary conditions 17517, 1752
5895 m_pressureUnburnt = m_PInfinity + m_rhoInfinity * POW2(m_flameSpeed) * (m_burntUnburntTemperatureRatio - F1);
5896
5897 m_log << "CFL number: " << m_cfl << endl;
5898 m_log << "smallest Cell distance according to max refinement Level: " << c_cellLengthAtLevel(maxRefinementLevel())
5899 << endl;
5900
5901 // update needed for computing the correct burnt and unburnt density values for DL instability growth rate computation
5902 if(m_restart && (m_initialCondition == 1991 || m_initialCondition == 19911)) {
5903 // correct burnt unburnt temperature ratio only for restart
5904 m_log << "corrected m_rhoUnburnt = " << m_rhoUnburnt << endl;
5905 m_log << "corrected TbTu = " << m_burntUnburntTemperatureRatio << endl;
5906
5907 m_rhoBurnt = m_rhoUnburnt / m_burntUnburntTemperatureRatio;
5908 m_log << "corrected m_rhoBurnt = " << m_rhoBurnt << endl;
5909
5910
5911 // correct thermal diffusivity
5912 m_DthInfinity = sysEqn().m_muInfinity / (m_rhoUnburnt * m_Pr);
5913 m_log << "corrected DthInfinity = " << m_DthInfinity << endl;
5914
5915 m_marksteinLengthTh = (F1 - m_rhoUnburnt * F1 / m_burntUnburntTemperatureRatio) / (F2 * m_strouhal);
5916
5917 m_log << "corrected neutral markstein length (theory) = " << m_marksteinLengthTh << endl;
5918 m_log << "perturbation amplitude = " << m_perturbationAmplitude << endl;
5919 // don't correct rho infinity because it shouldn't be changed for the sponge layer!!!
5920 }
5921
5922 // update needed for computing the correct burnt and unburnt density values for DL instability neutral Markstein
5923 // length computation
5924 if(m_restart && (m_initialCondition == 1990 || m_initialCondition == 19901)) {
5925 // correct burnt unburnt temperature ratio only for restart
5926 m_log << "corrected m_rhoUnburnt (should be set by your properties file) = " << m_rhoUnburnt << endl;
5927 m_log << "corrected TbTu (should be set by your properties file) = " << m_burntUnburntTemperatureRatio << endl;
5928 m_rhoBurnt = m_rhoUnburnt / m_burntUnburntTemperatureRatio;
5929 m_log << "corrected m_rhoBurnt = " << m_rhoBurnt << endl;
5930
5931 // correct thermal diffusivity
5932 m_DthInfinity = sysEqn().m_muInfinity / (m_rhoUnburnt * m_Pr);
5933 m_log << "corrected DthInfinity = " << m_DthInfinity << endl;
5934
5935 m_marksteinLengthTh = (F1 - m_rhoUnburnt * F1 / m_burntUnburntTemperatureRatio) / (F2 * m_strouhal);
5936
5937 m_log << "corrected neutral markstein length (theory) = " << m_marksteinLengthTh << endl;
5938 m_log << "CFL number: " << m_cfl << endl;
5939 m_log << "smallest Cell distance according to max refinement Level: " << c_cellLengthAtLevel(maxRefinementLevel())
5940 << endl;
5941
5942 // calculate actual markstein length
5943 m_log << "actual used markstein length (should be set by your properties file)" << m_marksteinLength << endl;
5944 }
5945
5946 if(m_confinedFlame) {
5947 m_velocityOutlet = m_rhoInfinity / (m_rhoFlameTube * m_targetDensityFactor) * m_VInfinity * m_inletOutletAreaRatio;
5948 // nondimensionalization of the mean velocity which is caluclated based on the Ma not on VInf
5949 m_meanVelocity *= sqrt(m_TInfinity);
5950
5951 m_meanVelocityOutlet =
5952 m_rhoInfinity / (m_rhoFlameTube * m_targetDensityFactor) * m_meanVelocity * m_inletOutletAreaRatio;
5953 m_log << "mean velocity " << m_meanVelocity << endl;
5954 m_log << "mean velocity outlet" << m_meanVelocityOutlet << endl;
5955
5956 m_deltaPL = m_rRe0 * sysEqn().m_muInfinity * m_meanVelocity * F3 * m_tubeLength / POW2(m_radiusVelFlameTube);
5957 m_log << "friction deltaP tube " << m_deltaPL << endl;
5958 m_deltaPL += m_rRe0 * SUTHERLANDLAW(m_burntUnburntTemperatureRatio) * m_meanVelocityOutlet * F3 * m_outletLength
5959 / POW2(m_radiusOutlet);
5960 m_log << "friction deltaP total " << m_deltaPL << endl;
5961
5962 MFloat pressureLossFlame = m_rhoInfinity * (m_burntUnburntTemperatureRatio - F1);
5963 if(m_pressureLossFlameSpeed != 0) {
5964 pressureLossFlame *= POW2(m_flameSpeed);
5965 } else {
5966 pressureLossFlame *= POW2(m_VInfinity);
5967 }
5968 pressureLossFlame += m_rhoFlameTube * m_targetDensityFactor * POW2(m_meanVelocityOutlet) * m_flameOutletAreaRatio;
5969 pressureLossFlame -= m_rhoFlameTube * POW2(m_meanVelocity);
5970 m_log << "pressureLoss" << pressureLossFlame << endl;
5971 m_deltaPL += pressureLossFlame;
5972 m_log << "deltaP total = friction deltaP + pressureLoss " << m_deltaPL << endl;
5973 m_deltaPL += m_pressureLossCorrection;
5974 m_log << "deltaP total = friction deltaP + pressureLoss + pressureLossCorrection " << m_deltaPL << endl;
5975 m_log << " pressure forced at inlet p = pInf + totaldeltaP " << m_PInfinity + m_deltaPL << endl;
5976 m_meanPressure = m_PInfinity + m_deltaPL;
5977 m_log << "mean pressure is initialized according to the inlet pressure" << endl;
5978 m_log << " pressure forced at outlet p = pInf " << m_PInfinity << endl;
5979 }
5980
5981 // for flame testcase the reference values are set to the flame tube variables if there is a plenum
5982 if(m_plenum && !m_confinedFlame) {
5983 // compute primitive variables of flame tube
5984 m_temperatureFlameTube = sysEqn().temperature_IR(m_MaFlameTube);
5985
5986 m_velocityFlameTube = m_MaFlameTube * sqrt(m_temperatureFlameTube);
5987
5988 m_timeRef = m_velocityFlameTube;
5989 // compute conservative variables
5990 m_rhoFlameTube = sysEqn().density_IR(m_temperatureFlameTube);
5991
5992 // velocity of the outlet needed for target pressure calculation, see spongeLayerLayout 17513, if a plenum and no
5993 // slip walls are used at the outlet sides
5994 if(m_combustion && m_plenumWall) {
5995 m_velocityOutlet =
5996 m_rhoInfinity / (m_rhoFlameTube * m_targetDensityFactor) * m_VInfinity * m_inletOutletAreaRatio;
5997 }
5998 m_pressureFlameTube = sysEqn().pressure_IR(m_temperatureFlameTube);
5999 sysEqn().m_muInfinity = SUTHERLANDLAW(m_temperatureFlameTube);
6000 // heat release model (progress variable) assumption of unity Lewis number Le=1 -> lambda(T)=D(T), see Dissertation
6001 // D.Hartmann page 13
6002 m_DInfinity = sysEqn().m_muInfinity;
6003 sysEqn().m_Re0 = m_Re * sysEqn().m_muInfinity / (m_rhoFlameTube * m_MaFlameTube * sqrt(m_temperatureFlameTube));
6004 m_rRe0 = 1. / sysEqn().m_Re0;
6005 // - - assuming m_TInfinity is the temperature of the unburnt gas
6006 // - - Dth = mue^u / ( rho^u *Pr )
6007 m_DthInfinity = sysEqn().m_muInfinity / (m_rhoFlameTube * m_Pr);
6008
6009 m_rhoEInfinity = sysEqn().internalEnergy(m_pressureFlameTube, m_rhoFlameTube, POW2(m_velocityFlameTube));
6010
6011 // pressure loss inlet -> tube
6012 pressureLoss = m_rhoInfinity * POW2(m_VInfinity) * (m_inletTubeAreaRatio - F1);
6013
6014 m_log << "***************************************************************************" << endl;
6015 m_log << "Plenum - Computation:" << endl;
6016 m_log << "Initial Condition summary referred to the averaged values of the flame tube" << endl;
6017 m_log << "***************************************************************************" << endl;
6018 m_log << "Re = " << m_Re << endl;
6019 m_log << "Re0 (used in code) = " << sysEqn().m_Re0 << endl;
6020 m_log << "Ma_fl (used in code) = " << m_MaFlameTube << endl;
6021 m_log << "T_fl = " << m_temperatureFlameTube << endl;
6022 m_log << "V_fl = " << m_velocityFlameTube << endl;
6023 m_log << "P_fl = " << m_pressureFlameTube << endl;
6024 m_log << "rho_fl (used in code) = " << m_rhoFlameTube << endl;
6025 m_log << "rhoEInfinity (used in code) = " << m_rhoEInfinity << endl;
6026 m_log << "mu_Infinity (used in code) = " << sysEqn().m_muInfinity << endl;
6027 m_log << "D_Infinity (used in code) = " << m_DInfinity << endl;
6028 m_log << "Dth_Infinity (used in code) = " << m_DthInfinity << endl << endl;
6029 m_log << "Tb/Tu (used in code) = " << m_burntUnburntTemperatureRatio << endl << endl;
6030
6031 if(m_plenumWall) {
6032 m_log << "******************************************************************" << endl;
6033 m_log << "Plenum + Wall - Computation:" << endl;
6034 m_log << "Additional information for the use of no slip walls at the outlet:" << endl;
6035 m_log << "******************************************************************" << endl;
6036 m_log << "inletOutletAreaRatio = " << m_inletOutletAreaRatio << endl;
6037 m_log << "inletTubeAreaRatio = " << m_inletTubeAreaRatio << endl;
6038 m_log << "flameOutletAreaRatio = " << m_flameOutletAreaRatio << endl;
6039 m_log << "averaged velocity outlet = " << m_velocityOutlet << endl;
6040 m_log << "Calculating additional pressure loss ... " << pressureLoss << endl;
6041
6042 pressureLoss += m_rhoFlameTube * m_targetDensityFactor
6043 * (POW2(m_velocityOutlet) - POW2(m_flameSpeed) * m_flameOutletAreaRatio);
6044 }
6045 // pressure loss = pressure loss (inlet -> tube) + pressure loss (tube -> outlet )
6046 m_log << "pressure loss = " << pressureLoss << endl;
6047 }
6048
6049 if(m_confinedFlame) {
6050 m_log << "******************************************************************" << endl;
6051 m_log << "Confined flame - Computation:" << endl;
6052 m_log << "Additional information for the use of no slip walls at the outlet:" << endl;
6053 m_log << "******************************************************************" << endl;
6054 m_log << "inletOutletAreaRatio = " << m_inletOutletAreaRatio << endl;
6055 m_log << "flameOutletAreaRatio = " << m_flameOutletAreaRatio << endl;
6056 m_log << "averaged velocity outlet = " << m_velocityOutlet << endl;
6057 m_log << "Calculating additional pressure loss ... " << pressureLoss << endl;
6058
6059 // pressureLoss +=
6060 // m_rhoFlameTube * m_targetDensityFactor * (POW2(m_velocityOutlet) - POW2(m_flameSpeed) *
6061 // m_flameOutletAreaRatio);
6062 }
6063
6064
6065 IF_CONSTEXPR(nDim == 3) {
6066 // turb flame speed contribution Pitsch et al. 2005
6067 MFloat FDL = 1 / m_DthInfinity;
6068 MFloat DL = m_DthInfinity;
6069 MFloat b3T = 1.0;
6070 MFloat b1T = 2.0;
6071 // MFloat m_ScT = 0.4; // Pitsch et al. 2005 and 2000 (0.5) -> a constant value can be used
6072 // MFloat m_NuT = 0.0017169;// max value determined from cold jet with grid refinement r11 at y=-0.5
6073
6074 MFloat Dt = m_NuT / m_ScT;
6075 // lam. flame speed
6076 MFloat flameSpeed = m_flameSpeed;
6077
6078 MFloat delta = c_cellLengthAtLevel(maxLevel()); // LES filter width equals grid siz
6079 MFloat uAmpl = pow(m_integralAmplitude, 3); // filtered velocity
6080 uAmpl *= delta;
6081 uAmpl /= m_integralLengthScale;
6082 uAmpl = pow(uAmpl, F1B3); // filtered velocity Pitsch et al. 2005
6083 m_Da = flameSpeed * delta / (uAmpl * m_laminarFlameThickness); // Eq. 2 in Pitsch et al. 2002
6084
6085 MFloat bFactor = pow(b3T, 2) / (F2 * b1T * m_ScT);
6086
6087 bFactor *= m_NuT * FDL * m_flameSpeed / uAmpl;
6088
6089 MFloat b3Factor = pow(b3T, 2) * m_NuT;
6090 b3Factor /= (m_ScT * DL);
6091
6092 // -bFactor + sqrt(bFactor + b3Factor)
6093 MFloat turbFlameSpeed = -bFactor;
6094 turbFlameSpeed += sqrt(pow(bFactor, 2) + b3Factor);
6095 turbFlameSpeed *= m_flameSpeed;
6096
6097 m_turbFlameSpeed = turbFlameSpeed;
6098 m_log << "Da = " << m_Da << endl;
6099 MFloat Ka = sqrt(pow((uAmpl / m_flameSpeed), 3) * m_laminarFlameThickness / delta);
6100 m_log << "Ka = " << Ka << endl;
6101
6102 m_log << "turbulent flame speed = " << m_turbFlameSpeed << endl;
6103 m_log << "turbulent flame speed/lam flame speed = " << m_turbFlameSpeed / m_flameSpeed << endl;
6104
6105 MFloat FDa = Dt;
6106 if(m_Da > 1) {
6107 FDa *= F1 / pow(m_Da, 2);
6108 m_log << "Pitsch model for Da > 1 " << endl;
6109 } else {
6110 m_log << "Pitsch model for Da < 1 " << endl;
6111 }
6112 m_log << "turbulent diffusivity D_tk = " << FDa << endl;
6113 m_log << "ratio of integral velocity to flame speed " << m_integralAmplitude / m_flameSpeed << endl;
6114 }
6115}
6116//----------------------------------------------------------------------------
6117
6118
6119template <MInt nDim_, class SysEqn>
6121 TRACE();
6122
6123 const MInt noFVars = FV->noVariables;
6124 //---
6125
6126#ifdef _OPENMP
6127#pragma omp parallel for collapse(2)
6128#endif
6129 for(MInt id = 0; id < a_noCells(); id++) {
6130 for(MInt varId = 0; varId < noFVars; varId++) {
6131 a_rightHandSide(id, varId) = F0;
6132 }
6133 }
6134}
6135
6136
6137//----------------------------------------------------------------------------
6138
6139
6140template <MInt nDim_, class SysEqn>
6142 TRACE();
6143
6144 copyVarsToSmallCells();
6145
6146 if(m_gridInterfaceFilter) {
6147 filterConservativeVariablesAtFineToCoarseGridInterfaces();
6148 }
6149
6150 computePrimitiveVariables();
6151}
6152
6153
6154//----------------------------------------------------------------------------
6155
6160template <MInt nDim_, class SysEqn>
6162 MFloat radius = NAN;
6163 MFloat v_t = NAN;
6164 MInt cellId = 0;
6165
6166 for(MInt ac = 0; ac < m_noActiveCells; ac++) {
6167 cellId = m_activeCellIds[ac];
6168 radius = 0.0;
6169
6170 for(MInt i = 0; i < 2; i++) {
6171 radius += pow(a_coordinate(cellId, i + 1) - m_rotAxisCoord[i], 2.0);
6172 }
6173 radius = sqrt(radius);
6174
6175
6176 MFloat phi_mid = 74.9355804414;
6177 MFloat v_t_mid = m_UInfinity * sin(phi_mid / 180.0 * PI);
6178 v_t = v_t_mid / ((150.0 + 67.5) / 2.0) * radius;
6179
6180 // momentum equation
6181 a_rightHandSide(m_activeCellIds[ac], CV->RHO_VV[1]) -=
6182 a_cellVolume(m_activeCellIds[ac])
6183 * (F2 * v_t * a_pvariable(cellId, PV->RHO) * a_pvariable(cellId, PV->W) / radius
6184 + a_pvariable(cellId, PV->RHO) * pow(v_t / radius, 2.0) * (a_coordinate(cellId, 1) - m_rotAxisCoord[0]));
6185
6186 a_rightHandSide(m_activeCellIds[ac], CV->RHO_VV[2]) -=
6187 a_cellVolume(m_activeCellIds[ac])
6188 * (-F2 * v_t * a_pvariable(cellId, PV->RHO) * a_pvariable(cellId, PV->V) / radius
6189 + a_pvariable(cellId, PV->RHO) * pow(v_t / radius, 2.0) * (a_coordinate(cellId, 2) - m_rotAxisCoord[1]));
6190
6191 // energy equation
6192 IF_CONSTEXPR(hasE<SysEqn>)
6193 a_rightHandSide(m_activeCellIds[ac], CV->RHO_E) -=
6194 a_cellVolume(m_activeCellIds[ac]) * a_pvariable(cellId, PV->RHO) * pow(v_t / radius, 2.0)
6195 * ((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) * a_pvariable(cellId, PV->V)
6196 + (a_coordinate(cellId, 2) - m_rotAxisCoord[1]) * a_pvariable(cellId, PV->W));
6197 }
6198}
6199
6204template <MInt nDim_, class SysEqn>
6206 TRACE();
6207 // Volume forces are added in rhsEEGas() if m_isEEGas
6208 if(m_isEEGas) return;
6209
6210#ifdef _OPENMP
6211#pragma omp parallel for collapse(2)
6212#endif
6213 for(MInt ac = 0; ac < m_noActiveCells; ac++) {
6214 for(MInt i = 0; i < nDim; i++) {
6215 a_rightHandSide(m_activeCellIds[ac], CV->RHO_VV[i]) -=
6216 a_pvariable(m_activeCellIds[ac], PV->RHO) * m_volumeAcceleration[i] * a_cellVolume(m_activeCellIds[ac]);
6217 IF_CONSTEXPR(hasE<SysEqn>)
6218 a_rightHandSide(m_activeCellIds[ac], CV->RHO_E) -= a_pvariable(m_activeCellIds[ac], PV->VV[i])
6219 * a_pvariable(m_activeCellIds[ac], PV->RHO)
6220 * m_volumeAcceleration[i] * a_cellVolume(m_activeCellIds[ac]);
6221 }
6222 }
6223}
6224
6225
6226template <MInt nDim_, class SysEqn>
6228 TRACE();
6229 return mMax(1, (MInt)(F1 / (timeStep() * m_timeRef * m_sampleRate)));
6230}
6231
6232
6237template <MInt nDim_, class SysEqn>
6239 TRACE();
6240
6241 if(noNeighborDomains() == 0) return;
6242
6243 ScratchSpace<MInt> haloCellsCnt(noNeighborDomains(), AT_, "noHaloCells");
6244 ScratchSpace<MInt> windowCellsCnt(noNeighborDomains(), AT_, "noWindowCells");
6245 for(MInt d = 0; d < noNeighborDomains(); d++) {
6246 haloCellsCnt[d] = noHaloCells(d);
6247 windowCellsCnt[d] = noWindowCells(d);
6248 }
6249
6250 mDeallocate(m_maxLevelHaloCells);
6251 mAlloc(m_maxLevelHaloCells, noNeighborDomains(), &haloCellsCnt[0], "m_maxLevelHaloCells", AT_);
6252 mDeallocate(m_maxLevelWindowCells);
6253 mAlloc(m_maxLevelWindowCells, noNeighborDomains(), &windowCellsCnt[0], "m_maxLevelWindowCells", AT_);
6254
6255 ScratchSpace<MInt> isOnMaxLevel(a_noCells(), AT_, "isOnMaxLevel");
6256 isOnMaxLevel.fill(0);
6257
6258 for(MInt i = 0; i < noNeighborDomains(); i++) {
6259 m_noMaxLevelHaloCells[i] = 0;
6260 for(MInt j = 0; j < noHaloCells(i); j++) {
6261 if(!a_hasProperty(haloCellId(i, j), SolverCell::IsOnCurrentMGLevel)) {
6262 continue;
6263 }
6264 m_maxLevelHaloCells[i][m_noMaxLevelHaloCells[i]] = haloCellId(i, j);
6265 m_noMaxLevelHaloCells[i]++;
6266 isOnMaxLevel(haloCellId(i, j)) = 1;
6267 }
6268 }
6269
6270 MUint recvSize = maia::mpi::getBufferSize(grid().windowCells());
6271 ScratchSpace<MInt> recvBuffer(mMax(1u, recvSize), AT_, "recvBuffer");
6272 maia::mpi::reverseExchangeData(grid().neighborDomains(), grid().haloCells(), grid().windowCells(), mpiComm(),
6273 &isOnMaxLevel[0], &recvBuffer[0]);
6274
6275 recvSize = 0;
6276 for(MInt i = 0; i < noNeighborDomains(); i++) {
6277 m_noMaxLevelWindowCells[i] = 0;
6278 for(MInt j = 0; j < noWindowCells(i); j++) {
6279 if(recvBuffer[recvSize]) {
6280 // ASSERT(a_hasProperty(windowCellId(i, j), SolverCell::IsOnCurrentMGLevel), "");
6281 m_maxLevelWindowCells[i][m_noMaxLevelWindowCells[i]] = windowCellId(i, j);
6282 m_noMaxLevelWindowCells[i]++;
6283 }
6284 recvSize++;
6285 }
6286 }
6287
6288 prepareMpiExchange();
6289
6290 if(grid().noAzimuthalNeighborDomains() > 0) {
6291 initAzimuthalMaxLevelExchange();
6292 }
6293
6294 initNearBoundaryExchange();
6295}
6296
6297
6298// Prepare persistent MPI requests for start/finish MpiExchange and exchange
6299// of primitive variable exchange during lhsBndry formulation
6300template <MInt nDim_, class SysEqn>
6302 TRACE();
6303
6304
6305 if(m_nonBlockingComm) {
6306 m_maxLvlMpiSendNeighbor.clear();
6307 m_maxLvlMpiRecvNeighbor.clear();
6308 MInt noSendNghbrs = 0;
6309 MInt noRecvNghbrs = 0;
6310
6311
6312 for(MInt i = 0; i < noNeighborDomains(); i++) {
6313 if(m_mpi_receiveRequest[i] != MPI_REQUEST_NULL) {
6314 MPI_Request_free(&m_mpi_receiveRequest[i], AT_);
6315 }
6316 if(m_mpi_sendRequest[i] != MPI_REQUEST_NULL) {
6317 MPI_Request_free(&m_mpi_sendRequest[i], AT_);
6318 }
6319 }
6320
6321 for(MInt i = 0; i < noNeighborDomains(); i++) {
6322 MInt bufferCounter = m_noMaxLevelHaloCells[i] * m_dataBlockSize;
6323 if(bufferCounter > 0) {
6324 MPI_Recv_init(m_receiveBuffersNoBlocking[i], bufferCounter, MPI_DOUBLE, neighborDomain(i), MAIA_MPI_FV_TAG,
6325 mpiComm(), &m_mpi_receiveRequest[noRecvNghbrs], AT_, "m_receiveBuffersNoBlocking[i]");
6326 m_maxLvlMpiRecvNeighbor.push_back(i);
6327 noRecvNghbrs++;
6328 }
6329 bufferCounter = m_noMaxLevelWindowCells[i] * m_dataBlockSize;
6330 if(bufferCounter > 0) {
6331 MPI_Send_init(m_sendBuffersNoBlocking[i], bufferCounter, MPI_DOUBLE, neighborDomain(i), MAIA_MPI_FV_TAG,
6332 mpiComm(), &m_mpi_sendRequest[noSendNghbrs], AT_, "m_sendBuffersNoBlocking[i]");
6333 m_maxLvlMpiSendNeighbor.push_back(i);
6334 noSendNghbrs++;
6335 }
6336 }
6337 // Set status of MPI requests
6338 m_mpiSendRequestsOpen = false;
6339 m_mpiRecvRequestsOpen = false;
6340 }
6341}
6342
6343template <MInt nDim_, class SysEqn>
6345 TRACE();
6346
6347 RECORD_TIMER_START(m_tcomm);
6348 RECORD_TIMER_START(m_texchange);
6349
6350 gather<true>();
6351 send(true);
6352 receive(true);
6353 scatter<true>();
6354
6355 if(grid().azimuthalPeriodicity()) {
6356 exchangeFloatDataAzimuthal(&a_pvariable(0, 0), PV->noVariables, m_rotIndVarsPV);
6357 }
6358
6359
6360 RECORD_TIMER_STOP(m_texchange);
6361 RECORD_TIMER_STOP(m_tcomm);
6362}
6363
6364//----------------------------------------------------------------------------
6365
6366
6367template <MInt nDim_, class SysEqn>
6369 TRACE();
6370
6371 RECORD_TIMER_START(m_tcomm);
6372 RECORD_TIMER_START(m_texchange);
6373
6374 // periodic exchange is included in normal window and halo cell exchange, quasi periodic exchange is not yet applied
6375 if(!m_nonBlockingComm) {
6376 gather<false>();
6377 send();
6378 receive();
6379 scatter<false>();
6380
6381 } else {
6382 if(grid().azimuthalPeriodicity()) {
6383 mTerm(1, AT_, "non blocking comm is not implemented for azimuthal periodicity");
6384 }
6385 startMpiExchange();
6386 finishMpiExchange();
6387 }
6388
6389 if(grid().azimuthalPeriodicity()) {
6390 exchangeFloatDataAzimuthal<false>(&a_pvariable(0, 0), PV->noVariables, m_rotIndVarsPV);
6391 }
6392 RECORD_TIMER_STOP(m_texchange);
6393 RECORD_TIMER_STOP(m_tcomm);
6394
6395 if(m_wmLES && m_RKStep == m_noRKSteps - 1) {
6396 RECORD_TIMER_START(m_timers[Timers::WMExchange]);
6397 exchangeWMVars();
6398 RECORD_TIMER_STOP(m_timers[Timers::WMExchange]);
6399 }
6400
6401 // DISPLAY_TIMER_OFFSET(m_tcomm, m_restartInterval);
6402}
6403
6410template <MInt nDim_, class SysEqn>
6412 TRACE();
6413
6414 // SEND: Wait for old send requests to finish (blocking)
6415 RECORD_TIMER_START(m_tgatherAndSend);
6416 RECORD_TIMER_START(m_tgatherAndSendWait);
6417 if(m_mpiSendRequestsOpen) {
6418 MPI_Waitall((MInt)m_maxLvlMpiSendNeighbor.size(), m_mpi_sendRequest, MPI_STATUSES_IGNORE, AT_);
6419 }
6420 RECORD_TIMER_STOP(m_tgatherAndSendWait);
6421
6422 // Start receive requests if not already open
6423 if(!m_mpiRecvRequestsOpen) {
6424 MPI_Startall((MInt)m_maxLvlMpiRecvNeighbor.size(), m_mpi_receiveRequest, AT_);
6425 m_mpiRecvRequestsOpen = true;
6426 }
6427
6428 // SEND: Fill send buffer and start sending (non-blocking)
6429 for(MInt i = 0; i < (MInt)m_maxLvlMpiSendNeighbor.size(); i++) {
6430 const MInt completedId = m_maxLvlMpiSendNeighbor[i];
6431 MInt bufferCounter = 0;
6432 for(MInt j = 0; j < m_noMaxLevelWindowCells[completedId]; j++) {
6433 copy_n(&a_pvariable(m_maxLevelWindowCells[completedId][j], 0),
6434 PV->noVariables,
6435 &m_sendBuffersNoBlocking[completedId][bufferCounter]);
6436 bufferCounter += m_dataBlockSize;
6437 }
6438 }
6439
6440 MPI_Startall((MInt)m_maxLvlMpiSendNeighbor.size(), m_mpi_sendRequest, AT_);
6441
6442 m_mpiSendRequestsOpen = true;
6443
6444 RECORD_TIMER_STOP(m_tgatherAndSend);
6445}
6446
6447
6454template <MInt nDim_, class SysEqn>
6456 TRACE();
6457
6458 if(!m_mpiRecvRequestsOpen) {
6459 mTerm(1, "MPI receive requests are not open.");
6460 }
6461
6462 MBool useWaitsome = false; // true;
6463 RECORD_TIMER_START(m_tscatter);
6464
6465 if(useWaitsome) {
6466 const MBool loadWasRunning = this->isLoadTimerRunning();
6467 if(loadWasRunning) {
6468 this->stopLoadTimer(AT_);
6469 this->startIdleTimer(AT_);
6470 this->disableDlbTimers();
6471 }
6472
6473 // RECV: Wait for old receive requests to finish (blocking) and unpack buffers
6474 MIntScratchSpace completedIds(noNeighborDomains(), AT_, "completedIds");
6475 while(true) {
6476 // Wait for old receive requests (blocking)
6477 MInt noCompleted = 0;
6478 RECORD_TIMER_START(m_tscatterWaitSome);
6479 MPI_Waitsome((MInt)m_maxLvlMpiRecvNeighbor.size(), m_mpi_receiveRequest, &noCompleted, &completedIds[0],
6480 MPI_STATUSES_IGNORE, AT_);
6481 RECORD_TIMER_STOP(m_tscatterWaitSome);
6482
6483 // Exit loop if no more unfinished requests are found
6484 if(noCompleted == MPI_UNDEFINED) {
6485 break;
6486 }
6487
6488 // Unpack buffers
6489 for(MInt i = 0; i < noCompleted; i++) {
6490 const MInt completedId = completedIds[i];
6491 MInt bufferCounter = 0;
6492 for(MInt j = 0; j < m_noMaxLevelHaloCells[completedId]; j++) {
6493 copy_n(&m_receiveBuffersNoBlocking[completedId][bufferCounter],
6494 m_dataBlockSize,
6495 &a_pvariable(m_maxLevelHaloCells[completedId][j], 0));
6496 bufferCounter += m_dataBlockSize;
6497 }
6498 }
6499 }
6500
6501 if(loadWasRunning) {
6502 this->reEnableDlbTimers();
6503 this->stopIdleTimer(AT_);
6504 this->startLoadTimer(AT_);
6505 }
6506 } else {
6507 RECORD_TIMER_START(m_tscatterWaitSome);
6508 MPI_Waitall((MInt)m_maxLvlMpiRecvNeighbor.size(), m_mpi_receiveRequest, MPI_STATUSES_IGNORE, AT_);
6509 RECORD_TIMER_STOP(m_tscatterWaitSome);
6510
6511 // Unpack all buffers
6512 // for(MInt i = 0; i < noNeighborDomains(); i++) {
6513 for(MInt n = 0; n < (MInt)m_maxLvlMpiRecvNeighbor.size(); n++) {
6514 const MInt i = m_maxLvlMpiRecvNeighbor[n];
6515 MInt bufferCounter = 0;
6516 for(MInt j = 0; j < m_noMaxLevelHaloCells[i]; j++) {
6517 std::copy_n(&m_receiveBuffersNoBlocking[i][bufferCounter], m_dataBlockSize,
6518 &a_pvariable(m_maxLevelHaloCells[i][j], 0));
6519 bufferCounter += m_dataBlockSize;
6520 }
6521 }
6522 }
6523
6524 RECORD_TIMER_STOP(m_tscatter);
6525
6526 // RECV: Start receiving (non-blocking)
6527 // open new receive
6528 RECORD_TIMER_START(m_treceive);
6529 MPI_Startall((MInt)m_maxLvlMpiRecvNeighbor.size(), m_mpi_receiveRequest, AT_);
6530 m_mpiRecvRequestsOpen = true;
6531 RECORD_TIMER_STOP(m_treceive);
6532}
6533
6534
6539template <MInt nDim_, class SysEqn>
6541 TRACE();
6542
6543 // Make sure all send requests are completed
6544 if(m_mpiSendRequestsOpen) {
6545 MPI_Waitall((MInt)m_maxLvlMpiSendNeighbor.size(), m_mpi_sendRequest, MPI_STATUSES_IGNORE, AT_);
6546 m_mpiSendRequestsOpen = false;
6547 }
6548
6549 // Cancel opened receive requests
6550 if(m_mpiRecvRequestsOpen) {
6551 std::vector<MBool> waitForCancel(noNeighborDomains(), false);
6552 for(MInt i = 0; i < noNeighborDomains(); i++) {
6553 if(m_mpi_receiveRequest[i] != MPI_REQUEST_NULL) {
6554 MPI_Cancel(&m_mpi_receiveRequest[i], AT_);
6555 waitForCancel[i] = true;
6556 }
6557 }
6558 // Wait for all requests until they are canceled
6559 for(MInt i = 0; i < noNeighborDomains(); i++) {
6560 if(waitForCancel[i]) {
6561 MPI_Wait(&m_mpi_receiveRequest[i], MPI_STATUS_IGNORE, AT_);
6562 }
6563 }
6564 m_mpiRecvRequestsOpen = false;
6565 }
6566}
6567
6568
6570template <MInt nDim_, class SysEqn>
6572 // Cancel and free MPI requests
6573 if(m_nonBlockingComm && noNeighborDomains() > 0) {
6574 // Wait for open send requests to finish
6575 if(m_mpiSendRequestsOpen) {
6576 MPI_Waitall((MInt)m_maxLvlMpiSendNeighbor.size(), m_mpi_sendRequest, MPI_STATUSES_IGNORE, AT_);
6577 }
6578
6579 for(MInt i = 0; i < noNeighborDomains(); i++) {
6580 if(m_mpi_receiveRequest != nullptr) {
6581 if(m_mpi_receiveRequest[i] != MPI_REQUEST_NULL) {
6582 // Cancel opened receive request that do not have a matching send initiated yet
6583 if(m_mpiRecvRequestsOpen) {
6584 MPI_Cancel(&m_mpi_receiveRequest[i], AT_);
6585 }
6586 MPI_Request_free(&m_mpi_receiveRequest[i], AT_);
6587 }
6588 }
6589 if(m_mpi_sendRequest != nullptr) {
6590 if(m_mpi_sendRequest[i] != MPI_REQUEST_NULL) {
6591 // Free send request (cannot be canceled)
6592 MPI_Request_free(&m_mpi_sendRequest[i], AT_);
6593 }
6594 }
6595 }
6596
6597 m_mpiSendRequestsOpen = false;
6598 m_mpiRecvRequestsOpen = false;
6599 }
6600}
6601
6602
6603//----------------------------------------------------------------------------
6604
6605
6611template <MInt nDim_, class SysEqn>
6613 if(m_periodicCells > 0 && m_periodicCells != 3) {
6614 // init
6615 MFloat v_comp = 0;
6616 MFloat w_comp = 0;
6617 MFloat rot_times = 0;
6618 MInt n_Id = -1;
6619 MInt off_ = 0;
6620
6621 if(m_periodicCells == 1) {
6622 for(MInt d = 0; d < noDomains(); d++) {
6623 // No OMP possible here because off_ needs to be sequentially increased...
6624 for(MInt c = 0; c < m_noPerCellsToSend[d]; c++) {
6625 const auto sortedId = static_cast<MInt>(m_periodicDataToSend[d][5 + c * m_noPeriodicData]);
6626
6627 v_comp = F0;
6628 w_comp = F0;
6629 m_periodicDataToSend[d][0 + c * m_noPeriodicData] = F0;
6630 m_periodicDataToSend[d][1 + c * m_noPeriodicData] = F0;
6631 m_periodicDataToSend[d][2 + c * m_noPeriodicData] = F0;
6632 m_periodicDataToSend[d][3 + c * m_noPeriodicData] = F0;
6633 m_periodicDataToSend[d][4 + c * m_noPeriodicData] = F0;
6634
6635 // LS interpolation
6636 MInt noNeighboursRec =
6637 (m_reconstructionDataPeriodic[off_ + c + 1] - m_reconstructionDataPeriodic[off_ + c]) / 2;
6638 for(MInt n = (m_reconstructionDataPeriodic[off_ + c] + noNeighboursRec);
6639 n < m_reconstructionDataPeriodic[off_ + c + 1];
6640 n++) {
6641 n_Id = static_cast<MInt>(m_reconstructionConstantsPeriodic[n - noNeighboursRec]);
6642
6643 v_comp += m_reconstructionConstantsPeriodic[n] * a_pvariable(n_Id, PV->VV[1]);
6644 w_comp += m_reconstructionConstantsPeriodic[n] * a_pvariable(n_Id, PV->VV[2]);
6645
6646 m_periodicDataToSend[d][0 + c * m_noPeriodicData] +=
6647 m_reconstructionConstantsPeriodic[n] * a_pvariable(n_Id, PV->RHO);
6648 m_periodicDataToSend[d][1 + c * m_noPeriodicData] +=
6649 m_reconstructionConstantsPeriodic[n] * a_pvariable(n_Id, PV->VV[0]);
6650 m_periodicDataToSend[d][4 + c * m_noPeriodicData] +=
6651 m_reconstructionConstantsPeriodic[n] * a_pvariable(n_Id, PV->P);
6652 }
6653
6654
6655 if(m_periodicCellDataDom[d][4 + sortedId * m_noPeriodicCellData] < 0.0) // left Cells ..rotate anticlockwise
6656 {
6657 rot_times = -m_periodicCellDataDom[d][4 + sortedId * m_noPeriodicCellData];
6658 m_periodicDataToSend[d][2 + c * m_noPeriodicData] =
6659 cos(72.0 / 180.0 * PI * rot_times) * v_comp + sin(72.0 / 180.0 * PI * rot_times) * w_comp;
6660 m_periodicDataToSend[d][3 + c * m_noPeriodicData] =
6661 -sin(72.0 / 180.0 * PI * rot_times) * v_comp + cos(72.0 / 180.0 * PI * rot_times) * w_comp;
6662 } else { // right cells ..rotate clockwise
6663 rot_times = m_periodicCellDataDom[d][4 + sortedId * m_noPeriodicCellData];
6664 m_periodicDataToSend[d][2 + c * m_noPeriodicData] =
6665 cos(72.0 / 180.0 * PI * rot_times) * v_comp - sin(72.0 / 180.0 * PI * rot_times) * w_comp;
6666 m_periodicDataToSend[d][3 + c * m_noPeriodicData] =
6667 sin(72.0 / 180.0 * PI * rot_times) * v_comp + cos(72.0 / 180.0 * PI * rot_times) * w_comp;
6668 }
6669 }
6670 off_ += m_noPerCellsToSend[d];
6671 }
6672 } else if(m_periodicCells == 2) {
6673 for(MInt d = 0; d < noDomains(); d++) {
6674 for(MInt c = 0; c < m_noPerCellsToSend[d]; c++) {
6675 const auto cell_Id = static_cast<MInt>(m_periodicDataToSend[d][6 + c * m_noPeriodicData]);
6676
6677 m_periodicDataToSend[d][0 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->RHO);
6678 m_periodicDataToSend[d][1 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->U);
6679 m_periodicDataToSend[d][2 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->V);
6680 m_periodicDataToSend[d][3 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->W);
6681 m_periodicDataToSend[d][4 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->P);
6682 }
6683 }
6684 }
6685
6686 // set Data for current domain
6687 for(MInt c = 0; c < m_noPerCellsToSend[domainId()]; c++) {
6688 for(MInt v = 0; v < 7; v++) {
6689 m_periodicDataToReceive[domainId()][v + c * m_noPeriodicData] =
6690 m_periodicDataToSend[domainId()][v + c * m_noPeriodicData];
6691 }
6692 }
6693
6694
6695 // exchange interpolated PV Variables
6696 ScratchSpace<MPI_Request> send_Req(noDomains(), AT_, "sendReq");
6697 ScratchSpace<MPI_Request> recv_Req(noDomains(), AT_, "recvReq");
6698 send_Req.fill(MPI_REQUEST_NULL);
6699 recv_Req.fill(MPI_REQUEST_NULL);
6700
6701
6702 for(MInt snd = 0; snd < domainId(); snd++) {
6703 if(m_noPerCellsToReceive[snd] > 0) {
6704 MInt bufSize = m_noPerCellsToReceive[snd] * m_noPeriodicData;
6705 MPI_Irecv(m_periodicDataToReceive[snd], bufSize, MPI_DOUBLE, snd, 0, mpiComm(), &recv_Req[snd], AT_,
6706 "m_periodicDataToReceive[snd]");
6707 }
6708 }
6709
6710 for(MInt rcv = 0; rcv < noDomains(); rcv++) {
6711 if(m_noPerCellsToSend[rcv] > 0 && rcv != domainId()) {
6712 MInt bufSize = m_noPerCellsToSend[rcv] * m_noPeriodicData;
6713 MPI_Isend(m_periodicDataToSend[rcv], bufSize, MPI_DOUBLE, rcv, 0, mpiComm(), &send_Req[rcv], AT_,
6714 "m_periodicDataToSend[rcv]");
6715 }
6716 }
6717
6718 if(domainId() < noDomains() - 1) {
6719 for(MInt snd = domainId() + 1; snd < noDomains(); snd++) {
6720 if(m_noPerCellsToReceive[snd] > 0) {
6721 MInt bufSize = m_noPerCellsToReceive[snd] * m_noPeriodicData;
6722 MPI_Irecv(m_periodicDataToReceive[snd], bufSize, MPI_DOUBLE, snd, 0, mpiComm(), &recv_Req[snd], AT_,
6723 "m_periodicDataToReceive[snd]");
6724 }
6725 }
6726 }
6727
6728
6729 MPI_Waitall(noDomains(), &recv_Req[0], MPI_STATUSES_IGNORE, AT_);
6730 MPI_Waitall(noDomains(), &send_Req[0], MPI_STATUSES_IGNORE, AT_);
6731
6732
6733 for(MInt d = 0; d < noDomains(); d++) {
6734 for(MInt c = 0; c < m_noPerCellsToReceive[d]; c++) {
6735 const auto sortedId = static_cast<MInt>(m_periodicDataToReceive[d][5 + c * m_noPeriodicData]);
6736 const MInt cell_Id = m_sortedPeriodicCells->a[sortedId];
6737
6738 a_pvariable(cell_Id, PV->RHO) = m_periodicDataToReceive[d][0 + c * m_noPeriodicData];
6739 a_pvariable(cell_Id, PV->U) = m_periodicDataToReceive[d][1 + c * m_noPeriodicData];
6740 a_pvariable(cell_Id, PV->V) = m_periodicDataToReceive[d][2 + c * m_noPeriodicData];
6741 a_pvariable(cell_Id, PV->W) = m_periodicDataToReceive[d][3 + c * m_noPeriodicData];
6742 a_pvariable(cell_Id, PV->P) = m_periodicDataToReceive[d][4 + c * m_noPeriodicData];
6743 }
6744 }
6745 computeConservativeVariables();
6746 }
6747
6748 if(m_periodicCells == 3) {
6749 exchangePipe(); // volume forcing for periodic pipe
6750 }
6751}
6752
6753
6759template <MInt nDim_, class SysEqn>
6761 for(MInt d = 0; d < noDomains(); d++) {
6762 for(MInt c = 0; c < m_noPerCellsToSend[d]; c++) {
6763 const auto cell_Id = static_cast<MInt>(m_periodicDataToSend[d][6 + c * m_noPeriodicData]);
6764
6765 m_periodicDataToSend[d][0 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->RHO);
6766 m_periodicDataToSend[d][1 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->U);
6767 m_periodicDataToSend[d][2 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->V);
6768 m_periodicDataToSend[d][3 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->W);
6769 m_periodicDataToSend[d][4 + c * m_noPeriodicData] = a_pvariable(cell_Id, PV->P);
6770 }
6771 }
6772
6773 // set Data for current domain
6774 for(MInt c = 0; c < m_noPerCellsToSend[domainId()]; c++) {
6775 for(MInt v = 0; v < 7; v++) {
6776 m_periodicDataToReceive[domainId()][v + c * 7] = m_periodicDataToSend[domainId()][v + c * m_noPeriodicData];
6777 }
6778 }
6779
6780 // exchange interpolated PV Variables
6781 ScratchSpace<MPI_Request> send_Req(noDomains(), AT_, "sendReq");
6782 ScratchSpace<MPI_Request> recv_Req(noDomains(), AT_, "recvReq");
6783 send_Req.fill(MPI_REQUEST_NULL);
6784 recv_Req.fill(MPI_REQUEST_NULL);
6785
6786
6787 // MPI_Status status;
6788
6789 for(MInt snd = 0; snd < domainId(); snd++) {
6790 if(m_noPerCellsToReceive[snd] > 0) {
6791 MInt bufSize = m_noPerCellsToReceive[snd] * m_noPeriodicData;
6792 MPI_Irecv(m_periodicDataToReceive[snd], bufSize, MPI_DOUBLE, snd, 0, mpiComm(), &recv_Req[snd], AT_,
6793 "m_periodicDataToReceive[snd]");
6794 }
6795 }
6796
6797 for(MInt rcv = 0; rcv < noDomains(); rcv++) {
6798 if(m_noPerCellsToSend[rcv] > 0 && rcv != domainId()) {
6799 MInt bufSize = m_noPerCellsToSend[rcv] * m_noPeriodicData;
6800 MPI_Isend(m_periodicDataToSend[rcv], bufSize, MPI_DOUBLE, rcv, 0, mpiComm(), &send_Req[rcv], AT_,
6801 "m_periodicDataToSend[rcv]");
6802 }
6803 }
6804
6805 if(domainId() < noDomains() - 1) {
6806 for(MInt snd = domainId() + 1; snd < noDomains(); snd++) {
6807 if(m_noPerCellsToReceive[snd] > 0) {
6808 MInt bufSize = m_noPerCellsToReceive[snd] * m_noPeriodicData;
6809 MPI_Irecv(m_periodicDataToReceive[snd], bufSize, MPI_DOUBLE, snd, 0, mpiComm(), &recv_Req[snd], AT_,
6810 "m_periodicDataToReceive[snd]");
6811 }
6812 }
6813 }
6814
6815 MPI_Waitall(noDomains(), &recv_Req[0], MPI_STATUSES_IGNORE, AT_);
6816 MPI_Waitall(noDomains(), &send_Req[0], MPI_STATUSES_IGNORE, AT_);
6817
6818 // inlet
6819 MFloat area = 0;
6820 MFloat localArea = 0;
6821 MFloat globalArea = 0;
6822 MFloat localPressure_1 = 0;
6823 MFloat globalPressure_1 = 0;
6824 MFloat localPressure_2 = 0;
6825 MFloat globalPressure_2 = 0;
6826 MFloat localMass = 0;
6827 MFloat globalMass = 0;
6828 MFloat localUbulk = 0;
6829 MFloat globalUbulk = 0;
6830 MFloat localDensity_2 = 0;
6831 MFloat globalDensity_2 = 0;
6832 MFloat localMeanMach_2 = 0;
6833 MFloat globalMeanMach_2 = 0;
6834
6835 for(MInt d = 0; d < noDomains(); d++) {
6836 for(MInt c = 0; c < m_noPerCellsToReceive[d]; c++) {
6837 const auto sortedId = static_cast<MInt>(m_periodicDataToReceive[d][5 + c * m_noPeriodicData]);
6838 const MInt cell_Id = m_sortedPeriodicCells->a[sortedId];
6839
6840 // inlet
6841 if(a_hasNeighbor(cell_Id, 0) == 0 && a_isHalo(cell_Id) == false) {
6842 MInt nghbrId = c_neighborId(cell_Id, 1);
6843 MInt bndryId = a_bndryId(nghbrId);
6844
6845
6846 if(bndryId > -1) {
6847 MFloat vfrac = m_bndryCells->a[bndryId].m_volume / POW3(c_cellLengthAtCell(nghbrId));
6848 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[1];
6849 if(srfcId > -1) {
6850 area = POW2(c_cellLengthAtCell(cell_Id)) * vfrac;
6851 } else {
6852 mTerm(1, AT_, "something went wrong!");
6853 }
6854 } else {
6855 area = POW2(c_cellLengthAtCell(cell_Id)); // m_lengthLevel0 / FPOW2( a_level( cell_Id )));
6856 }
6857
6858 localPressure_1 += area * a_pvariable(cell_Id, PV->P);
6859 localMeanMach_2 += area
6860 * sqrt(m_periodicDataToReceive[d][1 + c * m_noPeriodicData]
6861 * m_periodicDataToReceive[d][1 + c * m_noPeriodicData]
6862 + m_periodicDataToReceive[d][2 + c * m_noPeriodicData]
6863 * m_periodicDataToReceive[d][2 + c * m_noPeriodicData]
6864 + m_periodicDataToReceive[d][3 + c * m_noPeriodicData]
6865 * m_periodicDataToReceive[d][3 + c * m_noPeriodicData])
6866 / sqrt(1.4 * m_periodicDataToReceive[d][4 + c * m_noPeriodicData]
6867 / m_periodicDataToReceive[d][0 + c * m_noPeriodicData]);
6868 localPressure_2 += area * m_periodicDataToReceive[d][4 + c * m_noPeriodicData];
6869 localDensity_2 += area * m_periodicDataToReceive[d][0 + c * m_noPeriodicData];
6870 localMass += area * m_periodicDataToReceive[d][1 + c * m_noPeriodicData]
6871 * m_periodicDataToReceive[d][0 + c * m_noPeriodicData];
6872 localUbulk += area * m_periodicDataToReceive[d][1 + c * m_noPeriodicData];
6873 localArea += area;
6874 }
6875 }
6876 }
6877
6878 MPI_Allreduce(&localMass, &globalMass, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localMass", "globalMass");
6879 MPI_Allreduce(&localPressure_1, &globalPressure_1, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localPressure_1",
6880 "globalPressure_1");
6881 MPI_Allreduce(&localPressure_2, &globalPressure_2, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localPressure_2",
6882 "globalPressure_2");
6883 MPI_Allreduce(&localDensity_2, &globalDensity_2, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localDensity_2",
6884 "globalDensity_2");
6885 MPI_Allreduce(&localArea, &globalArea, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localArea", "globalArea");
6886 MPI_Allreduce(&localUbulk, &globalUbulk, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localUbulk", "globalUbulk");
6887 MPI_Allreduce(&localMeanMach_2, &globalMeanMach_2, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localMeanMach_2",
6888 "globalMeanMach_2");
6889
6890 globalPressure_1 = globalPressure_1 / globalArea;
6891 globalPressure_2 = globalPressure_2 / globalArea;
6892 globalMass = globalMass / globalArea;
6893 globalUbulk = globalUbulk / globalArea;
6894 globalDensity_2 = globalDensity_2 / globalArea;
6895 globalMeanMach_2 = globalMeanMach_2 / globalArea;
6896
6897
6898 // inlet2
6899 localArea = 0;
6900 globalArea = 0;
6901 area = 0;
6902 MFloat localPressure_3 = 0;
6903 MFloat globalPressure_3 = 0;
6904 MFloat localPressure_4 = 0;
6905 MFloat globalPressure_4 = 0;
6906
6907 for(MInt d = 0; d < noDomains(); d++) {
6908 for(MInt c = 0; c < m_noPerCellsToReceive[d]; c++) {
6909 const auto sortedId = static_cast<MInt>(m_periodicDataToReceive[d][5 + c * m_noPeriodicData]);
6910 const MInt cell_Id = m_sortedPeriodicCells->a[sortedId];
6911
6912 // inlet
6913 if(a_hasNeighbor(cell_Id, 0) > 0 && a_isHalo(cell_Id) == false && a_coordinate(cell_Id, 0) < 1.5) {
6914 MInt nghbrId = c_neighborId(cell_Id, 0);
6915 MInt bndryId = a_bndryId(nghbrId);
6916
6917 if(bndryId > -1) {
6918 MFloat vfrac = m_bndryCells->a[bndryId].m_volume / POW3(c_cellLengthAtCell(nghbrId));
6919 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[1];
6920 if(srfcId > -1) {
6921 area = POW2(c_cellLengthAtCell(cell_Id)) * vfrac;
6922 } else {
6923 mTerm(1, AT_, "something went wrong!");
6924 }
6925 } else {
6926 area = POW2(c_cellLengthAtCell(cell_Id)); // m_lengthLevel0 / FPOW2( a_level( cell_Id )));
6927 }
6928
6929 localPressure_3 += area * a_pvariable(cell_Id, PV->P);
6930 localPressure_4 += area * m_periodicDataToReceive[d][4 + c * m_noPeriodicData];
6931 localArea += area;
6932 }
6933 }
6934 }
6935
6936 MPI_Allreduce(&localPressure_3, &globalPressure_3, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localPressure_3",
6937 "globalPressure_3");
6938 MPI_Allreduce(&localPressure_4, &globalPressure_4, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localPressure_4",
6939 "globalPressure_4");
6940 MPI_Allreduce(&localArea, &globalArea, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localArea", "globalArea");
6941
6942 globalPressure_3 = globalPressure_3 / globalArea;
6943 globalPressure_4 = globalPressure_4 / globalArea;
6944
6945 // outlet
6946 area = 0;
6947 MFloat localPressure_5 = 0;
6948 MFloat globalPressure_5 = 0;
6949 MFloat localPressure_6 = 0;
6950 MFloat globalPressure_6 = 0;
6951 globalArea = 0;
6952 localArea = 0;
6953
6954
6955 for(MInt d = 0; d < noDomains(); d++) {
6956 for(MInt c = 0; c < m_noPerCellsToReceive[d]; c++) {
6957 const MInt sortedId = static_cast<MInt>(m_periodicDataToReceive[d][5 + c * m_noPeriodicData]);
6958 const MInt cell_Id = m_sortedPeriodicCells->a[sortedId];
6959
6960 // outlet
6961 if(a_hasNeighbor(cell_Id, 1) > 0 && a_isHalo(cell_Id) == false && a_coordinate(cell_Id, 0) > 1.5) {
6962 MInt nghbrId = c_neighborId(cell_Id, 1);
6963 MInt bndryId = a_bndryId(nghbrId);
6964
6965 if(bndryId > -1) {
6966 MFloat vfrac = m_bndryCells->a[bndryId].m_volume / POW3(c_cellLengthAtCell(nghbrId));
6967 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[0];
6968 if(srfcId > -1) {
6969 area = POW2(c_cellLengthAtCell(cell_Id)) * vfrac;
6970 } else {
6971 mTerm(1, AT_, "something went wrong!");
6972 }
6973 } else {
6974 area = POW2(c_cellLengthAtCell(cell_Id)); // m_lengthLevel0 / FPOW2( a_level( cell_Id )));
6975 }
6976
6977 localPressure_5 += area * a_pvariable(cell_Id, PV->P);
6978 localPressure_6 += area * m_periodicDataToReceive[d][4 + c * m_noPeriodicData];
6979 localArea += area;
6980 }
6981 }
6982 }
6983
6984 MPI_Allreduce(&localPressure_5, &globalPressure_5, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localPressure_5",
6985 "globalPressure_5");
6986 MPI_Allreduce(&localPressure_6, &globalPressure_6, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localPressure_6",
6987 "globalPressure_6");
6988 MPI_Allreduce(&localArea, &globalArea, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localArea", "globalArea");
6989
6990 globalPressure_5 = globalPressure_5 / globalArea;
6991 globalPressure_6 = globalPressure_6 / globalArea;
6992
6993 // outlet2
6994 area = 0;
6995 MFloat localPressure_7 = 0;
6996 MFloat globalPressure_7 = 0;
6997 MFloat localPressure_8 = 0;
6998 MFloat globalPressure_8 = 0;
6999 globalArea = 0;
7000 localArea = 0;
7001
7002
7003 for(MInt d = 0; d < noDomains(); d++) {
7004 for(MInt c = 0; c < m_noPerCellsToReceive[d]; c++) {
7005 const MInt sortedId = static_cast<MInt>(m_periodicDataToReceive[d][5 + c * m_noPeriodicData]);
7006 const MInt cell_Id = m_sortedPeriodicCells->a[sortedId];
7007
7008 // outlet
7009 if(a_hasNeighbor(cell_Id, 1) == 0 && a_isHalo(cell_Id) == false) {
7010 MInt nghbrId = c_neighborId(cell_Id, 0);
7011 MInt bndryId = a_bndryId(nghbrId);
7012
7013 if(bndryId > -1) {
7014 MFloat vfrac = m_bndryCells->a[bndryId].m_volume / POW3(c_cellLengthAtCell(nghbrId));
7015 MInt srfcId = m_bndryCells->a[bndryId].m_associatedSrfc[0];
7016 if(srfcId > -1) {
7017 area = POW2(c_cellLengthAtCell(cell_Id)) * vfrac;
7018 } else {
7019 mTerm(1, AT_, "something went wrong!");
7020 }
7021 } else {
7022 area = POW2(c_cellLengthAtCell(cell_Id)); // m_lengthLevel0 / FPOW2( a_level( cell_Id )));
7023 }
7024
7025 localPressure_7 += area * a_pvariable(cell_Id, PV->P);
7026 localPressure_8 += area * m_periodicDataToReceive[d][4 + c * m_noPeriodicData];
7027 localArea += area;
7028 }
7029 }
7030 }
7031
7032 MPI_Allreduce(&localPressure_7, &globalPressure_7, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localPressure_7",
7033 "globalPressure_7");
7034 MPI_Allreduce(&localPressure_8, &globalPressure_8, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localPressure_8",
7035 "globalPressure_8");
7036 MPI_Allreduce(&localArea, &globalArea, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localArea", "globalArea");
7037
7038 globalPressure_7 = globalPressure_7 / globalArea;
7039 globalPressure_8 = globalPressure_8 / globalArea;
7040
7041 m_TInfinity = 1.0 / (1.0 + F1B2 * 0.4 * POW2(m_Ma));
7042 // MFloat UT = m_Ma * sqrt(m_TInfinity);
7043 // MFloat m_delta_P = 0.3164 / sqrt(sqrt(sysEqn().m_Re0)) * m_referenceLength * F1B2 * m_rhoInfinity *
7044 // POW2(UT);//*4.94140625;
7045
7046 for(MInt d = 0; d < noDomains(); d++) {
7047 for(MInt c = 0; c < m_noPerCellsToReceive[d]; c++) {
7048 const MInt sortedId = static_cast<MInt>(m_periodicDataToReceive[d][5 + c * m_noPeriodicData]);
7049 const MInt cell_Id = m_sortedPeriodicCells->a[sortedId];
7050
7051 a_pvariable(cell_Id, PV->RHO) = m_periodicDataToReceive[d][0 + c * m_noPeriodicData];
7052 a_pvariable(cell_Id, PV->U) = m_periodicDataToReceive[d][1 + c * m_noPeriodicData];
7053 a_pvariable(cell_Id, PV->V) = m_periodicDataToReceive[d][2 + c * m_noPeriodicData];
7054 a_pvariable(cell_Id, PV->W) = m_periodicDataToReceive[d][3 + c * m_noPeriodicData];
7055 a_pvariable(cell_Id, PV->P) = m_periodicDataToReceive[d][4 + c * m_noPeriodicData];
7056 }
7057 }
7058
7059 m_target_Ubulk = m_Ma * sqrt(m_TInfinity); // m_rhoUInfinity;
7060
7061 if(globalTimeStep <= 1 || globalTimeStep == m_restartTimeStep) {
7062 m_oldUbulk = globalUbulk;
7063 m_oldPressure_Gradient = m_volumeAcceleration[0]; // m_delta_P;
7064 }
7065
7066 if(globalTimeStep > 1 && globalTimeStep > m_oldTimeStep) {
7067 UbulkDiff = (1 / timeStep()) * ((m_target_Ubulk - 2 * globalUbulk + m_oldUbulk));
7068
7069 MFloat m_delta_P = m_oldPressure_Gradient + UbulkDiff;
7070
7071 m_volumeAcceleration[0] = m_delta_P;
7072
7073 if(domainId() == 0) {
7074 cout << " step " << globalTimeStep << " deltaT " << timeStep() << " newPresGrad " << m_delta_P << " oldPresGrad "
7075 << m_oldPressure_Gradient << " Pinf " << m_PInfinity << " meanPres " << globalPressure_2 << " meanDens "
7076 << globalDensity_2 << " Mass_mean " << globalMass << " Umean " << globalUbulk << " UTarget "
7077 << m_Ma * sqrt(m_TInfinity) << " UmeanDiff" << globalUbulk - m_Ma * sqrt(m_TInfinity) << " meanMach "
7078 << globalMeanMach_2 << " machDiff" << m_Ma - globalMeanMach_2 << endl;
7079 }
7080
7081 m_oldPressure_Gradient = m_delta_P;
7082 m_oldUbulk = globalUbulk;
7083 }
7084
7085 m_oldTimeStep = globalTimeStep;
7086 computeConservativeVariables();
7087}
7088
7089
7093template <MInt nDim_, class SysEqn>
7094template <MBool exchangeAll_>
7096 TRACE();
7097 RECORD_TIMER_START(m_tgatherAndSend);
7098 RECORD_TIMER_START(m_tgather);
7099 for(MInt i = 0; i < noNeighborDomains(); i++) {
7100 MInt sendBufferCounter = 0;
7101 const MInt noWindows = (exchangeAll_) ? noWindowCells(i) : m_noMaxLevelWindowCells[i];
7102 for(MInt j = 0; j < noWindows; j++) {
7103 const MInt windowCell = (exchangeAll_) ? windowCellId(i, j) : m_maxLevelWindowCells[i][j];
7104 std::copy_n(&a_pvariable(windowCell, 0), m_dataBlockSize, &m_sendBuffers[i][sendBufferCounter]);
7105 sendBufferCounter += m_dataBlockSize;
7106 }
7107 }
7108 RECORD_TIMER_STOP(m_tgather);
7109 RECORD_TIMER_STOP(m_tgatherAndSend);
7110}
7111
7112
7116template <MInt nDim_, class SysEqn>
7117template <MBool exchangeAll_>
7119 TRACE();
7120 RECORD_TIMER_START(m_tscatter);
7121 for(MInt i = 0; i < noNeighborDomains(); i++) {
7122 MInt receiveBufferCounter = 0;
7123 const MInt noHalos = (exchangeAll_) ? noHaloCells(i) : m_noMaxLevelHaloCells[i];
7124 for(MInt j = 0; j < noHalos; j++) {
7125 const MInt haloCell = (exchangeAll_) ? haloCellId(i, j) : m_maxLevelHaloCells[i][j];
7126 std::copy_n(&m_receiveBuffers[i][receiveBufferCounter], m_dataBlockSize, &a_pvariable(haloCell, 0));
7127 receiveBufferCounter += m_dataBlockSize;
7128 }
7129 }
7130 RECORD_TIMER_STOP(m_tscatter);
7131}
7132
7133
7137template <MInt nDim_, class SysEqn>
7139 TRACE();
7140 RECORD_TIMER_START(m_tgatherAndSend);
7141 RECORD_TIMER_START(m_tsend);
7142 for(MInt i = 0; i < noNeighborDomains(); i++) {
7143 const MInt noWindows = (exchangeAll) ? noWindowCells(i) : m_noMaxLevelWindowCells[i];
7144 const MInt bufSize = noWindows * m_dataBlockSize;
7145 MPI_Issend(m_sendBuffers[i], bufSize, MPI_DOUBLE, neighborDomain(i), 0, mpiComm(), &m_mpi_request[i], AT_,
7146 "m_sendBuffers[i]");
7147 }
7148 RECORD_TIMER_STOP(m_tsend);
7149 RECORD_TIMER_STOP(m_tgatherAndSend);
7150}
7151
7152
7156template <MInt nDim_, class SysEqn>
7158 TRACE();
7159 if(noNeighborDomains() == 0) {
7160 return; // No neighbor -> serial + nonperiodic case
7161 }
7162 RECORD_TIMER_START(m_treceive);
7163
7164 ScratchSpace<MPI_Request> recvRequests(noNeighborDomains(), AT_, "recvRequests");
7165 recvRequests.fill(MPI_REQUEST_NULL);
7166
7167 RECORD_TIMER_START(m_treceiving);
7168 // Start receiving from all neighbors
7169 for(MInt i = 0; i < noNeighborDomains(); i++) {
7170 const MInt noHalos = (exchangeAll) ? noHaloCells(i) : m_noMaxLevelHaloCells[i];
7171 const MInt bufSize = noHalos * m_dataBlockSize;
7172 MPI_Irecv(m_receiveBuffers[i], bufSize, type_traits<MFloat>::mpiType(), neighborDomain(i), 0, mpiComm(),
7173 &recvRequests[i], AT_, "m_receiveBuffer[i]");
7174 }
7175 RECORD_TIMER_STOP(m_treceiving);
7176
7177 RECORD_TIMER_START(m_treceiveWait);
7178 // Wait for all send and receive requests to finish
7179 MPI_Waitall(noNeighborDomains(), &m_mpi_request[0], MPI_STATUSES_IGNORE, AT_);
7180 MPI_Waitall(noNeighborDomains(), &recvRequests[0], MPI_STATUSES_IGNORE, AT_);
7181 RECORD_TIMER_STOP(m_treceiveWait);
7182
7183 RECORD_TIMER_STOP(m_treceive);
7184}
7185
7186template <MInt nDim_, class SysEqn>
7188 if(m_levelSetMb) return; // m_cellSurfaceMapping is filled in a different way inside the FvMb Solver
7189
7190 const MUint noSurfaces = a_noSurfaces();
7191
7192 for(MUint srfcId = 0; srfcId < noSurfaces; srfcId++) {
7193 const MInt orientation = a_surfaceOrientation(srfcId);
7194 const MInt nghbrId0 = a_surfaceNghbrCellId(srfcId, 0);
7195 const MInt nghbrId1 = a_surfaceNghbrCellId(srfcId, 1);
7196
7197 if(a_level(nghbrId1) > a_level(nghbrId0)) {
7198 m_cellSurfaceMapping[nghbrId0][2 * orientation + 1] = -1;
7199 m_cellSurfaceMapping[nghbrId1][2 * orientation] = srfcId;
7200 } else {
7201 m_cellSurfaceMapping[nghbrId0][2 * orientation + 1] = srfcId;
7202 m_cellSurfaceMapping[nghbrId1][2 * orientation] = -1;
7203 }
7204
7205 if(a_level(nghbrId0) == a_level(nghbrId1)) {
7206 m_cellSurfaceMapping[nghbrId0][2 * orientation + 1] = srfcId;
7207 m_cellSurfaceMapping[nghbrId1][2 * orientation] = srfcId;
7208 }
7209 }
7210}
7211
7212template <MInt nDim_, class SysEqn>
7213template <class _, std::enable_if_t<isDetChem<SysEqn>, _*>>
7215 MFloat* const dtdn) {
7216 TRACE();
7217
7218 const MInt noDirs = 2 * nDim;
7219 const MUint noPVars = PV->noVariables;
7220 const MUint noSurfaceCoefficients = hasSC ? SC->m_noSurfaceCoefficients : 0;
7221 const MUint surfaceVarMemory = 2 * noPVars;
7222 const MUint noSlopes = nDim * noPVars;
7223
7224 const MInt* const RESTRICT orientations = ALIGNED_I(&a_surfaceOrientation(0));
7225 const MInt* const RESTRICT nghbrCellIds = ALIGNED_I(&a_surfaceNghbrCellId(0, 0));
7226 const MFloat* const RESTRICT surfaceVars = ALIGNED_F(&a_surfaceVariable(0, 0, 0));
7227 const MFloat* const RESTRICT surfaceCoefficients = hasSC ? ALIGNED_F(&a_surfaceCoefficient(0, 0)) : nullptr;
7228 const MFloat* const RESTRICT factor = ALIGNED_F(&a_surfaceFactor(0, 0));
7229 const MFloat* const RESTRICT slope = ALIGNED_F(&a_slope(0, 0, 0));
7230
7231#ifdef _OPENMP
7232#pragma omp parallel for
7233#endif
7234
7235 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
7236 vector<vector<MFloat>> J(noDirs, vector<MFloat>(PV->m_noSpecies, F0));
7237 vector<vector<MFloat>> J_noSoret(noDirs, vector<MFloat>(PV->m_noSpecies, F0));
7238 vector<vector<MFloat>> dXdn(noDirs, vector<MFloat>(PV->m_noSpecies, F0));
7239 vector<vector<MFloat>> dXdn_int(nDim, vector<MFloat>(PV->m_noSpecies, F0));
7240 vector<MFloat> dXH2dn1(2, F0);
7241 vector<MFloat> dTdn(noDirs, F0);
7242 vector<MFloat> DH2(noDirs, F0);
7243 vector<vector<MFloat>> J_int(nDim, vector<MFloat>(PV->m_noSpecies, F0));
7244 vector<vector<MFloat>> J_noSoret_int(nDim, vector<MFloat>(PV->m_noSpecies, F0));
7245 vector<MFloat> dTdn_int(nDim, F0);
7246
7247
7248 for(MInt dir = 0; dir < noDirs; dir++) {
7249 const MInt srfcId = m_cellSurfaceMapping[cellId][dir];
7250 if(srfcId < 0) continue;
7251
7252 ASSERT((nghbrCellIds[2 * srfcId] == cellId) || (nghbrCellIds[2 * srfcId + 1] == cellId), "");
7253
7254 const MUint offset = srfcId * surfaceVarMemory;
7255 const MFloat* const RESTRICT vars0 = ALIGNED_F(surfaceVars + offset);
7256 const MFloat* const RESTRICT vars1 = ALIGNED_F(vars0 + noPVars);
7257 const MFloat f0 = factor[srfcId * 2];
7258 const MFloat f1 = factor[srfcId * 2 + 1];
7259 const MUint offset0 = nghbrCellIds[2 * srfcId] * noSlopes;
7260 const MUint offset1 = nghbrCellIds[2 * srfcId + 1] * noSlopes;
7261 const MFloat* const RESTRICT slope0 = ALIGNED_F(slope + offset0);
7262 const MFloat* const RESTRICT slope1 = ALIGNED_F(slope + offset1);
7263 const MUint coefficientOffset = srfcId * noSurfaceCoefficients;
7264 const MFloat* const RESTRICT srfcCoeff = hasSC ? ALIGNED_F(surfaceCoefficients + coefficientOffset) : nullptr;
7265
7266 sysEqn().getSpeciesDiffusionMassFluxes(orientations[srfcId], vars0, vars1, slope0, slope1, srfcCoeff, f0, f1,
7267 J[dir], dXdn[dir], dTdn[dir], sysEqn().m_soretEffect);
7268 sysEqn().getSpeciesDiffusionMassFluxes(orientations[srfcId], vars0, vars1, slope0, slope1, srfcCoeff, f0, f1,
7269 J_noSoret[dir], dXdn[dir], dTdn[dir], false);
7270 for(MUint s = 0; s < PV->m_noSpecies; s++) {
7271 if(m_speciesName[s] == "H2") DH2[dir] = a_srfcCoeffs(srfcId, SC->D[s]);
7272 if(m_speciesName[s] == "H2" && (dir == 0 || dir == 1)) dXH2dn1[dir] = dXdn[dir][s];
7273 }
7274 }
7275
7276 for(MInt dim = 0; dim < nDim; dim++) {
7277 dTdn_int[dim] = dTdn[2 * dim] + F1B2 * (dTdn[2 * dim + 1] - dTdn[2 * dim]);
7278 dtdn[cellId * nDim + dim] = dTdn_int[dim];
7279 for(MUint s = 0; s < PV->m_noSpecies; s++) {
7280 J_int[dim][s] = J[2 * dim][s] + F1B2 * (J[2 * dim + 1][s] - J[2 * dim][s]);
7281 dXdn_int[dim][s] = dXdn[2 * dim][s] + F1B2 * (dXdn[2 * dim + 1][s] - dXdn[2 * dim][s]);
7282 dXdn[cellId * nDim * PV->m_noSpecies + dim * PV->m_noSpecies + s] = dXdn_int[dim][s];
7283 J[cellId * nDim * PV->m_noSpecies + dim * PV->m_noSpecies + s] = J_int[dim][s];
7284 }
7285 }
7286 }
7287}
7288
7289template <MInt nDim_, class SysEqn>
7291 TRACE();
7292
7293 MBool flag;
7294 const MInt noSrfcs = a_noSurfaces();
7295 const MInt noDirs = 2 * nDim;
7296
7297 //---
7298 switch(m_upwindMethod) {
7299 default: {
7300 for(MInt s = 0; s < noSrfcs; s++) {
7301 flag = false;
7302 for(MInt side = 0; side < 2; side++) {
7303 for(MInt d = 0; d < noDirs; d++) {
7304 MInt gridcellId = a_surfaceNghbrCellId(s, side);
7305 MInt gridcellId2 = a_surfaceNghbrCellId(s, side);
7306 if(a_hasProperty(gridcellId, SolverCell::IsSplitClone)) {
7307 gridcellId = m_splitChildToSplitCell.find(gridcellId)->second;
7308 }
7309 if(a_hasProperty(gridcellId2, SolverCell::IsSplitClone)) {
7310 gridcellId2 = m_splitChildToSplitCell.find(gridcellId2)->second;
7311 }
7312 if(a_isBndryGhostCell(a_surfaceNghbrCellId(s, side)) || c_parentId(gridcellId) == -1) {
7313 continue;
7314 }
7315 if(a_hasNeighbor(gridcellId, d) > 0) {
7316 continue;
7317 }
7318 if(a_hasNeighbor(c_parentId(gridcellId2), d) == 0) {
7319 continue;
7320 }
7321 if(c_noChildren(c_neighborId(c_parentId(gridcellId2), d)) > 0) {
7322 continue;
7323 }
7324 flag = true;
7325 d = noDirs;
7326 }
7327 }
7328 if(flag) {
7329 a_surfaceUpwindCoefficient(s) = m_chi;
7330 } else {
7331 a_surfaceUpwindCoefficient(s) = m_globalUpwindCoefficient;
7332 }
7333 }
7334 if(m_combustion && m_jet) {
7335 m_log << "upwinding on coarse level is set to max upwind coefficient 0.5, only valid when the coarse level "
7336 "is not of interest !!!!"
7337 << endl;
7338 for(MInt s = 0; s < noSrfcs; s++) {
7339 if(a_isBndryGhostCell(a_surfaceNghbrCellId(s, 0)) || a_isBndryGhostCell(a_surfaceNghbrCellId(s, 1))) {
7340 continue;
7341 }
7342 if(a_surfaceNghbrCellId(s, 0) == -1 || a_surfaceNghbrCellId(s, 1) == -1) {
7343 continue;
7344 }
7345 if(a_level(a_surfaceNghbrCellId(s, 0)) == maxLevel() && a_level(a_surfaceNghbrCellId(s, 1)) == maxLevel()) {
7346 continue;
7347 }
7348
7349 a_surfaceUpwindCoefficient(s) = m_chi;
7350 }
7351 }
7352
7353 break;
7354 }
7355
7356 // Upwinding at coarse-fine surfaces only
7357 case 1: {
7358 for(MInt s = 0; s < noSrfcs; s++) {
7359 flag = false;
7360 for(MInt side = 0; side < 2; side++) {
7361 MInt gridcellId = a_surfaceNghbrCellId(s, side);
7362 MInt orientation = a_surfaceOrientation(s);
7363 MInt d = 2 * orientation + (1 - side);
7364 TERMM_IF_NOT_COND(gridcellId == a_surfaceNghbrCellId(s, side), "");
7365 if(a_hasProperty(gridcellId, SolverCell::IsSplitClone)) {
7366 gridcellId = m_splitChildToSplitCell.find(gridcellId)->second;
7367 }
7368 if(a_isBndryGhostCell(a_surfaceNghbrCellId(s, side)) || c_parentId(gridcellId) == -1) {
7369 continue;
7370 }
7371 if(a_hasNeighbor(gridcellId, d) > 0) {
7372 continue;
7373 }
7374 if(a_hasNeighbor(c_parentId(gridcellId), d) == 0) {
7375 continue;
7376 }
7377 if(c_noChildren(c_neighborId(c_parentId(gridcellId), d)) > 0) {
7378 continue;
7379 }
7380 flag = true;
7381 }
7382 if(flag) {
7383 a_surfaceUpwindCoefficient(s) = m_chi;
7384 } else {
7385 a_surfaceUpwindCoefficient(s) = m_globalUpwindCoefficient;
7386 }
7387 }
7388 break;
7389 }
7390
7391 // Upwinding on coarse-fine surface and its opposite surface on fine cell
7392 case 2: {
7393 for(MInt s = 0; s < noSrfcs; s++) {
7394 flag = false;
7395 for(MInt side = 0; side < 2; side++) {
7396 MInt gridcellId = a_surfaceNghbrCellId(s, side);
7397 MInt orientation = a_surfaceOrientation(s);
7398 TERMM_IF_NOT_COND(gridcellId == a_surfaceNghbrCellId(s, side), "");
7399 for(MInt side2 = 0; side2 < 2; ++side2) {
7400 MInt d = 2 * orientation + side2;
7401 if(a_hasProperty(gridcellId, SolverCell::IsSplitClone)) {
7402 gridcellId = m_splitChildToSplitCell.find(gridcellId)->second;
7403 }
7404 if(a_isBndryGhostCell(a_surfaceNghbrCellId(s, side)) || c_parentId(gridcellId) == -1) {
7405 continue;
7406 }
7407 if(a_hasNeighbor(gridcellId, d) > 0) {
7408 continue;
7409 }
7410 if(a_hasNeighbor(c_parentId(gridcellId), d) == 0) {
7411 continue;
7412 }
7413 if(c_noChildren(c_neighborId(c_parentId(gridcellId), d)) > 0) {
7414 continue;
7415 }
7416 flag = true;
7417 break;
7418 }
7419 }
7420 if(flag) {
7421 a_surfaceUpwindCoefficient(s) = m_chi;
7422 } else {
7423 a_surfaceUpwindCoefficient(s) = m_globalUpwindCoefficient;
7424 }
7425 }
7426 break;
7427 }
7428
7429 // FAN --> Alexej Pogorelov
7430 case 38:
7431 case 36: {
7432 if(m_periodicCells == 1) { // azimuthal periodicity concept
7433
7434 MFloat radius = 0.0;
7435 MInt cellId = -1;
7436
7437 for(MInt s = 0; s < noSrfcs; s++) {
7438 flag = false;
7439 for(MInt side = 0; side < 2; side++) {
7440 for(MInt d = 0; d < noDirs; d++) {
7441 cellId = a_surfaceNghbrCellId(s, side);
7442 if(a_isBndryGhostCell(cellId)) continue;
7443 radius = 0.0;
7444 for(MInt i = 0; i < 2; i++) {
7445 radius += pow(a_coordinate(cellId, i + 1) - m_rotAxisCoord[i], 2.0);
7446 }
7447 radius = sqrt(radius);
7448
7449 const MFloat halfLength = c_cellLengthAtLevel(minLevel() + 1);
7450
7451 if(a_hasProperty(a_surfaceNghbrCellId(s, side), SolverCell::IsPeriodicWithRot)
7452 && radius < 8.0 * halfLength) {
7453 flag = true;
7454 break;
7455 }
7456 MInt gridcellId = a_surfaceNghbrCellId(s, side);
7457 MInt gridcellId2 = a_surfaceNghbrCellId(s, side);
7458 if(a_hasProperty(gridcellId, SolverCell::IsSplitClone)) {
7459 gridcellId = m_splitChildToSplitCell.find(gridcellId)->second;
7460 }
7461 if(a_hasProperty(gridcellId2, SolverCell::IsSplitClone)) {
7462 gridcellId2 = m_splitChildToSplitCell.find(gridcellId2)->second;
7463 }
7464 if(a_hasNeighbor(gridcellId, d) > 0) {
7465 cellId = c_neighborId(gridcellId, d);
7466 radius = 0.0;
7467 for(MInt i = 0; i < 2; i++) {
7468 radius += pow(a_coordinate(cellId, i + 1) - m_rotAxisCoord[i], 2.0);
7469 }
7470 radius = sqrt(radius);
7471
7472
7473 if(a_hasProperty(c_neighborId(gridcellId, d), SolverCell::IsPeriodicWithRot)
7474 && radius < 8.0 * halfLength) {
7475 flag = true;
7476 d = noDirs;
7477 break;
7478 }
7479 }
7480
7481
7482 if(a_hasNeighbor(gridcellId, d) > 0) {
7483 continue;
7484 }
7485 if(c_parentId(gridcellId) == -1) {
7486 continue;
7487 }
7488 if(a_hasNeighbor(c_parentId(gridcellId2), d) == 0) {
7489 continue;
7490 }
7491 if(c_noChildren(c_neighborId(c_parentId(gridcellId2), d)) > 0) {
7492 continue;
7493 }
7494 if(!a_hasProperty(c_neighborId(c_parentId(gridcellId2), d), SolverCell::IsOnCurrentMGLevel)) {
7495 continue;
7496 }
7497 flag = true;
7498 d = noDirs;
7499 }
7500 }
7501
7502
7503 if(flag) {
7504 a_surfaceUpwindCoefficient(s) = m_chi;
7505 } else {
7506 a_surfaceUpwindCoefficient(s) = m_globalUpwindCoefficient;
7507 }
7508 }
7509 }
7510
7511 } break;
7512
7513 case 1949: {
7514 for(MInt s = 0; s < noSrfcs; s++) {
7515 flag = false;
7516 for(MInt side = 0; side < 2; side++) {
7517 for(MInt d = 0; d < noDirs; d++) {
7518 MInt gridcellId = a_surfaceNghbrCellId(s, side);
7519 if(a_hasProperty(gridcellId, SolverCell::IsSplitClone)) {
7520 gridcellId = m_splitChildToSplitCell.find(gridcellId)->second;
7521 }
7522 if(a_hasNeighbor(gridcellId, d) > 0) {
7523 continue;
7524 }
7525 if(c_parentId(gridcellId) == -1) {
7526 continue;
7527 }
7528 if(a_hasNeighbor(c_parentId(gridcellId), d) == 0) {
7529 continue;
7530 }
7531 flag = true;
7532 d = noDirs;
7533 }
7534 }
7535 if(flag || ABS(a_surfaceCoordinate(s, 1) - 50) < 10) {
7536 a_surfaceUpwindCoefficient(s) = m_chi;
7537 } else {
7538 a_surfaceUpwindCoefficient(s) = m_globalUpwindCoefficient;
7539 }
7540 }
7541 } break;
7542 }
7543}
7544
7545
7546template <MInt nDim_, class SysEqn>
7548 TRACE();
7549
7550 for(MInt cellId = 0; cellId < a_noCells(); ++cellId) {
7551 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
7552 continue;
7553 }
7554 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) {
7555 continue;
7556 }
7557 if(a_isBndryGhostCell(cellId)) {
7558 continue;
7559 }
7560 if(a_hasProperty(cellId, SolverCell::IsSplitClone)) {
7561 continue;
7562 }
7563
7564 for(MInt dir = 0; dir < m_noDirs; ++dir) {
7565 if(a_hasNeighbor(cellId, dir) > 0) { // nghbr on same or higher lvl
7566 const MInt nghbrId = c_neighborId(cellId, dir);
7567 if(c_noChildren(nghbrId) > 0) { // finer neighbor
7568 TERMM_IF_COND(a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel),
7569 "Nghbr can't have children & be on curent MG lvl!");
7570 // Ensure that at least one of the children is adjacent to current cell.
7571 // If cell is not bndry cell, it must have IPOW2(nDim-1) nghbrs on higher lvl.
7572 MInt noNghbrChilds = 0;
7573 for(MInt child = 0; child < IPOW2(nDim); child++) {
7574 if(c_childId(nghbrId, child) > -1) {
7575 if(childCodePro[dir] & 1 << child) { // check if adjacent to current cell.
7576 TERMM_IF_NOT_COND(a_hasProperty(c_childId(nghbrId, child), SolverCell::IsOnCurrentMGLevel),
7577 "Unkown situation!");
7578 ++noNghbrChilds;
7579 }
7580 }
7581 }
7582 TERMM_IF_COND(!a_isBndryCell(cellId) && noNghbrChilds != IPOW2(nDim - 1), "");
7583 if(noNghbrChilds > 0) {
7584 // a bndry cell may have less then IPOW2(nDim-1) finer nghbrs
7585 m_cells.nghbrInterface(cellId, dir, 2);
7586 } else { // no neighbor at all
7587 m_cells.nghbrInterface(cellId, dir, 0);
7588 }
7589 } else { // neighbor on same level
7590 m_cells.nghbrInterface(cellId, dir, 1);
7591 }
7592 } else if(c_parentId(cellId) > -1 && a_hasNeighbor(c_parentId(cellId), dir) > 0
7593 && a_hasProperty(c_neighborId(c_parentId(cellId), dir),
7594 SolverCell::IsOnCurrentMGLevel)) { // coarse neighbor
7595 const MInt parentId = c_parentId(cellId);
7596 for(MInt child = 0; child < IPOW2(nDim); child++) {
7597 if(c_childId(parentId, child) == cellId) {
7598 if((childCodePro[m_revDir[dir]] & 1 << child) == (uint_fast8_t)0) {
7599 m_cells.nghbrInterface(cellId, dir, 0);
7600 } else {
7601 m_cells.nghbrInterface(cellId, dir, 3);
7602 }
7603 break;
7604 }
7605 }
7606 } else { // no neighbor at all
7607 m_cells.nghbrInterface(cellId, dir, 0);
7608 }
7609 }
7610
7611 a_hasProperty(cellId, SolverCell::HasCoarseNghbr) = false;
7612 for(MInt d = 0; d < nDim; ++d) {
7613 if(m_cells.nghbrInterface(cellId, 2 * d) == 3 || m_cells.nghbrInterface(cellId, 2 * d + 1) == 3) {
7614 a_hasProperty(cellId, SolverCell::HasCoarseNghbr) = true;
7615 break;
7616 }
7617 }
7618 }
7619}
7620
7621
7622template <MInt nDim_, class SysEqn>
7624 TRACE();
7625
7626 const MInt noFVars = FV->noVariables;
7627 const MInt noCells = a_noCells();
7628
7629 const MInt offset = noInternalCells();
7630 //---
7631
7632#ifdef _OPENMP
7633#pragma omp parallel for collapse(2)
7634#endif
7635 for(MInt c = offset; c < noCells; c++) {
7636 for(MInt varId = 0; varId < noFVars; varId++) {
7637 a_rightHandSide(c, varId) = F0;
7638 }
7639 }
7640}
7641
7645template <MInt nDim_, class SysEqn>
7647 TRACE();
7648
7649 m_surfaces.clear(); // invalidate all elements and set size to 0
7650}
7651
7652
7653// if no multisolver is used properties 11 and 13 are equivalent
7654// uses b_properties[SolverCell::IsFlux], which is set in tagCellsNeededForSurfaceFlux
7655template <MInt nDim_, class SysEqn>
7657 TRACE();
7658
7659 // reset
7660 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
7661 a_hasProperty(cellId, SolverCell::IsActive) = a_hasProperty(cellId, SolverCell::IsFlux);
7662 }
7663
7664 // include all cells involved in the reconstruction process
7665 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
7666 if(a_hasProperty(cellId, SolverCell::IsActive)) {
7667 for(MInt c = 0; c < a_noReconstructionNeighbors(cellId); c++) {
7668 a_hasProperty(a_reconstructionNeighborId(cellId, c), SolverCell::IsActive) = true;
7669 }
7670 }
7671 }
7672
7673 m_noActiveCells = 0;
7674 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
7675 if(a_hasProperty(cellId, SolverCell::IsActive)) {
7676 m_activeCellIds[m_noActiveCells] = cellId;
7677 m_noActiveCells++;
7678 }
7679 }
7680 m_noActiveHaloCellOffset = m_noActiveCells;
7681 for(MInt cellId = noInternalCells(); cellId < a_noCells(); cellId++) {
7682 if(a_hasProperty(cellId, SolverCell::IsActive)) {
7683 m_activeCellIds[m_noActiveCells] = cellId;
7684 m_noActiveCells++;
7685 }
7686 }
7687 m_log << "Time step - Active cells: " << globalTimeStep << " " << m_noActiveHaloCellOffset << " " << m_noActiveCells
7688 << endl;
7689}
7690
7691
7692// --------------------------------------------------------------------------------------
7693
7694
7695template <MInt nDim_, class SysEqn>
7697 TRACE();
7698 const MInt noCells = a_noCells();
7699 const MInt noDirs = 2 * nDim;
7700
7701 //---
7702
7703 // set property 13 - cell is on the current computing level
7704 // if multilevel computation is applied the maxRfnmntLevel should be changed to a new variable like
7705 // m_currentMultiGridLevel
7706 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
7707 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) =
7708 ((c_isLeafCell(cellId) && a_level(cellId) <= maxRefinementLevel())
7709 || (!c_isLeafCell(cellId) && a_level(cellId) == maxRefinementLevel()))
7710 && !a_hasProperty(cellId, SolverCell::IsInvalid);
7711 }
7712
7713
7714 // set property defaults:
7715#ifdef _OPENMP
7716#pragma omp parallel for simd
7717#endif
7718 for(MInt c = 0; c < noCells; c++) {
7719 a_isHalo(c) = false;
7720 a_hasProperty(c, SolverCell::IsNotGradient) = false;
7721 }
7722
7723 // set property 15 - cell is a multisolver halo cell
7724 for(MInt i = 0; i < noNeighborDomains(); i++) {
7725 for(MInt c = 0; c < noHaloCells(i); c++) {
7726 a_isHalo(haloCellId(i, c)) = true;
7727 }
7728 }
7729 // Azimuthal periodicty exchange halos
7730 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
7731 for(MInt c = 0; c < grid().noAzimuthalHaloCells(i); c++) {
7732 a_isHalo(grid().azimuthalHaloCell(i, c)) = true;
7733 }
7734 }
7735 for(MInt c = 0; c < grid().noAzimuthalUnmappedHaloCells(); c++) {
7736 a_isHalo(grid().azimuthalUnmappedHaloCell(c)) = true;
7737 }
7738
7739 // set property 7 - cell is a not gradient
7740 // no gradient needs to be computed on those cells
7741 for(MInt i = 0; i < noNeighborDomains(); i++) {
7742 for(MInt c = 0; c < noHaloCells(i); c++) {
7743 a_hasProperty(haloCellId(i, c), SolverCell::IsNotGradient) = true;
7744 if(!a_hasProperty(haloCellId(i, c), SolverCell::IsOnCurrentMGLevel)) continue;
7745 for(MInt d = 0; d < noDirs; d++) {
7746 if(a_hasNeighbor(haloCellId(i, c), d) > 0) {
7747 if(!a_isHalo(c_neighborId(haloCellId(i, c), d))) {
7748 a_hasProperty(haloCellId(i, c), SolverCell::IsNotGradient) = false;
7749 }
7750 } else {
7751 MInt parentId = c_parentId(haloCellId(i, c));
7752 if(parentId > -1) {
7753 if(a_hasNeighbor(parentId, d) > 0) {
7754 if(!a_isHalo(c_neighborId(parentId, d))) {
7755 a_hasProperty(haloCellId(i, c), SolverCell::IsNotGradient) = false;
7756 }
7757 }
7758 }
7759 }
7760 }
7761 }
7762 }
7763
7764 // Azimuthal periodicty exchange halos
7765 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
7766 for(MInt c = 0; c < grid().noAzimuthalHaloCells(i); c++) {
7767 MInt cellId = grid().azimuthalHaloCell(i, c);
7768 a_hasProperty(cellId, SolverCell::IsNotGradient) = true;
7769 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
7770 for(MInt d = 0; d < noDirs; d++) {
7771 if(a_hasNeighbor(cellId, d) > 0) {
7772 if(!a_isHalo(c_neighborId(cellId, d))) {
7773 a_hasProperty(cellId, SolverCell::IsNotGradient) = false;
7774 }
7775 } else {
7776 MInt parentId = c_parentId(cellId);
7777 if(parentId > -1) {
7778 if(a_hasNeighbor(parentId, d) > 0) {
7779 if(!a_isHalo(c_neighborId(parentId, d))) {
7780 a_hasProperty(cellId, SolverCell::IsNotGradient) = false;
7781 }
7782 }
7783 }
7784 }
7785 }
7786 }
7787 }
7788 for(MInt c = 0; c < grid().noAzimuthalUnmappedHaloCells(); c++) {
7789 MInt cellId = grid().azimuthalUnmappedHaloCell(c);
7790 a_hasProperty(cellId, SolverCell::IsNotGradient) = true;
7791 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
7792 for(MInt d = 0; d < noDirs; d++) {
7793 if(a_hasNeighbor(cellId, d) > 0) {
7794 if(!a_isHalo(c_neighborId(cellId, d))) {
7795 a_hasProperty(cellId, SolverCell::IsNotGradient) = false;
7796 }
7797 } else {
7798 MInt parentId = c_parentId(cellId);
7799 if(parentId > -1) {
7800 if(a_hasNeighbor(parentId, d) > 0) {
7801 if(!a_isHalo(c_neighborId(parentId, d))) {
7802 a_hasProperty(cellId, SolverCell::IsNotGradient) = false;
7803 }
7804 }
7805 }
7806 }
7807 }
7808 }
7809
7810 // Copy Periodic-Cell-Property as a grid-property!
7811 for(MInt id = 0; id < a_noCells(); ++id) {
7812 if(a_hasProperty(id, SolverCell::IsSplitChild)) continue;
7813 if(a_isBndryGhostCell(id)) continue;
7814 if(a_hasProperty(id, SolverCell::IsSplitClone)) continue;
7815 assertValidGridCellId(id);
7816 a_isPeriodic(id) = grid().isPeriodic(id);
7817 }
7818
7819 // Set Cell-Properties for Splitchilds:
7820 for(MInt splitId = 0; (unsigned)splitId < m_splitCells.size(); splitId++) {
7821 MInt scId = m_splitCells[splitId];
7822 if(a_isHalo(scId)) {
7823 for(MInt ssc = 0; (unsigned)ssc < m_splitChilds[splitId].size(); ssc++) {
7824 MInt splitChildId = m_splitChilds[splitId][ssc];
7825 a_isHalo(splitChildId) = true;
7826 }
7827 }
7828 if(a_isPeriodic(scId)) {
7829 for(MInt ssc = 0; (unsigned)ssc < m_splitChilds[splitId].size(); ssc++) {
7830 MInt splitChildId = m_splitChilds[splitId][ssc];
7831 a_isPeriodic(splitChildId) = true;
7832 }
7833 }
7834 }
7835
7836 initSpongeLayer();
7837}
7838
7839
7840// --------------------------------------------------------------------------------------
7841
7842
7843template <MInt nDim_, class SysEqn>
7845 TRACE();
7846
7847 const MInt noCells = a_noCells();
7848 const MInt noDirs = 2 * nDim;
7849 const MFloat epsilon = m_spongeLayerThickness / 10000000.0;
7850 MFloat constant = NAN;
7851 MFloatScratchSpace delta(noDirs, AT_, "delta");
7852 MFloatScratchSpace dis(nDim, AT_, "dis");
7853 MFloat beta = 1.0;
7854 MFloat maxSpongeFactor = 0.0;
7855 MFloat minSpongeFactor = 100.0;
7856
7857 //---
7858
7859 // initialize the arrays containing the list of cells in the sponge layer
7860 if(!m_createSpongeBoundary) {
7861 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
7862 a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = false;
7863 a_spongeFactor(cellId) = F0;
7864 }
7865
7866 m_noCellsInsideSpongeLayer = 0;
7867 if(m_spongeLayerThickness > F0) {
7868 switch(m_spongeLayerLayout) {
7869 case 0: {
7870 for(MInt cellId = 0; cellId < noCells; cellId++) {
7871 if(a_isBndryGhostCell(cellId)) {
7872 continue;
7873 }
7874 a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = false;
7875 a_spongeFactor(cellId) = F0;
7876 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
7877 // compute the distance from the sponge layer
7878 // if the cell is not inside the sponge layer, the distance is set to zero
7879 for(MInt i = 0; i < nDim; i++) {
7880 delta.p[2 * i] =
7881 mMax(F0, (a_coordinate(cellId, i) - m_spongeCoord[2 * i + 1]) * m_spongeCoord[noDirs + 2 * i + 1]);
7882 delta.p[2 * i + 1] =
7883 mMin(F0, (a_coordinate(cellId, i) - m_spongeCoord[2 * i]) * m_spongeCoord[noDirs + 2 * i]);
7884 delta.p[2 * i + 1] = fabs(delta.p[2 * i + 1]);
7885 dis.p[i] = mMax(delta.p[2 * i], delta.p[2 * i + 1]);
7886 }
7887
7888 // compute the dissipation function...
7889 constant = F0;
7890 for(MInt i = 0; i < nDim; i++) {
7891 constant = mMax(constant, ABS(dis.p[i]));
7892 }
7893 constant = pow(constant, beta);
7894 constant *= m_sigmaSponge;
7895
7896 if(constant > epsilon) {
7897 m_cellsInsideSpongeLayer[m_noCellsInsideSpongeLayer] = cellId;
7898 m_noCellsInsideSpongeLayer++;
7899 a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = true;
7900 a_spongeFactor(cellId) = constant;
7901 maxSpongeFactor = mMax(maxSpongeFactor, a_spongeFactor(cellId));
7902 minSpongeFactor = mMin(minSpongeFactor, a_spongeFactor(cellId));
7903 }
7904 }
7905 }
7906 if(globalTimeStep < 1) {
7907 m_log << endl;
7908 m_log << "*************************************************************" << endl;
7909 m_log << "Information for domain sponge: " << endl;
7910 m_log << "*************************************************************" << endl;
7911
7912 m_log << "number of cells inside sponge layer " << m_noCellsInsideSpongeLayer << endl;
7913 m_log << "max sponge factor: " << maxSpongeFactor << endl;
7914 m_log << "min sponge factor: " << minSpongeFactor << endl << endl;
7915 }
7916 break;
7917 }
7918 case 2: {
7919 MFloat radius = NAN;
7920 IF_CONSTEXPR(nDim == 3) {
7921 for(MInt cellId = 0; cellId < noCells; cellId++) {
7922 a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = false;
7923 a_spongeFactor(cellId) = F0;
7924 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
7925 // compute the distance from the sponge layer (streamwise direction is y)
7926 // if the cell is not inside the sponge layer, the distance is set to zero
7927 // radial (xz)
7928 radius = sqrt(POW2(a_coordinate(cellId, 0)) + POW2(a_coordinate(cellId, 2)));
7929 delta.p[0] = mMax(F0, (radius - ABS(m_spongeCoord[1])) * m_spongeCoord[noDirs + 1]);
7930 dis.p[0] = delta.p[0];
7931 dis.p[2] = F0;
7932 // streamwise (y)
7933 delta.p[2] = mMax(F0, (a_coordinate(cellId, 1) - m_spongeCoord[3]) * m_spongeCoord[noDirs + 3]);
7934 delta.p[3] = mMin(F0, (a_coordinate(cellId, 1) - m_spongeCoord[2]) * m_spongeCoord[noDirs + 2]);
7935 delta.p[3] = fabs(delta.p[3]);
7936 dis.p[1] = mMax(delta.p[2], delta.p[3]);
7937
7938 // compute the dissipation function...
7939 constant = F0;
7940 for(MInt i = 0; i < nDim; i++) {
7941 constant = mMax(constant, ABS(dis.p[i]));
7942 }
7943
7944 constant *= m_sigmaSponge;
7945
7946 if(constant > epsilon) {
7947 m_cellsInsideSpongeLayer[m_noCellsInsideSpongeLayer] = cellId;
7948 m_noCellsInsideSpongeLayer++;
7949 a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = true;
7950 a_spongeFactor(cellId) = constant;
7951 }
7952 }
7953 }
7954 }
7955 else {
7956 for(MInt cellId = 0; cellId < noCells; cellId++) {
7957 a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = false;
7958 a_spongeFactor(cellId) = F0;
7959 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
7960 // compute the distance from the sponge layer radial (xy)
7961 // if the cell is not inside the sponge layer, the distance is set to zero
7962 radius = sqrt(POW2(a_coordinate(cellId, 0)) + POW2(a_coordinate(cellId, 1)));
7963 // compute the dissipation function...
7964 constant = mMax(F0, (radius - ABS(m_spongeCoord[0])) * m_spongeCoord[noDirs]);
7965 constant *= m_sigmaSponge;
7966
7967 if(constant > epsilon) {
7968 m_cellsInsideSpongeLayer[m_noCellsInsideSpongeLayer] = cellId;
7969 m_noCellsInsideSpongeLayer++;
7970 a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = true;
7971 a_spongeFactor(cellId) = constant;
7972 }
7973 }
7974 }
7975 }
7976 break;
7977 }
7978 default: {
7979 mTerm(1, AT_,
7980 "FvCartesianSolver::setCellProperties(): switch variable 'm_spongeLayerLayout' not matching any "
7981 "case");
7982 }
7983 }
7984 }
7985 }
7986}
7987
7988
7989// --------------------------------------------------------------------------------------
7990
7991
7992template <MInt nDim_, class SysEqn>
7994 TRACE();
7995 const MInt noCells = a_noCells();
7996 MBoolScratchSpace atBnd(noCells, AT_, "atBnd");
7997 MBoolScratchSpace nearBnd(noCells, AT_, "nearBnd");
7998 atBnd.fill(false);
7999 nearBnd.fill(false);
8000 // std::vector< std::vector<MInt> > structuredCells( maxLevel()-minLevel()+1 );
8001 // std::vector<MInt> nearBoundaryCells;
8002
8003 for(MInt level = minLevel(); level <= maxLevel(); level++) {
8004 // structuredCells[level-minLevel()].clear();
8005 }
8006 for(MInt level = minLevel(); level < maxRefinementLevel(); level++) {
8007 // centralDiffConst[level] = F1 / ( F2*c_cellLengthAtLevel(level) );
8008 }
8009 for(MInt cellId = 0; cellId < noCells; cellId++) {
8010 a_hasProperty(cellId, SolverCell::AtStructuredRegion) = false;
8011 }
8012 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
8013 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
8014 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
8015 atBnd(cellId) = true;
8016 MInt parentId = a_hasProperty(cellId, SolverCell::IsSplitChild) ? c_parentId(getAssociatedInternalCell(cellId))
8017 : c_parentId(cellId);
8018 while(parentId > -1) {
8019 atBnd(parentId) = true;
8020 parentId = c_parentId(parentId);
8021 }
8022 }
8023 for(MInt cellId = 0; cellId < noCells; cellId++) {
8024 if(a_bndryId(cellId) < -1) continue;
8025 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
8026 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
8027 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
8028 //---
8029 if(atBnd(cellId)) {
8030 // nearBoundaryCells.push_back( cellId );
8031 nearBnd(cellId) = true;
8032 continue;
8033 }
8034 MBool nearb = false;
8035 a_hasProperty(cellId, SolverCell::AtStructuredRegion) = true;
8036 for(MInt dir = 0; dir < m_noDirs; dir++) {
8037 if(!a_hasNeighbor(cellId, dir)) {
8038 a_hasProperty(cellId, SolverCell::AtStructuredRegion) = false;
8039 MInt parentId = c_parentId(cellId);
8040 while(parentId > -1) {
8041 if(a_hasNeighbor(parentId, dir)) {
8042 if(atBnd(c_neighborId(parentId, dir))) {
8043 nearb = true;
8044 }
8045 break;
8046 }
8047 parentId = c_parentId(parentId);
8048 }
8049 } else if(atBnd(c_neighborId(cellId, dir))) {
8050 a_hasProperty(cellId, SolverCell::AtStructuredRegion) = false;
8051 nearb = true;
8052 break;
8053 }
8054 }
8055 if(nearb) {
8056 // nearBoundaryCells.push_back( cellId );
8057 nearBnd(cellId) = true;
8058 continue;
8059 }
8060 if(a_hasProperty(cellId, SolverCell::AtStructuredRegion)) {
8061 // structuredCells[ a_level(cellId) - minLevel() ].push_back( cellId );
8062 } else {
8063 MInt parentId = c_parentId(cellId);
8064 if(parentId > -1) {
8065 if(!a_hasProperty(parentId, SolverCell::AtStructuredRegion)) {
8066 a_hasProperty(parentId, SolverCell::AtStructuredRegion) = true;
8067 for(MInt dir = 0; dir < m_noDirs; dir++) {
8068 if(!a_hasNeighbor(parentId, dir)) {
8069 a_hasProperty(parentId, SolverCell::AtStructuredRegion) = false;
8070 break;
8071 }
8072 }
8073 if(a_hasProperty(parentId, SolverCell::AtStructuredRegion)) {
8074 // structuredCells[ a_level(parentId) - minLevel() ].push_back( parentId );
8075 } else {
8076 mTerm(1, "strange grid configuration (1).");
8077 }
8078 }
8079 } else {
8080 cerr << c_globalId(cellId) << " " << a_hasProperty(cellId, Cell::IsHalo) << endl;
8081 mTerm(1, "strange grid configuration (2).");
8082 }
8083 }
8084 }
8085}
8086
8087
8088// this sets b_properties[SolverCell::IsFlux]
8089// see also writeListOfActiveFlowCells
8090template <MInt nDim_, class SysEqn>
8092 TRACE();
8093
8094 const MInt noCells = a_noCells();
8095 const MInt noDirs = 2 * nDim;
8096 const MInt noSurfaces = a_noSurfaces();
8097 //---end of initialization
8098
8099 // reset the property 10 (flux computation)
8100 for(MInt cellId = 0; cellId < noCells; cellId++) {
8101 a_hasProperty(cellId, SolverCell::IsDummy) = false;
8102 a_hasProperty(cellId, SolverCell::IsFlux) = false;
8103 }
8104
8105 // tag those cells which are needed for the surface flux computation
8106 // add two additional layers
8107 for(MInt s = 0; s < noSurfaces; s++) {
8108 ASSERT(a_surfaceNghbrCellId(s, 0) > -1 && a_surfaceNghbrCellId(s, 1) > -1, to_string(s));
8109 a_hasProperty(a_surfaceNghbrCellId(s, 0), SolverCell::IsFlux) = true;
8110 a_hasProperty(a_surfaceNghbrCellId(s, 1), SolverCell::IsFlux) = true;
8111 }
8112
8113 for(MInt addLayer = 0; addLayer < 2; addLayer++) {
8114 for(MInt cellId = 0; cellId < noCells; cellId++) {
8115 if(a_hasProperty(cellId, SolverCell::IsFlux) && !a_isBndryGhostCell(cellId)) {
8116 for(MInt dir = 0; dir < noDirs; dir++) {
8117 MInt gridcellId = cellId;
8118 if(a_hasProperty(cellId, SolverCell::IsSplitClone)) {
8119 gridcellId = m_splitChildToSplitCell.find(cellId)->second;
8120 }
8121 if(a_hasNeighbor(gridcellId, dir) > 0) {
8122 a_hasProperty(c_neighborId(gridcellId, dir), SolverCell::IsDummy) = true;
8123 }
8124 }
8125 }
8126 }
8127 // refresh
8128 for(MInt cellId = 0; cellId < noCells; cellId++) {
8129 if(a_hasProperty(cellId, SolverCell::IsDummy)) {
8130 a_hasProperty(cellId, SolverCell::IsFlux) = true;
8131 }
8132 }
8133 }
8134}
8135
8136
8143template <MInt nDim_, class SysEqn>
8145 TRACE();
8146 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8147 const MBool isGhost = a_isBndryGhostCell(cellId);
8148 const MInt boundaryId = a_bndryId(cellId);
8149 if((isGhost && boundaryId != -2) || (!isGhost && boundaryId == -2)) {
8150 cout << "ERROR: globalId: " << c_globalId(cellId) << " " << isGhost << " " << boundaryId << endl;
8151 mTerm(1, AT_, "ERROR in checkGhostCellIntegrity");
8152 }
8153 }
8154}
8155
8156//-------------------------------------------------------------------------------------
8157
8158template <MInt nDim_, class SysEqn>
8160 MFloat x[nDim];
8161 ASSERT(exId > -1 && exId < m_extractedCells->size() && node > -1 && node < IPOW2(nDim), "");
8162 MInt gridPointId = m_extractedCells->a[exId].m_pointIds[node];
8163 ASSERT(gridPointId > -1 && gridPointId < m_gridPoints->size(), "");
8164 for(MInt i = 0; i < nDim; i++) {
8165 x[i] = m_gridPoints->a[gridPointId].m_coordinates[i];
8166 }
8167 return m_geometry->pointIsInside2(x);
8168}
8169
8170
8180template <MInt nDim_, class SysEqn>
8182 TRACE();
8183
8184 // Open grid file
8185 using namespace maia::parallel_io;
8186 ParallelIo parallelIo(outputDir() + grid().gridInputFileName(), PIO_APPEND, mpiComm());
8187
8188 // Check if cut cell information is already in the grid file - if yes, inform the user
8189 // that modifying that data is not possible and return from the method.
8190 if(parallelIo.hasDataset("cutCellIds", 1)) {
8191 // m_log << "Cannot add cut cell information as it is already in the grid file." << endl;
8192 return;
8193 }
8194
8195 // Collect all necessary information for cut cell visualization
8196 MInt noBndryCells = 0;
8197 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
8198 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
8199 if(!a_isHalo(cellId)) {
8200 noBndryCells++;
8201 }
8202 }
8203
8204 // Save number of cut points for boundary cells
8205 MIntScratchSpace noCutPoints(noBndryCells, FUN_, "noCutPoints");
8206 MInt localNoCutPoints = 0;
8207 MInt bcnt = 0;
8208 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
8209 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
8210 if(a_isHalo(cellId)) continue;
8211 noCutPoints[bcnt] = m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints;
8212 localNoCutPoints += noCutPoints[bcnt];
8213 bcnt++;
8214 }
8215
8216 // Save cut edges and cut point coordinates
8217 MIntScratchSpace cutEdges(localNoCutPoints, FUN_, "cutEdges");
8218 MFloatScratchSpace cutCoordinates(localNoCutPoints, nDim, FUN_, "cutCoordinates");
8219 MInt ccId = 0;
8220 bcnt = 0;
8221 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
8222 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
8223 if(a_isHalo(cellId)) continue;
8224 // Create array to keep track of checked edges
8225 MInt edgeChecked[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
8226 for(MInt cutId = 0; cutId < m_bndryCells->a[bndryId].m_srfcs[0]->m_noCutPoints; cutId++) {
8227 MInt edge;
8228 edge = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutEdge[cutId];
8229
8230 // Skip if edge was already checked
8231 if(edgeChecked[edge]) {
8232 continue;
8233 }
8234
8235 cutEdges[ccId] = edge;
8236 edgeChecked[edge] = 1;
8237
8238 for(MInt dim = 0; dim < nDim; dim++) {
8239 cutCoordinates(ccId, dim) = m_bndryCells->a[bndryId].m_srfcs[0]->m_cutCoordinates[cutId][dim];
8240 }
8241 ccId++;
8242 }
8243 bcnt++;
8244 }
8245
8246
8247 // Save whether original cell vertices are inside or outside the domain
8248 // signStencil is needed for the calculation of the vertex coordinates
8249 const MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
8250 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
8251 // cellLengths holds the length of all cells depending on their refinement level
8252 vector<MFloat> cellLengths(maxRefinementLevel() + 1);
8253 for(vector<MFloat>::size_type i = 0; i < cellLengths.size(); i++) {
8254 cellLengths[i] = c_cellLengthAtLevel(i);
8255 }
8256 // Iterate over all cells, then all points to calculate and store whether the point is inside or not
8257 MIntScratchSpace pointInside(noBndryCells, IPOW2(nDim), FUN_, "pointInside");
8258 bcnt = 0;
8259 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
8260 const MInt cellId = m_bndryCells->a[bndryId].m_cellId;
8261 if(a_isHalo(cellId)) continue;
8262 for(MInt pointId = 0; pointId < IPOW2(nDim); pointId++) {
8263 // Here we loop over all directions to calculate the coordinate of the corner point,
8264 // then we check whether it is inside or not
8265 MFloat pointCoordinates[MAX_SPACE_DIMENSIONS];
8266 for(MInt dir = 0; dir < nDim; dir++) {
8267 const MFloat cellCenterCoord = a_coordinate(cellId, dir);
8268 const MFloat cellLength = cellLengths[a_level(cellId)];
8269 pointCoordinates[dir] = cellCenterCoord + signStencil[pointId][dir] * F1B2 * cellLength;
8270 }
8271 pointInside(bcnt, pointId) = m_geometry->pointIsInside2(pointCoordinates);
8272 }
8273 bcnt++;
8274 }
8275
8276 // Determine data offsets for cells, boundary cells, and cut points in the grid file
8277 ParallelIo::size_type cellOffset, bndryCellOffset, cutPointOffset;
8278 ParallelIo::size_type globalNoCells, globalNoBndryCells, globalNoCutPoints;
8279 parallelIo.calcOffset(noInternalCells(), &cellOffset, &globalNoCells, mpiComm());
8280 parallelIo.calcOffset(noBndryCells, &bndryCellOffset, &globalNoBndryCells, mpiComm());
8281 parallelIo.calcOffset(localNoCutPoints, &cutPointOffset, &globalNoCutPoints, mpiComm());
8282
8283 // Add new variables to grid file
8284 parallelIo.defineArray(PIO_INT, "cutCellIds", globalNoCells);
8285 parallelIo.defineArray(PIO_INT, "noCutPoints", globalNoBndryCells);
8286 parallelIo.defineArray(PIO_INT, "cutEdges", globalNoCutPoints);
8287 parallelIo.defineArray(PIO_FLOAT, "cutCoordinates", globalNoCutPoints * nDim);
8288 parallelIo.defineArray(PIO_INT, "pointIsInside", globalNoBndryCells * IPOW2(nDim));
8289
8290 // Write data to file
8291 // This field is used to show whether a cell has cut cell information or not
8292 parallelIo.setOffset(noInternalCells(), cellOffset);
8293 parallelIo.writeArray(&a_bndryId(0), "cutCellIds");
8294
8295 parallelIo.setOffset(noBndryCells, bndryCellOffset);
8296 parallelIo.writeArray(noCutPoints.getPointer(), "noCutPoints");
8297
8298 parallelIo.setOffset(localNoCutPoints, cutPointOffset);
8299 parallelIo.writeArray(cutEdges.getPointer(), "cutEdges");
8300
8301 parallelIo.setOffset(localNoCutPoints * nDim, cutPointOffset * nDim);
8302 parallelIo.writeArray(cutCoordinates.getPointer(), "cutCoordinates");
8303
8304 parallelIo.setOffset(noBndryCells * IPOW2(nDim), bndryCellOffset * IPOW2(nDim));
8305 parallelIo.writeArray(pointInside.getPointer(), "pointIsInside");
8306}
8307
8308
8309template <MInt nDim_, class SysEqn>
8311 TRACE();
8312
8313 MInt offset = a_noCells();
8314 for(MInt c = 0; c < noInternalCells(); c++) {
8315 vorticity[c] = F1B2 * (a_slope(c, PV->W, 1) - a_slope(c, PV->V, 2));
8316 vorticity[offset + c] = F1B2 * (a_slope(c, PV->U, 2) - a_slope(c, PV->W, 0));
8317 vorticity[offset * 2 + c] = F1B2 * (a_slope(c, PV->V, 0) - a_slope(c, PV->U, 1));
8318 }
8319}
8320
8321template <MInt nDim_, class SysEqn>
8323 TRACE();
8324
8325 for(MInt c = 0; c < noInternalCells(); c++) {
8326 vorticity[c] = F1B2 * (a_slope(c, PV->V, 0) - a_slope(c, PV->U, 1));
8327 }
8328}
8329
8330
8340template <MInt nDim_, class SysEqn>
8342 TRACE();
8343
8344 for(MInt c = 0; c < noInternalCells(); c++) {
8345 vorticity[3 * c + 0] = F1B2 * (a_slope(c, PV->W, 1) - a_slope(c, PV->V, 2));
8346 vorticity[3 * c + 1] = F1B2 * (a_slope(c, PV->U, 2) - a_slope(c, PV->W, 0));
8347 vorticity[3 * c + 2] = F1B2 * (a_slope(c, PV->V, 0) - a_slope(c, PV->U, 1));
8348 }
8349}
8350
8351
8352template <MInt nDim_, class SysEqn>
8354 TRACE();
8355 // Q - criterion
8356 MFloat normS, normO;
8357 MInt offsetS = nDim * nDim;
8358 MInt tmpSize = offsetS + offsetS;
8359 MFloatScratchSpace grad(offsetS, AT_, "grad");
8360 MFloatScratchSpace q(tmpSize, AT_, "q");
8361
8362 for(MInt c = 0; c < noInternalCells(); c++) {
8363 // compute the velocity vector gradient
8364 for(MInt i = 0; i < nDim; i++) {
8365 for(MInt j = 0; j < nDim; j++) {
8366 grad.p[i * nDim + j] = a_slope(c, PV->VV[i], j);
8367 }
8368 }
8369 // compute the strain rate and vorticity tensor
8370 for(MInt i = 0; i < nDim; i++) {
8371 for(MInt j = 0; j < nDim; j++) {
8372 q.p[j + i * nDim] = F1B2 * (grad.p[i * nDim + j] + grad.p[j * nDim + i]);
8373 q.p[j + i * nDim + offsetS] = F1B2 * (grad.p[i * nDim + j] - grad.p[j * nDim + i]);
8374 }
8375 }
8376 // compute the value of Q
8377 normS = F0;
8378 normO = F0;
8379 for(MInt i = 0; i < nDim; i++) {
8380 for(MInt j = 0; j < nDim; j++) {
8381 normS += POW2(q.p[i * nDim + j]);
8382 normO += POW2(q.p[i * nDim + offsetS + j]);
8383 }
8384 }
8385 qCriterion.p[c] = F1B2 * (normO - normS);
8386 }
8387}
8388
8389// ---------------------------------------------------------------------------------------------
8390
8391
8402template <MInt nDim_, class SysEqn>
8404 const MChar* fileName, MInt noTotalCells, MLong noInternalCellIds, MFloatScratchSpace& dbVariables,
8405 vector<MString>& dbVariablesName, MInt noDbVars, MIntScratchSpace& idVariables, vector<MString>& idVariablesName,
8406 MInt noIdVars, MFloatScratchSpace& dbParameters, vector<MString>& dbParametersName, MIntScratchSpace& idParameters,
8407 vector<MString>& idParametersName, const MInt* recalcIds) {
8408 TRACE();
8409
8410 IF_CONSTEXPR(nDim != 2 && nDim != 3) {
8411 stringstream errorMessage;
8412 errorMessage << " In global function saveGridFlowVarsPar: wrong number of dimensions !" << endl;
8413 mTerm(1, AT_, errorMessage.str());
8414 return;
8415 }
8416
8417 // File creation.
8418 MString tmpNcVariablesName;
8419 noDbVars = dbVariablesName.size();
8420 noIdVars = idVariablesName.size();
8421 MInt noIdPars = idParametersName.size();
8422 MInt noDbPars = dbParametersName.size();
8423 vector<MString> ncVariablesName;
8424 MFloat* tmpDbVariables;
8425 MInt* tmpIdVariables;
8426
8427 using namespace parallel_io;
8428 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
8429
8430 // Creating file header
8431 MLong num = -1;
8432 auto longNoInternalCells = (MLong)noInternalCellIds;
8433 MPI_Allreduce(&longNoInternalCells, &num, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "longNoInternalCells", "num");
8434 parallelIo.setAttribute(num, "noCells");
8435
8436 parallelIo.setAttribute(solverId(), "solverId");
8437
8438
8439 for(MInt j = 0; j < noDbVars; j++) {
8440 tmpNcVariablesName = "variables" + to_string(j);
8441 ncVariablesName.push_back(tmpNcVariablesName);
8442
8443 parallelIo.defineArray(PIO_FLOAT, ncVariablesName[j], num);
8444 m_log << dbVariablesName[j].c_str() << endl;
8445 parallelIo.setAttribute(dbVariablesName[j], "name", ncVariablesName[j]);
8446 }
8447
8448 for(MInt j = 0; j < noIdVars; j++) {
8449 MInt k = j + noDbVars;
8450 tmpNcVariablesName = "variables" + to_string(k);
8451 ncVariablesName.push_back(tmpNcVariablesName);
8452
8453 parallelIo.defineArray(PIO_INT, ncVariablesName[k], num);
8454 parallelIo.setAttribute(idVariablesName[j], "name", ncVariablesName[k]);
8455 }
8456
8457 MString XString = "variables" + to_string(noDbVars + noIdVars + (MInt)isDetChem<SysEqn> + 1);
8458 MString YString = "variables" + to_string(noDbVars + noIdVars + (MInt)isDetChem<SysEqn> + 2);
8459
8460 IF_CONSTEXPR(isDetChem<SysEqn>) {
8461 parallelIo.defineArray(PIO_FLOAT, XString, num);
8462 parallelIo.defineArray(PIO_FLOAT, YString, num);
8463 parallelIo.setAttribute("XCoord", "name", XString);
8464 parallelIo.setAttribute("YCoord", "name", YString);
8465 }
8466
8467 for(MInt j = 0; j < noIdPars; j++) {
8468 // solution parameters
8469 parallelIo.setAttribute(idParameters.p[j], idParametersName[j]);
8470 }
8471
8472 for(MInt j = 0; j < noDbPars; j++) {
8473 // solution parameters
8474 parallelIo.setAttribute(dbParameters.p[j], dbParametersName[j]);
8475 }
8476 parallelIo.setAttribute(m_currentGridFileName, "gridFile");
8477
8478 if(m_initialCondition == 16) {
8479 parallelIo.setAttributes(&m_Re, "Re", 1);
8480 parallelIo.setAttributes(&sysEqn().m_Re0, "Re0", 1);
8481 parallelIo.setAttributes(&m_randomDeviceSeed, "randomDeviceSeed", 1);
8482 }
8483
8484 ParallelIo::size_type start = 0;
8485 ParallelIo::size_type count = 1;
8486
8487 // Update start and count for parallel writing
8488 MPI_Exscan(&noInternalCellIds, &start, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "noInternalCells", "start");
8489 count = noInternalCellIds;
8490 parallelIo.setOffset(count, start);
8491
8492 for(MInt j = 0; j < noDbVars; j++) {
8493 tmpDbVariables = &(dbVariables.p[j * noTotalCells]);
8494
8495 if(m_recalcIds != nullptr) {
8496 MFloatScratchSpace tmpDouble(count, AT_, "tmpDouble");
8497 for(MInt l = 0; l < count; ++l) {
8498 tmpDouble[l] = tmpDbVariables[recalcIds[l]];
8499 }
8500 parallelIo.writeArray(tmpDouble.begin(), ncVariablesName[j]);
8501 } else {
8502 parallelIo.writeArray(tmpDbVariables, ncVariablesName[j]);
8503 }
8504 }
8505
8506 IF_CONSTEXPR(isDetChem<SysEqn>) {
8507 MFloatScratchSpace tmpX(a_noCells(), AT_, "tmpX");
8508 MFloatScratchSpace tmpY(a_noCells(), AT_, "tmpY");
8509 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8510 tmpX[cellId] = a_coordinate(cellId, 0);
8511 }
8512 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8513 tmpY[cellId] = a_coordinate(cellId, 1);
8514 }
8515 parallelIo.writeArray(&tmpX[0], XString);
8516 parallelIo.writeArray(&tmpY[0], YString);
8517 }
8518
8519 for(MInt j = 0; j < noIdVars; j++) {
8520 tmpIdVariables = &(idVariables.p[j * noTotalCells]);
8521 if(m_recalcIds != nullptr) {
8522 MIntScratchSpace tmpInt(count, AT_, "tmpInt");
8523 for(MInt l = 0; l < count; ++l) {
8524 tmpInt[l] = tmpIdVariables[recalcIds[l]];
8525 }
8526 parallelIo.writeArray(tmpInt.begin(), ncVariablesName[j + noDbVars]);
8527 } else {
8528 parallelIo.writeArray(tmpIdVariables, ncVariablesName[j + noDbVars]);
8529 }
8530 }
8531
8533}
8534
8535
8537template <MInt nDim_, class SysEqn>
8539 TRACE();
8540 using namespace maia::parallel_io;
8541
8542 if(!m_useNonSpecifiedRestartFile) {
8543 mTerm(1, "determineRestartTimeStep should only be used with useNonSpecifiedRestartFile enabled!");
8544 }
8545
8546 std::stringstream varFileName;
8547 if(!m_multipleFvSolver) {
8548 varFileName << restartDir() << "restartVariables" << ParallelIo::fileExt();
8549 } else {
8550 varFileName << restartDir() << "restartVariables" << m_solverId << "_" << ParallelIo::fileExt();
8551 }
8552 ParallelIo parallelIo(varFileName.str(), PIO_READ, MPI_COMM_SELF);
8553 MInt timeStep = -1;
8554 parallelIo.getAttribute(&timeStep, "globalTimeStep");
8555 return timeStep;
8556}
8557
8558// -----------------------------------------------------------------------------------------------------------
8559
8564template <MInt nDim_, class SysEqn>
8565void FvCartesianSolverXD<nDim_, SysEqn>::loadRestartTime(const MChar* fileName, MInt& globalTimeStepInput,
8566 MFloat& timeInput, MFloat& physicalTimeInput) {
8567 TRACE();
8568
8569 ParallelIo parallelIo(fileName, maia::parallel_io::PIO_READ, MPI_COMM_SELF);
8570
8571 CartesianNetcdf CN;
8572 // ----------------------------------------------------------
8573
8574 // --------------------------------------------------------------
8575 // Read solution parameters
8576 // number of samples used for averaging
8577
8578 // global time step
8579 parallelIo.getAttribute(&globalTimeStepInput, CN.globalTimeStep);
8580 // solution time
8581 parallelIo.getAttribute(&timeInput, CN.time);
8582 // physical time
8583 parallelIo.getAttribute(&physicalTimeInput, CN.physicalTime);
8584}
8585
8586
8587template <MInt nDim_, class SysEqn>
8589 TRACE();
8590
8591 cerr << "**********************************************************" << endl;
8592 cerr << "Writing cell data for cell " << c << " at time step " << globalTimeStep << ", " << m_RKStep << "> at level "
8593 << a_level(c) << endl;
8594 cerr << "Primitive cell variables: " << endl;
8595 for(MInt v = 0; v < PV->noVariables; v++) {
8596 cerr << a_pvariable(c, v) << " ";
8597 }
8598 cerr << endl;
8599 cerr << "Conservative cell variables: " << endl;
8600 for(MInt v = 0; v < CV->noVariables; v++) {
8601 cerr << a_variable(c, v) << " ";
8602 }
8603 cerr << "Cell slopes: " << endl;
8604 for(MInt v = 0; v < PV->noVariables; v++) {
8605 for(MInt i = 0; i < 3; i++) {
8606 cerr << a_slope(c, v, i) << " ";
8607 }
8608 cerr << endl;
8609 }
8610 cerr << "**********************************************************" << endl;
8611}
8612
8614template <MInt nDim_, class SysEqn>
8616 TRACE();
8617
8618 std::fill(m_timers.begin(), m_timers.end(), -1);
8619
8620 // Create timer group & timer for solver, and start the timer
8621 NEW_TIMER_GROUP_NOCREATE(m_timerGroup, "FvCartesianSolver (solverId = " + to_string(m_solverId) + ")");
8622 NEW_TIMER_NOCREATE(m_timers[Timers::SolverType], "total object lifetime", m_timerGroup);
8623 RECORD_TIMER_START(m_timers[Timers::SolverType]);
8624
8625 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::TimeInt], "Time-integration", m_timers[Timers::SolverType]);
8626
8627 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Rhs], "rhs", m_timers[Timers::TimeInt]);
8628 // RHS subtimers
8629 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Muscl], "MUSCL", m_timers[Timers::Rhs]);
8630 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Ausm], "AUSM", m_timers[Timers::Rhs]);
8631 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ViscFlux], "Viscous flux", m_timers[Timers::Rhs]);
8632 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::DistFlux], "Distribute flux", m_timers[Timers::Rhs]);
8633 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::RhsMisc], "Misc", m_timers[Timers::Rhs]);
8634 if(m_useSandpaperTrip) {
8635 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SandpaperTrip], "SandpaperTrip", m_timers[Timers::Rhs]);
8636 }
8637 if(m_wmLES) {
8638 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::WMExchange], "WMExchange", m_timers[Timers::Rhs]);
8639 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::WMSurfaceLoop], "WMSurfaceLoop", m_timers[Timers::Rhs]);
8640 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::WMFluxCorrection], "WMFluxCorrection", m_timers[Timers::Rhs]);
8641 }
8642 IF_CONSTEXPR(isDetChem<SysEqn>) {
8643 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfaceCoefficients], "Surface Coefficients", m_timers[Timers::Rhs]);
8644 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfaceMeanMolarWeight], "Surface Mean Molar Weight",
8645 m_timers[Timers::SurfaceCoefficients]);
8646 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfaceTransportCoefficients], "Surface Transport Coefficients",
8647 m_timers[Timers::SurfaceCoefficients]);
8648 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CellCenterCoefficients], "Cell Center Coefficients", m_timers[Timers::Rhs]);
8649 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SpeciesReactionRates], "Species Reaction Rates", m_timers[Timers::Rhs]);
8650 }
8651 // MUSCL subtimers
8652 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MusclReconst], "LSReconstructCellCenter", m_timers[Timers::Muscl]);
8653 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MusclCopy], "copySlopesToSmallCells", m_timers[Timers::Muscl]);
8654 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MusclGhostSlopes], "updateGhostCellSlopesInviscid", m_timers[Timers::Muscl]);
8655 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MusclCutSlopes], "updateCutOffSlopesInviscid", m_timers[Timers::Muscl]);
8656 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MusclReconstSrfc], "reconstructSurfaceData", m_timers[Timers::Muscl]);
8657
8658 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ReconstSrfcCompValues], "computeSurfaceValues",
8659 m_timers[Timers::MusclReconstSrfc]);
8660 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ReconstSrfcCorrVars], "correctSurfaceVariables",
8661 m_timers[Timers::MusclReconstSrfc]);
8662 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ReconstSrfcUpdateGhost], "updateGhost", m_timers[Timers::MusclReconstSrfc]);
8663 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ReconstSrfcUpdateCutOff], "updateCutOff", m_timers[Timers::MusclReconstSrfc]);
8664
8665 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::RhsBnd], "rhsBnd", m_timers[Timers::TimeInt]);
8666
8667 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Lhs], "lhs", m_timers[Timers::TimeInt]);
8668
8669 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LhsBnd], "lhsBnd", m_timers[Timers::TimeInt]);
8670
8671 // LHS-BND subtimers
8672 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SmallCellCorr], "small cell correction", m_timers[Timers::LhsBnd]);
8673 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ComputePV], "compute PV", m_timers[Timers::LhsBnd]);
8674 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Exchange], "exchange", m_timers[Timers::LhsBnd]);
8675 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CutOff], "cut off", m_timers[Timers::LhsBnd]);
8676 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::BndryCnd], "boundary conditions", m_timers[Timers::LhsBnd]);
8677
8678 // Small cell correction subtimers
8679 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SCCorrInit], "init", m_timers[Timers::SmallCellCorr]);
8680 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SCCorrExchange1], "first exchange", m_timers[Timers::SmallCellCorr]);
8681 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SCCorrExchange1Wait], "waiting/blocking MPI",
8682 m_timers[Timers::SCCorrExchange1]);
8683 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SCCorrInterp], "interpolation", m_timers[Timers::SmallCellCorr]);
8684 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SCCorrRedist], "redistribution", m_timers[Timers::SmallCellCorr]);
8685 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SCCorrExchange2], "second exchange", m_timers[Timers::SmallCellCorr]);
8686 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SCCorrExchange2Wait], "waiting/blocking MPI",
8687 m_timers[Timers::SCCorrExchange2]);
8688
8689 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Residual], "Residual", m_timers[Timers::TimeInt]);
8690 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ResidualMpi], "MPI", m_timers[Timers::Residual]);
8691
8692 // prepare solver subtimers
8693 if(m_levelSetMb) {
8694 // preTimeStep
8695 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::PreTime], "PreTimeStep", m_timers[Timers::SolverType]);
8696 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ReinitSolu], "ReinitSolutionStep", m_timers[Timers::PreTime]);
8697 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::BndryMb], "generateBndryCells", m_timers[Timers::ReinitSolu]);
8698 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::NearBndry], "initNearBndryExc", m_timers[Timers::ReinitSolu]);
8699 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitSmallCorr], "initSmallCellCor", m_timers[Timers::ReinitSolu]);
8700 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::GhostCells], "ghostCells", m_timers[Timers::ReinitSolu]);
8701 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::PostTime], "PostTimeStep", m_timers[Timers::SolverType]);
8702 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::PostSolu], "PostSolutionStep", m_timers[Timers::PostTime]);
8703 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ResidualMb], "Residual-MB", m_timers[Timers::PostSolu]);
8704 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SurfaceForces], "SurfaceForces", m_timers[Timers::PostSolu]);
8705 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LevelSetCorr], "LevelSetCorr", m_timers[Timers::PostSolu]);
8706 }
8707
8708 // TODO labels:FV,TIMERS Create accumulated timers that monitor selected subsystems
8709 /* NEW_SUB_TIMER_NOCREATE( */
8710 /* m_timers[Timers::Accumulated], "selected accumulated timers", m_timers[Timers::SolverType]); */
8711 /* NEW_SUB_TIMER_NOCREATE(m_timers[Timers::IO], "IO", */
8712 /* m_timers[Timers::Accumulated]); */
8713 /* NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MPI], "MPI", */
8714 /* m_timers[Timers::Accumulated]); */
8715
8716
8717 // Communication
8718 NEW_TIMER_GROUP_NOCREATE(m_tgfv, "FV Exchange");
8719 NEW_TIMER_NOCREATE(m_tcomm, "Communication", m_tgfv);
8720
8721 NEW_SUB_TIMER_NOCREATE(m_texchange, "exchange", m_tcomm);
8722
8723 NEW_SUB_TIMER_NOCREATE(m_tgatherAndSend, "gather and send", m_texchange);
8724 NEW_SUB_TIMER_NOCREATE(m_tgather, "gather", m_tgatherAndSend);
8725 NEW_SUB_TIMER_NOCREATE(m_tsend, "send", m_tgatherAndSend);
8726 NEW_SUB_TIMER_NOCREATE(m_tgatherAndSendWait, "wait", m_tgatherAndSend);
8727 NEW_SUB_TIMER_NOCREATE(m_treceive, "receive", m_texchange);
8728 NEW_SUB_TIMER_NOCREATE(m_tscatter, "scatter", m_texchange);
8729 NEW_SUB_TIMER_NOCREATE(m_tscatterWaitSome, "wait some", m_tscatter);
8730 NEW_SUB_TIMER_NOCREATE(m_treceiving, "receiving", m_treceive);
8731 NEW_SUB_TIMER_NOCREATE(m_treceiveWait, "waiting", m_treceive);
8732
8733 NEW_SUB_TIMER_NOCREATE(m_texchangeDt, "exchange time-step", m_tcomm);
8734}
8735
8738template <MInt nDim_, class SysEqn>
8740 TRACE();
8741
8742 setRungeKuttaProperties();
8743 m_RKStep = 0;
8744}
8745
8746
8757template <MInt nDim_, class SysEqn>
8759 m_loadSampleVariables = true;
8760 m_restartTimeStep = timeStep;
8761 loadRestartFile();
8762 m_loadSampleVariables = false;
8763}
8764
8776template <MInt nDim_, class SysEqn>
8778 vars = &a_pvariable(cellId, 0);
8779}
8780
8781template <MInt nDim_, class SysEqn>
8782void FvCartesianSolverXD<nDim_, SysEqn>::getSampleVariables(const MInt cellId, std::vector<MFloat>& vars) {
8783 const MInt noVars = vars.size();
8784 ASSERT(noVars <= noVariables(), "noVars > noVariables()");
8785 for(MInt varId = 0; varId < noVars; varId++) {
8786 vars[varId] = a_pvariable(cellId, varId);
8787 }
8788}
8789
8791template <MInt nDim_, class SysEqn>
8793 varNames.clear();
8794 for(MInt i = 0; i < PV->noVariables; i++) {
8795 varNames.push_back(PV->varNames[i]);
8796 }
8797}
8798
8806template <MInt nDim_, class SysEqn>
8808 vars = &a_slope(cellId, 0, 0);
8809}
8810
8811template <MInt nDim_, class SysEqn>
8813 std::memcpy(&vars[0], &a_slope(cellId, 0, 0), sizeof(MFloat) * (nDim * PV->noVariables));
8814 return true; // = implemented for this solver
8815}
8816
8825template <MInt nDim_, class SysEqn>
8827 IF_CONSTEXPR(isDetChem<SysEqn>) {
8828 for(MInt cellId = 0; cellId < a_noCells(); ++cellId) {
8829 const MFloat dampeningFactor = m_heatReleaseDamp ? m_dampFactor[cellId] : F1;
8830 m_heatRelease[cellId] = F0;
8831 for(MInt s = 0; s < m_noSpecies; ++s) {
8832 m_heatRelease[cellId] -= dampeningFactor * a_speciesReactionRate(cellId, s) * m_standardHeatFormation[s];
8833 }
8834 }
8835 }
8836 else {
8837 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
8838 m_heatRelease[cellId] = a_reactionRate(cellId, 0) * a_cellVolume(cellId) * (m_burntUnburntTemperatureRatio - F1)
8839 * (F1 / (m_gamma - F1));
8840 }
8841 }
8842}
8843
8852template <MInt nDim_, class SysEqn>
8854 heatRelease = m_heatRelease;
8855}
8856
8866template <MInt nDim_, class SysEqn>
8868 MInt bndryId = a_bndryId(cellId);
8869 if(bndryId > -1) {
8870 if(m_bndryCells->a[bndryId].m_noSrfcs > 1) {
8871 mTerm(1, AT_, "lineOutput not implemented for split cells or such");
8872 }
8873 // temperature gradient
8874 MFloat drhodn = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_normalDeriv[PV->RHO];
8875 MFloat rhoW = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_primVars[PV->RHO];
8876 MFloat pW = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_primVars[PV->P];
8877 return (-m_gamma * pW * drhodn / pow(rhoW, F2));
8878 }
8879 return std::numeric_limits<MFloat>::max();
8880}
8881
8890template <MInt nDim_, class SysEqn>
8892 return m_time;
8893}
8894
8906template <MInt nDim_, class SysEqn>
8908 TRACE();
8909
8910 IF_CONSTEXPR(nDim == 3) { computeVorticity3D(vorticity); }
8911 else IF_CONSTEXPR(nDim == 2) {
8912 computeVorticity2D(vorticity);
8913 }
8914}
8915
8916
8919template <MInt nDim_, class SysEqn>
8921 TRACE();
8922
8923 IF_CONSTEXPR(!hasE<SysEqn>)
8924 mTerm(1, AT_, "Not compatible with SysEqn without RHO_E!");
8925
8926
8927 for(MInt c = 0; c < noInternalCells(); c++) {
8928 const MFloat rho = a_oldVariable(c, CV->RHO);
8929 const MFloat rhoE = a_oldVariable(c, CV->RHO_E);
8930 IF_CONSTEXPR(nDim == 2) {
8931 p[c] =
8932 sysEqn().pressure(rho, POW2(a_oldVariable(c, CV->RHO_VV[0])) + POW2(a_oldVariable(c, CV->RHO_VV[1])), rhoE);
8933 }
8934 IF_CONSTEXPR(nDim == 3) {
8935 p[c] = sysEqn().pressure(rho,
8936 POW2(a_oldVariable(c, CV->RHO_VV[0])) + POW2(a_oldVariable(c, CV->RHO_VV[1]))
8937 + POW2(a_oldVariable(c, CV->RHO_VV[2])),
8938 rhoE);
8939 }
8940 }
8941}
8942
8943
8955template <MInt nDim_, class SysEqn>
8957 TRACE();
8958
8959 IF_CONSTEXPR(nDim == 3) { computeVorticity3DT(vorticity); }
8960 else IF_CONSTEXPR(nDim == 2) {
8961 computeVorticity2D(vorticity);
8962 }
8963}
8964
8965
8966template <MInt nDim_, class SysEqn>
8968 ASSERT(m_vorticity != nullptr, "Vorticity not initialized");
8969 return m_vorticity[cellId][dir];
8970}
8971
8980template <MInt nDim_, class SysEqn>
8981void FvCartesianSolverXD<nDim_, SysEqn>::getDimensionalizationParams(vector<pair<MFloat, MString>>& dimParams) const {
8982 TRACE();
8983
8984 dimParams.clear();
8985 dimParams.push_back(make_pair(m_Re, "Re"));
8986 dimParams.push_back(make_pair(m_Ma, "Ma"));
8987 dimParams.push_back(make_pair(sysEqn().gamma_Ref(), "gamma"));
8988 dimParams.push_back(make_pair(m_gasConstant, "R"));
8989 dimParams.push_back(make_pair(m_referenceTemperature, "T_ref"));
8990}
8991
8992
8993// --------------------------------------------------------------------------------------
8994
9017template <MInt nDim_, class SysEqn>
9020 MFloatScratchSpace& weights, const MInt recDim,
9021 const MInt weightMode, const MInt fallBackMode,
9022 const std::array<MBool, nDim> dirs,
9023 const MBool relocateCenter) {
9024 const MBool allDirs = std::all_of(dirs.begin(), dirs.end(), [](const MBool _) { return _ == false; });
9025 const MInt noDirs = std::accumulate(dirs.begin(), dirs.end(), 0);
9026 MInt currentSlopeDir = -1;
9027 if(noDirs == 1) {
9028 for(MInt d = 0; d < nDim; ++d) {
9029 if(dirs[d]) {
9030 currentSlopeDir = d;
9031 break;
9032 }
9033 }
9034 }
9035 ASSERT(a_hasProperty(cellId, SolverCell::IsSplitChild) || a_hasProperty(cellId, SolverCell::IsSplitClone)
9036 || c_isLeafCell(cellId),
9037 "");
9038 ASSERT(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel), "");
9039 ASSERT(a_hasProperty(cellId, SolverCell::IsFlux), "");
9040 ASSERT(!a_hasProperty(cellId, SolverCell::IsNotGradient), "");
9041 ASSERT(!a_isBndryGhostCell(cellId), "");
9042 const MInt noNghbrIds = a_noReconstructionNeighbors(cellId);
9043 if(noNghbrIds == 0) {
9044 return F0;
9045 }
9046 ASSERT(tmpA.size0() >= noNghbrIds && tmpA.size1() >= recDim, "");
9047 ASSERT(tmpC.size0() >= recDim && tmpC.size1() >= noNghbrIds, "");
9048 ASSERT(weights.size0() >= noNghbrIds, "");
9049 ASSERT(noNghbrIds <= m_cells.noRecNghbrs(), "");
9050
9051 const MInt rootCell = (a_hasProperty(cellId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(cellId) : cellId;
9052 const MFloat cellLength = c_cellLengthAtCell(cellId);
9053
9054 ASSERT(rootCell > -1 && rootCell < a_noCells(), "");
9055
9056 //
9057 if((weightMode == 3 || weightMode == 4) && allDirs) {
9058 std::array<MBool, nDim> dirsJmp = {};
9059 for(MInt d = 0; d < nDim; ++d) {
9060 const MBool coarseNghbr =
9061 m_cells.nghbrInterface(cellId, 2 * d) == 3 || m_cells.nghbrInterface(cellId, 2 * d + 1) == 3;
9062 const MBool fineNghbr =
9063 m_cells.nghbrInterface(cellId, 2 * d) == 2 || m_cells.nghbrInterface(cellId, 2 * d + 1) == 2;
9064 if(coarseNghbr || fineNghbr) {
9065 dirsJmp[d] = true;
9066 } else {
9067 dirsJmp[d] = false;
9068 }
9069 }
9070
9071 //
9072 MBool hasBndryInStencil = false;
9073 for(MInt n = 0; n < noNghbrIds; n++) {
9074 if(a_isBndryCell(a_reconstructionNeighborId(cellId, n))) {
9075 hasBndryInStencil = true;
9076 break;
9077 }
9078 }
9079
9080 // Bndry cells are by now treated as before, so one LS-system is solved for slopes in all directions
9081 if(a_isBndryCell(cellId) || a_isBndryGhostCell(cellId) || hasBndryInStencil) {
9082 std::fill_n(&dirsJmp[0], nDim, false);
9083 }
9084
9085 // Determine provisional slopes to correct cell center of bndry cells
9086 if(weightMode == 4 && m_relocateCenter) {
9087 if(hasBndryInStencil && !a_isBndryCell(cellId)) {
9088 std::array<MBool, nDim> dir;
9089 std::fill_n(&dir[0], nDim, true);
9090 computeRecConstSVD(cellId, offset, tmpA, tmpC, weights, recDim, weightMode, fallBackMode, dir);
9091 }
9092 }
9093
9094 MFloat condNumMax = std::numeric_limits<MFloat>::lowest();
9095 std::array<MBool, nDim> dir = dirsJmp;
9096 for(auto& d : dir) {
9097 d = !d;
9098 }
9099 if(std::any_of(dir.begin(), dir.end(), [](MBool _) { return _ == true; })) {
9100 auto condNum = computeRecConstSVD(cellId, offset, tmpA, tmpC, weights, recDim, weightMode, fallBackMode, dir,
9101 !a_isBndryCell(cellId) && m_relocateCenter);
9102 condNumMax = mMax(condNum, condNumMax);
9103 }
9104
9105 if(weightMode == 3) {
9106 if(std::any_of(dirsJmp.begin(), dirsJmp.end(), [](MBool _) { return _ == true; })) {
9107 auto condNum =
9108 computeRecConstSVD(cellId, offset, tmpA, tmpC, weights, recDim, weightMode, fallBackMode, dirsJmp);
9109 condNumMax = mMax(condNum, condNumMax);
9110 }
9111 }
9112 if(weightMode == 4) { // all jmp-directions are treated seperately according to method-of-lines principle
9113 for(MInt d = 0; d < nDim; ++d) {
9114 if(dirsJmp[d]) {
9115 std::array<MBool, nDim> dirsJmp_ = {};
9116 dirsJmp_[d] = true;
9117 auto condNum = computeRecConstSVD(cellId, offset, tmpA, tmpC, weights, recDim, weightMode, fallBackMode,
9118 dirsJmp_, !a_isBndryCell(cellId) && m_relocateCenter);
9119 condNumMax = mMax(condNum, condNumMax);
9120 }
9121 }
9122 }
9123
9124 return condNumMax;
9125 }
9126
9127 // Lambda fnct for weightMode == 3 & 4
9128 constexpr MFloat EPS = 1e-10;
9129 // Returns the direction of the nghbr, if nghbrId is a direct nghbr; returns -1 if nghbrId is the
9130 // ghost cell of cellId; return -2 if nghbrId does not share a common surface.
9131 auto isDirectNghbr = [=](const MInt nghbrId) {
9132 if(a_isBndryCell(cellId) && a_isBndryGhostCell(nghbrId)) {
9133 return -1;
9134 }
9135 for(MInt d = 0; d < nDim; ++d) {
9136 if(!dirs[d]) {
9137 continue;
9138 }
9139 for(MInt side = 0; side < 2; ++side) {
9140 const MInt orientation = 2 * d + side;
9141 if(a_level(nghbrId) == a_level(cellId)) {
9142 if(checkNeighborActive(cellId, orientation) && a_hasNeighbor(cellId, orientation)
9143 && c_neighborId(cellId, orientation) == nghbrId) {
9144 return orientation;
9145 }
9146 } else if(a_level(nghbrId) < a_level(cellId)) {
9147 if(c_neighborId(c_parentId(cellId), orientation) == nghbrId) {
9148 return orientation;
9149 }
9150 } else if(a_level(nghbrId) > a_level(cellId)) {
9151 if(checkNeighborActive(cellId, orientation) && a_hasNeighbor(cellId, orientation)) {
9152 const MInt nghbrParentId = c_neighborId(cellId, orientation);
9153 for(MInt child = 0; child < IPOW2(nDim); child++) {
9154 if(c_childId(nghbrParentId, child) == nghbrId) {
9155 if(childCodePro[orientation] & 1 << child) {
9156 return orientation;
9157 }
9158 }
9159 }
9160 }
9161 }
9162 }
9163 }
9164 return -2;
9165 };
9166
9167 // initialise weights
9168 weights.fill(F0);
9169
9170 // a) set direct neighbors for weightMode 1
9171 set<MInt> nextNghbrs;
9172 nextNghbrs.clear();
9173 if(weightMode == 1) {
9174 for(MInt dir = 0; dir < m_noDirs; dir++) {
9175 if(checkNeighborActive(rootCell, dir) && a_hasNeighbor(rootCell, dir) > 0) {
9176 const MInt nghbrId = c_neighborId(rootCell, dir);
9177 if(a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) {
9178 nextNghbrs.insert(nghbrId);
9179 }
9180 }
9181 }
9182 }
9183
9184 // b) set weights based on weightMode
9185 array<MInt, 2 * nDim> noFineNghbrs{};
9186 MBool hasBndryInStencil = false;
9187 for(MInt n = 0; n < noNghbrIds; n++) {
9188 const MInt nghbrId = a_reconstructionNeighborId(cellId, n);
9189 const MInt nghbrRootId =
9190 (a_hasProperty(nghbrId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(nghbrId) : nghbrId;
9191
9192 hasBndryInStencil = hasBndryInStencil || a_isBndryCell(nghbrId);
9193
9194 // compute distance weight
9195 MFloat dxdx = F0;
9196 for(MInt i = 0; i < nDim; i++) {
9197 dxdx += POW2(a_coordinate(nghbrId, i) - a_coordinate(cellId, i));
9198 }
9199
9200 MFloat fac = F1;
9201 // compute volume weight factor for weightMode 2
9202 // based on cell distances and volume ratios
9203 // to account for small cells falling out of the stencil!
9204 if(weightMode == 2 && !a_isBndryGhostCell(nghbrId) && a_isBndryCell(nghbrId)) {
9205 const MFloat vf = a_cellVolume(nghbrId) / c_cellVolumeAtLevel(a_level(nghbrId));
9206 fac = maia::math::deltaFun(vf, 1e-6, 0.1);
9207 // don't kompletly fade out small cells, but reduce them to the same value as uncut neighbors
9208 // which have a larger distance!
9209 if(m_engineSetup) {
9210 fac = fac * 0.5 + 0.5;
9211 }
9212 // if (a_bndryId( nghbrId )== -2 ) {
9213 // fac = F1 - maia::math::deltaFun( m_fvBndryCnd->m_bndryCells->a[a_bndryId( cellId )].m_volume/m_gridCellVolume[
9214 // a_level(cellId) ], 0.9, F1 );
9215 //}
9216 }
9217
9218 // set weight to zero for all non-direct neighbors for weightMode 1
9219 if(weightMode == 1 && !a_isBndryGhostCell(nghbrId)) {
9220 fac = (nextNghbrs.count(nghbrRootId) == 0) ? F0 : fac;
9221 // TODO labels:FV possibly change: do not to compute the diagonal neighbors as
9222 // their weight is currently set to zero and their reconstruction Constant
9223 // is thus very low!
9224 }
9225
9226 if(weightMode == 3 || weightMode == 4) {
9227 // By now bndry cells are excluded
9228 const MInt orientation = isDirectNghbr(nghbrId);
9229 if(((!a_isBndryCell(cellId) && !a_isBndryGhostCell(nghbrId)) || m_reExcludeBndryDiagonals) && orientation == -2) {
9230 fac = 0.0;
9231 } else if(m_2ndOrderWeights && (!a_isBndryCell(cellId) || m_reExcludeBndryDiagonals)
9232 && a_level(nghbrId) > a_level(cellId)) {
9233 TERMM_IF_NOT_COND(orientation >= 0 && orientation < 2 * nDim, "");
9234 ++noFineNghbrs[orientation];
9235 }
9236 }
9237
9238 weights[n] = fac * maia::math::RBF(dxdx, POW2(cellLength));
9239 // weights[n] = POW2(c_cellLengthAtCell(cellId) )/dxdx;
9240 }
9241
9242 // Update weights such that slope computation is 2nd order over rfn-jmp for 3-point stencil for locally 1D flow.
9243 // Since currently the stencils of bndry cells include diagonal cells, a weighting is needed
9244 // for the solutoin to be smooth, and weighting is kept as before.
9245 if((weightMode == 3 || weightMode == 4) && m_2ndOrderWeights
9246 && (!a_isBndryCell(cellId) || m_reExcludeBndryDiagonals)) {
9247 for(MInt n = 0; n < noNghbrIds; n++) {
9248 const MInt nghbrId = a_reconstructionNeighborId(cellId, n);
9249 if(approx(weights[n], 0.0, EPS)) {
9250 continue; // if weight was set to zero previously continue
9251 }
9252
9253 MFloat dxdx = F0;
9254 if(relocateCenter) {
9255 const MInt d = (MInt)isDirectNghbr(nghbrId) / 2;
9256 TERMM_IF_NOT_COND(d >= 0 && d < nDim, "Try setting reExcludeBndryDiagonals==true and retry!");
9257 dxdx = POW2(a_coordinate(nghbrId, d) - a_coordinate(cellId, d));
9258 } else {
9259 for(MInt i = 0; i < nDim; i++) {
9260 if(dirs[i]) {
9261 dxdx += POW2(a_coordinate(nghbrId, i) - a_coordinate(cellId, i));
9262 }
9263 }
9264 }
9265
9266 // If a bndry cell is contained in stencil, reduce power of weighting from w^2~1/dx^3 (2nd order)
9267 const MFloat exp = hasBndryInStencil ? 0.0 : 0.75;
9268 weights[n] = 1.0 / pow(fabs(dxdx), exp);
9269 if(a_level(nghbrId) > a_level(cellId)) {
9270 const MInt orientation = isDirectNghbr(nghbrId);
9271 TERMM_IF_NOT_COND(orientation >= 0 && orientation < 2 * nDim, "");
9272 weights[n] *= 1.0 / sqrt(noFineNghbrs[orientation]);
9273 }
9274 }
9275 }
9276
9277 // compute Stencil check
9278 if(fallBackMode == 1) {
9279 // compute stencil check and dirTest
9280 MFloat dirTest[3] = {F0, F0, F0};
9281 for(MInt n = 0; n < a_noReconstructionNeighbors(cellId); n++) {
9282 const MInt nghbrId = a_reconstructionNeighborId(cellId, n);
9283 ASSERT(!a_hasProperty(nghbrId, SolverCell::IsSplitCell), "");
9284 for(MInt i = 0; i < nDim; i++) {
9285 dirTest[i] =
9286 mMax(dirTest[i], weights(n) * fabs(a_coordinate(nghbrId, i) - a_coordinate(cellId, i)) / cellLength);
9287 }
9288 }
9289 MFloat stencilCheck = F1;
9290 for(MInt i = 0; i < nDim; i++) {
9291 stencilCheck = mMin(stencilCheck, dirTest[i]);
9292 }
9293 // if the cells are to close to each other, the stencil is extended
9294 if(stencilCheck < 0.1) {
9295 extendStencil(cellId);
9296 }
9297 // compute reconstruction constants and return
9298 return computeRecConstSVD(cellId, offset, tmpA, tmpC, weights, recDim, weightMode, 2);
9299 }
9300
9301
9302 const MFloat normalizationFactor = FPOW2(a_level(cellId)) / c_cellLengthAtLevel(0);
9303 // reduces the condition number of the eq system
9304
9305 std::vector<MBool> zeroColumns(recDim, true);
9306 std::array<MInt, nDim> recNghbrsRfn;
9307 std::fill_n(&recNghbrsRfn[0], nDim, -1);
9308 std::array<MFloat, nDim - 1> recConstantsRfn = {};
9309 MBool foundCoarseNghbr = false;
9310 for(MInt n = 0; n < noNghbrIds; n++) {
9311 const MInt nghbrId = a_reconstructionNeighborId(cellId, n);
9312 std::array<MFloat, nDim> dx;
9313 dx.fill(0.0);
9314 if(weightMode == 4) {
9315 if(!a_isBndryCell(cellId) && weights[n] > EPS && a_level(nghbrId) < a_level(cellId)
9316 && currentSlopeDir != -1) { //(relocateCenter == m_relocateCenter)) {
9317 TERMM_IF_NOT_COND(currentSlopeDir != -1, "Only one direction at a time should be considered");
9318 TERMM_IF_NOT_COND(!foundCoarseNghbr, "Only one coarse nghbr per direction is allowed!");
9319 recNghbrsRfn[0] = n;
9320 MInt dimN = currentSlopeDir; // direction of coarse nghbr
9321 array<MInt, nDim - 1> dimT{}; // tangential directions
9322 MFloatScratchSpace dxT(nDim - 1, nDim - 1, AT_, "dxT"); // dx in tangential directions
9323 MInt noTDims = 0;
9324 for(MInt i = 0; i < nDim; ++i) {
9325 if(i != dimN) {
9326 const MInt dir = a_coordinate(cellId, i) > a_coordinate(nghbrId, i) ? 0 : 1;
9327 if(checkNeighborActive(cellId, 2 * i + dir) && a_hasNeighbor(cellId, 2 * i + dir), "") {
9328 const MInt nghbrId_ = c_neighborId(cellId, 2 * i + dir);
9329 for(MInt nn = 0; nn < noNghbrIds; nn++) {
9330 if(a_reconstructionNeighborId(cellId, nn) == nghbrId_) {
9331 recNghbrsRfn[noTDims + 1] = nn;
9332 }
9333 }
9334 TERMM_IF_NOT_COND(recNghbrsRfn[noTDims + 1] != -1, "This nghbr must exist in rec-stencil!");
9335 TERMM_IF_NOT_COND(a_hasProperty(nghbrId_, SolverCell::IsOnCurrentMGLevel), "");
9336 dimT[noTDims] = i;
9337 for(MInt d = 0, dd = 0; d < nDim; ++d) {
9338 if(d != dimN) {
9339 dxT(dd++, noTDims) = a_coordinate(nghbrId_, d) - a_coordinate(cellId, d);
9340 }
9341 }
9342 ++noTDims;
9343 }
9344 }
9345 }
9346
9347 dx[dimN] = a_coordinate(nghbrId, dimN) - a_coordinate(cellId, dimN);
9348 if(noTDims == nDim - 1) {
9349 MFloatScratchSpace dxT_inv(nDim - 1, nDim - 1, AT_, "dxT_inv");
9350 maia::math::invert(dxT, dxT_inv, nDim - 1, nDim - 1);
9351 for(MInt i = 0; i < nDim - 1; ++i) {
9352 recConstantsRfn[i] = 0;
9353 for(MInt d = 0; d < nDim - 1; ++d) {
9354 recConstantsRfn[i] += dxT_inv(i, d) * (a_coordinate(nghbrId, dimT[d]) - a_coordinate(cellId, dimT[d]));
9355 }
9356 if(!a_isBndryCell(nghbrId) && !a_isBndryCell(a_reconstructionNeighborId(cellId, recNghbrsRfn[1]))
9357 && !a_isBndryCell(a_reconstructionNeighborId(cellId, recNghbrsRfn[nDim - 1]))) {
9358 TERMM_IF_NOT_COND(approx(recConstantsRfn[i], 0.5, EPS), "");
9359 }
9360 }
9361 for(MInt i = 0; i < nDim - 1; ++i) {
9362 const MInt nghbrId_ = a_reconstructionNeighborId(cellId, recNghbrsRfn[i + 1]);
9363 dx[dimN] += (a_coordinate(cellId, dimN) - a_coordinate(nghbrId_, dimN)) * recConstantsRfn[i];
9364 }
9365 }
9366 if(nDim == 3 && noTDims == 1) {
9367 for(MInt d = 0, dd = 0; d < nDim; ++d) {
9368 if(d != dimN) {
9369 dxT(dd, noTDims) = dxT(1 - dd, 0);
9370 ++dd;
9371 }
9372 }
9373 dxT(0, noTDims) *= -1;
9374 MFloatScratchSpace dxT_inv(nDim - 1, nDim - 1, AT_, "dxT_inv");
9375 maia::math::invert(dxT, dxT_inv, nDim - 1, nDim - 1);
9376 recConstantsRfn[0] = 0;
9377 for(MInt d = 0; d < nDim - 1; ++d) {
9378 recConstantsRfn[0] += dxT_inv(0, d) * (a_coordinate(nghbrId, dimT[d]) - a_coordinate(cellId, dimT[d]));
9379 }
9380 dx[dimN] +=
9381 (a_coordinate(cellId, dimN) - a_coordinate(a_reconstructionNeighborId(cellId, recNghbrsRfn[1]), dimN))
9382 * recConstantsRfn[0];
9383 }
9384 dx[dimN] *= normalizationFactor;
9385 foundCoarseNghbr = true;
9386 //} //else if(!a_isBndryCell(cellId) && weights[n] > EPS && a_level(nghbrId) > a_level(cellId)) {
9387 // for(MInt i = 0; i < nDim; i++) {
9388 // dx[i] = (a_coordinate(nghbrId, i) - a_coordinate(cellId, i)) * normalizationFactor;
9389 //}
9390 } else {
9391 if(relocateCenter) {
9392 const MInt d = (MInt)isDirectNghbr(nghbrId) / 2;
9393 if(d > -1) {
9394 dx[d] = (a_coordinate(nghbrId, d) - a_coordinate(cellId, d)) * normalizationFactor;
9395 }
9396 } else {
9397 for(MInt i = 0; i < nDim; i++) {
9398 if(dirs[i]) {
9399 dx[i] = (a_coordinate(nghbrId, i) - a_coordinate(cellId, i)) * normalizationFactor;
9400 }
9401 }
9402 }
9403 }
9404 } else if(weightMode == 3) {
9405 for(MInt i = 0; i < nDim; i++) {
9406 if(dirs[i]) {
9407 dx[i] = (a_coordinate(nghbrId, i) - a_coordinate(cellId, i)) * normalizationFactor;
9408 }
9409 }
9410 } else {
9411 for(MInt i = 0; i < nDim; i++) {
9412 dx[i] = (a_coordinate(nghbrId, i) - a_coordinate(cellId, i)) * normalizationFactor;
9413 }
9414 }
9415 MInt cnt = 0;
9416 for(MInt i = 0; i < nDim; i++) {
9417 tmpA(n, i) = dx[i];
9418 if(fabs(tmpA(n, i)) > EPS && fabs(weights[n]) > EPS) {
9419 zeroColumns[i] = false;
9420 }
9421 cnt++;
9422 }
9423 for(MInt i = 0; i < nDim; i++) {
9424 if(cnt < recDim) {
9425 tmpA(n, cnt) = F1B2 * POW2(dx[i]);
9426 if(fabs(tmpA(n, cnt)) > EPS && fabs(weights[n]) > EPS) {
9427 zeroColumns[cnt] = false;
9428 }
9429 cnt++;
9430 }
9431 }
9432 for(MInt i = 0; i < nDim; i++) {
9433 for(MInt j = i + 1; j < nDim; j++) {
9434 if(cnt < recDim) {
9435 tmpA(n, cnt) = dx[i] * dx[j];
9436 if(fabs(tmpA(n, cnt)) > EPS && fabs(weights[n]) > EPS) {
9437 zeroColumns[cnt] = false;
9438 }
9439 cnt++;
9440 }
9441 }
9442 }
9443 }
9444
9445 // Remove zero columns
9446 for(MInt n = 0; n < noNghbrIds; n++) {
9447 for(MInt i = 0, ii = 0; i < recDim; ++i) {
9448 if(!allDirs && !dirs[i]) { // TODO check if this would improve solution quality
9449 zeroColumns[i] = true;
9450 }
9451 if(!zeroColumns[i]) {
9452 tmpA(n, ii) = tmpA(n, i);
9453 ++ii;
9454 }
9455 }
9456 }
9457
9458 const MInt recDimSignificant = std::count(zeroColumns.begin(), zeroColumns.end(), false);
9459 TERMM_IF_COND(recDimSignificant == 0,
9460 std::to_string(dirs[0]) + " " + std::to_string(dirs[1]) + " " + std::to_string(allDirs));
9461
9462 const MInt rank = maia::math::invertR(tmpA, weights, tmpC, noNghbrIds, recDimSignificant);
9463 if(rank < min(noNghbrIds, recDimSignificant)) {
9464#ifndef NDEBUG
9465 cerr << domainId() << ": QRD failed for cell " << cellId << " " << c_globalId(cellId) << " " << a_level(cellId)
9466 << " " << a_isHalo(cellId) << " " << a_hasProperty(cellId, SolverCell::IsNotGradient) << " /split "
9467 << a_hasProperty(cellId, SolverCell::IsSplitCell) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild)
9468 << " " << a_hasProperty(cellId, SolverCell::HasSplitFace) << endl;
9469 for(MInt n = 0; n < noNghbrIds; n++) {
9470 cerr << weights[n] << " ";
9471 }
9472 cerr << endl;
9473 for(MInt dir = 0; dir < 2 * nDim; dir++) {
9474 if(checkNeighborActive(cellId, dir)) {
9475 cerr << a_hasNeighbor(cellId, dir) << "/" << c_neighborId(cellId, dir) << " ";
9476 }
9477 }
9478 cerr << endl;
9479#endif
9480 // todo labels:FV this is not correct tmpA and tmpC needs to be reset
9481 maia::math::invert(tmpA, weights, tmpC, noNghbrIds, recDimSignificant - 1);
9482 }
9483
9484 a_reconstructionData(cellId) = offset;
9485 if((signed)m_reconstructionConstants.size() < nDim * (offset + noNghbrIds)) {
9486 m_reconstructionConstants.resize(nDim * (offset + noNghbrIds));
9487 m_reconstructionCellIds.resize(offset + noNghbrIds);
9488 m_reconstructionNghbrIds.resize(offset + noNghbrIds);
9489 }
9490 std::vector<MFloat> reConstants;
9491 if(weightMode == 4 && relocateCenter && hasBndryInStencil) {
9492 reConstants.resize(nDim * noNghbrIds);
9493 std::copy_n(&m_reconstructionConstants[nDim * offset], nDim * noNghbrIds, &reConstants[0]);
9494 }
9495 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
9496 const MInt nghbrId = a_reconstructionNeighborId(cellId, nghbr);
9497 m_reconstructionCellIds[offset + nghbr] = cellId;
9498 m_reconstructionNghbrIds[offset + nghbr] = nghbrId;
9499 for(MInt i = 0, ii = -1; i < nDim; i++) {
9500 if(zeroColumns[i]) {
9501 continue;
9502 }
9503 ++ii;
9504 if(!allDirs && !dirs[i]) {
9505 continue;
9506 }
9507 m_reconstructionConstants[nDim * (offset + nghbr) + i] = tmpC(ii, nghbr) * normalizationFactor;
9508 }
9509 }
9510
9511 if(weightMode == 4 && relocateCenter && hasBndryInStencil) {
9512 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
9513 const MInt nghbrId = a_reconstructionNeighborId(cellId, nghbr);
9514
9515 const MInt d = (MInt)isDirectNghbr(nghbrId) / 2;
9516 if(a_isBndryCell(nghbrId) && a_level(nghbrId) >= a_level(cellId) && d > -1) {
9517 array<MFloat, nDim> dx{};
9518 for(MInt dd = 0; dd < nDim; ++dd) {
9519 if(dd != d) {
9520 dx[dd] = a_coordinate(nghbrId, dd) - a_coordinate(cellId, dd);
9521 }
9522 }
9523 for(MInt nghbr2 = 0; nghbr2 < noNghbrIds; nghbr2++) {
9524 for(MInt i = 0; i < nDim; ++i) {
9525 if(zeroColumns[i]) {
9526 continue;
9527 }
9528 if(!allDirs && !dirs[i]) {
9529 continue;
9530 }
9531 for(MInt dd = 0; dd < nDim; ++dd) {
9532 m_reconstructionConstants[nDim * (offset + nghbr2) + i] -=
9533 m_reconstructionConstants[nDim * (offset + nghbr) + i] * (reConstants[nDim * nghbr2 + dd] * dx[dd]);
9534 }
9535 }
9536 }
9537 }
9538 }
9539 }
9540
9541 if(foundCoarseNghbr) { // weightMode == 4
9542 const MInt nghbr = recNghbrsRfn[0];
9543 for(MInt i = 0; i < nDim; i++) {
9544 if(zeroColumns[i]) {
9545 continue;
9546 }
9547 if(!allDirs && !dirs[i]) {
9548 continue;
9549 }
9550 for(MInt n = 0; n < nDim - 1; ++n) {
9551 if(recNghbrsRfn[n + 1] != -1) {
9552 const MInt nghbr_ = recNghbrsRfn[n + 1];
9553 TERMM_IF_NOT_COND(approx(m_reconstructionConstants[nDim * (offset + nghbr_) + i], 0.0, MFloatEps), "");
9554 m_reconstructionConstants[nDim * (offset + nghbr_) + i] =
9555 -recConstantsRfn[n] * m_reconstructionConstants[nDim * (offset + nghbr) + i];
9556 }
9557 }
9558 }
9559 }
9560
9561 const MInt condNum = maia::math::frobeniusMatrixNormSquared(tmpA, noNghbrIds, recDimSignificant);
9562 if(condNum < F0 || condNum > 1e6 || std::isnan(condNum)) {
9563 // fall-back solution:
9564 if(fallBackMode > 0) {
9565 extendStencil(cellId);
9566 return computeRecConstSVD(cellId, offset, tmpA, tmpC, weights, recDim, weightMode, -1);
9567 }
9568
9569 // debug output
9570 cerr << domainId() << " " << globalTimeStep << " SVD decomposition for cell " << cellId << "/" << c_globalId(cellId)
9571 << " level " << a_level(cellId) << " with large condition number: " << condNum << " " << noNghbrIds << "x"
9572 << recDim << " " << a_cellVolume(cellId) / pow(cellLength, (MFloat)nDim) << " coords "
9573 << a_coordinate(cellId, 0) << ", " << a_coordinate(cellId, 1) << ", " << a_coordinate(cellId, 2) << " bndryId "
9574 << a_bndryId(cellId) << endl;
9575 for(MInt n = 0; n < noNghbrIds; n++) {
9576 cerr << c_globalId(a_reconstructionNeighborId(cellId, n)) << "(" << weights[n] << ") ";
9577 }
9578 ASSERT(false, "");
9579 }
9580
9581 return condNum;
9582}
9583
9584//-------------------------------------------------------------------------------------------
9585
9590template <MInt nDim_, class SysEqn>
9592 TRACE();
9593
9594 MIntScratchSpace nghbrList(100, AT_, "nghbrList");
9595 MIntScratchSpace layerId(100, AT_, "layerList");
9596
9597 const MInt rootCell = (a_hasProperty(cellId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(cellId) : cellId;
9598
9599 // reset reconstruction neighbors and only keep ghostCells
9600 a_noReconstructionNeighbors(cellId) = (a_isBndryCell(cellId)) ? m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs : 0;
9601
9602 const MInt counter2 = getAdjacentLeafCells_d2_c(rootCell, 1, nghbrList, layerId);
9603
9604 for(MInt n = 0; n < counter2; n++) {
9605 if(nghbrList[n] < 0) continue;
9606 if(a_hasProperty(nghbrList[n], SolverCell::IsInactive)) continue;
9607 if(a_noReconstructionNeighbors(cellId) < m_cells.noRecNghbrs()) {
9608 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) = nghbrList[n];
9609 a_noReconstructionNeighbors(cellId)++;
9610 } else {
9611 cerr << "Warning: too many reconstruction neighbors for cell " << cellId << endl;
9612 }
9613 }
9614}
9615
9616
9617//-------------------------------------------------------------------------------------------
9622template <MInt nDim_, class SysEqn>
9624 TRACE();
9625
9626 // compute the infinity values for the restart file Mach number (m_previousMa)
9627 const MFloat tInfRestart = sysEqn().temperature_IR(m_previousMa);
9628 const MFloat pInfRestart = sysEqn().pressure_IR(tInfRestart);
9629 const MFloat uInfRestart = m_previousMa * sqrt(tInfRestart);
9630 const MFloat rhoInfRestart = sysEqn().density_IR(tInfRestart);
9631
9632 // compute the infinity values for the Mach number
9633 const MFloat tInf = sysEqn().temperature_IR(m_Ma);
9634 const MFloat pInf = sysEqn().pressure_IR(tInf);
9635 const MFloat uInf = m_Ma * sqrt(tInf);
9636 const MFloat rhoInf = sysEqn().density_IR(tInf);
9637
9638 // set the ratio
9639 const MFloat velRatio = uInf / uInfRestart;
9640 const MFloat densityRatio = rhoInf / rhoInfRestart;
9641 const MFloat pressureRatio = pInf / pInfRestart;
9642
9643 // conversion
9644 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
9645 // compute the velocities
9646 for(MInt i = 0; i < nDim; i++) {
9647 a_pvariable(cellId, PV->VV[i]) *= velRatio;
9648 }
9649
9650 // compute the density
9651 a_pvariable(cellId, PV->RHO) *= densityRatio;
9652
9653 // compute the pressure
9654 a_pvariable(cellId, PV->P) *= pressureRatio;
9655 }
9656}
9657
9662template <MInt nDim_, class SysEqn>
9664 TRACE();
9665
9666 ASSERT(m_hasExternalSource, "");
9667
9668 // exchange all external sources
9669 if(noDomains() > 1) {
9670 maia::mpi::reverseExchangeAddData(grid().neighborDomains(), grid().haloCells(), grid().windowCells(), mpiComm(),
9671 m_externalSource, CV->noVariables);
9672 }
9673
9674
9675 MBool filter = false;
9676 // TODO labels:FV,totest check filter function!
9677 if(filter) {
9678 grid().smoothFilter(maxRefinementLevel() - 1, m_externalSource);
9679 }
9680}
9681
9685template <MInt nDim_, class SysEqn>
9687 TRACE();
9688
9689 for(MInt ac = 0; ac < m_noActiveCells; ac++) {
9690 const MInt cellId = m_activeCellIds[ac];
9691 for(MInt var = 0; var < CV->noVariables; var++) {
9692 a_rightHandSide(cellId, var) += a_externalSource(cellId, var);
9693 }
9694 }
9695}
9696
9700template <MInt nDim_, class SysEqn>
9702 TRACE();
9703
9704 ASSERT(m_hasExternalSource, "");
9705
9706 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
9707 for(MInt var = 0; var < CV->noVariables; var++) {
9708 a_externalSource(cellId, var) = 0;
9709 }
9710 }
9711}
9712
9713template <MInt nDim_, class SysEqn>
9715 const MInt noPVars = PV->noVariables;
9716
9717 for(MInt vari = 0; vari < noPVars; vari++)
9718 vars[vari] = a_pvariable(cellId, vari);
9719
9720 if(order == 0) return;
9721
9722 for(MInt vari = 0; vari < noPVars; vari++)
9723 for(MInt dimi = 0; dimi < nDim; dimi++)
9724 vars[vari] += a_slope(cellId, vari, dimi) * (Xp[dimi] - a_coordinate(cellId, dimi));
9725}
9726
9728template <MInt nDim_, class SysEqn>
9730 if(m_timeStepComputationInterval == -1 && m_restart) {
9731 return true;
9732 } else if(m_restart && Context::propertyExists("consistentRestart", m_solverId)
9733 && Context::getSolverProperty<MBool>("consistentRestart", m_solverId, AT_)) {
9734 return true;
9735 }
9736
9737 return false;
9738}
9739
9741template <MInt nDim_, class SysEqn>
9743 switch(m_timeStepComputationInterval) {
9744 case -1:
9745 case 0: {
9746 return false;
9747 } // only once at the beginning
9748 default: {
9749 if(m_timeStepComputationInterval < 0) {
9750 mTerm(1, AT_,
9751 "timeStepComputationInterval is " + to_string(m_timeStepComputationInterval)
9752 + " and out-of-range [-1, infinity)");
9753 }
9754 return globalTimeStep % m_timeStepComputationInterval == 0;
9755 }
9756 }
9757}
9758
9759template <MInt nDim_, class SysEqn>
9761 TRACE();
9762 if((m_timeStepMethod == 17511 && nDim == 2) || m_timeStepMethod == 6) {
9763 return;
9764 }
9765 m_restartFileOutputTimeStep = timeStep();
9766}
9767
9771template <MInt nDim_, class SysEqn>
9773 TRACE();
9774 RECORD_TIMER_START(m_timers[Timers::TimeInt]);
9775 RECORD_TIMER_START(m_timers[Timers::Rhs]);
9776
9777 resetRHS();
9778
9779 IF_CONSTEXPR(isDetChem<SysEqn>) {
9780 RECORD_TIMER_START(m_timers[Timers::CellCenterCoefficients]);
9781 computeMeanMolarWeights_CV();
9782 RECORD_TIMER_STOP(m_timers[Timers::CellCenterCoefficients]);
9783 }
9784
9785 RECORD_TIMER_START(m_timers[Timers::Muscl]);
9786 Muscl();
9787 RECORD_TIMER_STOP(m_timers[Timers::Muscl]);
9788
9789#if defined(WITH_CANTERA)
9790 if(m_detChem.hasChemicalReaction && (m_RKStep == 0)) {
9791 IF_CONSTEXPR(isDetChem<SysEqn>) {
9792 RECORD_TIMER_START(m_timers[Timers::SpeciesReactionRates]);
9793 computeSpeciesReactionRates();
9794 RECORD_TIMER_STOP(m_timers[Timers::SpeciesReactionRates]);
9795 }
9796 }
9797 IF_CONSTEXPR(isDetChem<SysEqn>) {
9798 RECORD_TIMER_START(m_timers[Timers::SurfaceCoefficients]);
9799 computeDetailedChemistryVariables();
9800 RECORD_TIMER_STOP(m_timers[Timers::SurfaceCoefficients]);
9801 }
9802#endif
9803
9804 RECORD_TIMER_START(m_timers[Timers::Ausm]);
9805 Ausm();
9806 RECORD_TIMER_STOP(m_timers[Timers::Ausm]);
9807
9808 RECORD_TIMER_START(m_timers[Timers::ViscFlux]);
9809 if(!m_euler) {
9810 viscousFlux();
9811 // TODO labels:FV Decide if those two variants are still needed. If yes, move to appropriate SysEqn!
9812 IF_CONSTEXPR(nDim == 2) {
9813 if(m_combustion) {
9814 if(m_plenum) {
9815 mTerm(1, "Move to sysEqn!");
9816 viscousFlux_Gequ_Pv_Plenum();
9817 } else if(m_divergenceTreatment) {
9818 mTerm(1, "Move to sysEqn!");
9819 viscousFlux_Gequ_Pv();
9820 }
9821 }
9822 }
9823 }
9824 RECORD_TIMER_STOP(m_timers[Timers::ViscFlux]);
9825
9826 RECORD_TIMER_START(m_timers[Timers::DistFlux]);
9827 distributeFluxToCells();
9828 RECORD_TIMER_STOP(m_timers[Timers::DistFlux]);
9829
9830 RECORD_TIMER_START(m_timers[Timers::RhsMisc]);
9831 if(m_combustion) {
9832 computeSourceTerms();
9833 }
9834
9835 IF_CONSTEXPR(isDetChem<SysEqn>) {
9836 if(m_detChem.hasChemicalReaction) {
9837 addSpeciesReactionRatesAndHeatRelease();
9838 }
9839 }
9840
9841 if(m_considerVolumeForces) {
9842 computeVolumeForces();
9843 }
9844
9845 if(m_rans) {
9846 computeVolumeForcesRANS();
9847 }
9848
9849 if(m_considerRotForces) {
9850 computeRotForces();
9851 }
9852
9853 if(m_dualTimeStepping) {
9854 dqdtau();
9855 }
9856
9857 IF_CONSTEXPR(isEEGas<SysEqn>) rhsEEGas();
9858
9859 if(m_hasExternalSource) {
9860 applyExternalSource();
9861 }
9862 RECORD_TIMER_STOP(m_timers[Timers::RhsMisc]);
9863
9864 RECORD_TIMER_STOP(m_timers[Timers::Rhs]);
9865 RECORD_TIMER_STOP(m_timers[Timers::TimeInt]);
9866}
9867
9868
9872template <MInt nDim_, class SysEqn>
9874 TRACE();
9875 RECORD_TIMER_START(m_timers[Timers::TimeInt]);
9876 RECORD_TIMER_START(m_timers[Timers::RhsBnd]);
9877
9878 updateSpongeLayer();
9879
9880 updateJet();
9881
9882 resetRHSNonInternalCells();
9883
9884 resetRHSCutOffCells();
9885
9886 correctMasterCells();
9887
9888 nonReflectingBCCutOff();
9889
9890 if(m_fvBndryCnd->m_smallCellRHSCorrection) {
9891 smallCellRHSCorrection();
9892 updateSplitParentVariables();
9893 }
9894
9895 RECORD_TIMER_STOP(m_timers[Timers::RhsBnd]);
9896 RECORD_TIMER_STOP(m_timers[Timers::TimeInt]);
9897}
9898
9902template <MInt nDim_, class SysEqn>
9904 RECORD_TIMER_START(m_timers[Timers::TimeInt]);
9905 RECORD_TIMER_START(m_timers[Timers::Lhs]);
9906
9907 //-->debug
9908 /* MInt nosplitclones = 0;
9909 for( MInt cellId = 0; cellId < a_noCells(); cellId++ ){
9910 if(a_hasProperty(cellId, SolverCell::IsSplitClone)) nosplitclones++;
9911 }
9912 ASSERT(nosplitclones==0, "ERROR: clone cells in use!");
9913 */
9914
9915 if(m_levelSet && !m_levelSetMb && !m_combustion && !m_levelSetRans) {
9916 RECORD_TIMER_STOP(m_timers[Timers::Lhs]);
9917 RECORD_TIMER_STOP(m_timers[Timers::TimeInt]);
9918 return true;
9919 }
9920
9921 // If multilevel is activated and this is *not* the finest solver, apply multilevel correction
9922 if(isMultilevel() && !isMultilevelPrimary()) {
9923 applyCoarseLevelCorrection();
9924 }
9925
9926 // Perform one Runge-Kutta substep, returns if time step is completed
9927 const MBool step = rungeKuttaStep();
9928
9929 IF_CONSTEXPR(isDetChem<SysEqn>) { correctMajorSpeciesMassFraction(); }
9930
9931 nonReflectingBCAfterTreatmentCutOff();
9932
9933 // update the timeStep after the last rungeKuttaStep (=> new timeStep for next iteration!)
9934 if(step && requiresTimeStepUpdate()) {
9935#if defined(WITH_CANTERA)
9936 IF_CONSTEXPR(isDetChem<SysEqn>) { computeGamma(); }
9937#endif
9938 setTimeStep();
9939 }
9940
9941 RECORD_TIMER_STOP(m_timers[Timers::Lhs]);
9942 RECORD_TIMER_STOP(m_timers[Timers::TimeInt]);
9943 return step;
9944}
9945
9946
9952template <MInt nDim_, class SysEqn>
9954 TRACE();
9955
9956 // relevant for Post-Processing and set from pp-init
9957 m_statisticCombustionAnalysis = false;
9958
9959 m_statisticCombustionAnalysis =
9960 Context::getBasicProperty<MBool>("statisticCombustionAnalysis", AT_, &m_statisticCombustionAnalysis);
9961 if(m_statisticCombustionAnalysis || isDetChem<SysEqn>) {
9962 mAlloc(m_heatRelease, maxNoGridCells(), "m_heatRelease", F0, AT_);
9963 }
9964
9965 // Nothing to be done if solver is not active
9966 if(!isActive()) return;
9967
9968 const MFloat time0 = MPI_Wtime();
9969
9970 IF_CONSTEXPR(isEEGas<SysEqn>)
9971 if(m_EEGas.depthCorrection) initDepthCorrection();
9972
9973 applyInitialCondition();
9974 computePV();
9975
9976 if(m_zonal) {
9977 resetZonalSolverData();
9978 if(m_restart || (m_resetInitialCondition && m_solverId == m_zonalRestartInterpolationSolverId)) {
9979 loadRestartFile();
9980 }
9981 }
9982
9983 if(m_STGSponge) initSTGSponge();
9984
9985 if(noNeighborDomains() > 0) {
9986 exchangeDataFV(&a_variable(0, 0), CV->noVariables, false, m_rotIndVarsCV);
9987 exchangeDataFV(&a_oldVariable(0, 0), CV->noVariables, false, m_rotIndVarsCV);
9988 exchangeDataFV(&a_pvariable(0, 0), PV->noVariables, false, m_rotIndVarsPV);
9989 }
9990
9991 const MFloat time1 = MPI_Wtime();
9992 if(domainId() == 0) m_log << "Init solution time " << time1 - time0 << endl;
9993}
9994
9995
10000template <MInt nDim_, class SysEqn>
10002 TRACE();
10003
10004 // Nothing to be done if solver is not active
10005 if(!isActive()) return;
10006
10007 // Load restart
10008 if(m_restart && !(m_zonal || grid().azimuthalPeriodicity())) {
10009 loadRestartFile();
10010 }
10011
10012 // Reallocate memory to small and master cell id arrays
10013 reInitSmallCellIdsMemory();
10014
10015 // initialize the solver
10016 initSolutionStep(-1);
10017
10018 // Reallocate solver memory to arrays depending on a_noCells()
10019 reInitActiveCellIdsMemory();
10020 writeListOfActiveFlowCells();
10021
10022 initializeMaxLevelExchange();
10023
10024 {
10025 MLong maxNoCells = noInternalCells();
10026 MPI_Allreduce(MPI_IN_PLACE, &maxNoCells, 1, type_traits<MLong>::mpiType(), MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
10027 "maxNoCells");
10028 MLong maxNoTotalCells = a_noCells();
10029 MPI_Allreduce(MPI_IN_PLACE, &maxNoTotalCells, 1, type_traits<MLong>::mpiType(), MPI_MAX, mpiComm(), AT_,
10030 "MPI_IN_PLACE", "maxNoTotalCells");
10031 stringstream message;
10032 message << "Solver #" << solverId() << " - maximum number of internal cells among ranks: " << maxNoCells
10033 << std::endl;
10034 message << "Solver #" << solverId() << " - maximum number of cells among ranks: " << maxNoTotalCells << std::endl;
10035 m_log << message.str();
10036 cerr0 << message.str();
10037 }
10038
10039 IF_CONSTEXPR(isEEGas<SysEqn>)
10040 if(m_EEGas.depthCorrection) initDepthCorrection();
10041
10042 // initialize the flow field (again)
10043 applyInitialCondition();
10044
10045 // IF_CONSTEXPR(isDetChem<SysEqn>) { computeMeanMolarWeights_CV(); }
10046
10047 // Calculate primitive variables
10048 computePV();
10049
10050#if defined(WITH_CANTERA)
10051 IF_CONSTEXPR(isDetChem<SysEqn>) { computeGamma(); }
10052#endif
10053
10054 // initialize the runge kutta integration scheme
10055 initializeRungeKutta();
10056
10057 setTimeStep();
10058
10059 // periodic exchange (azimuthal periodicity concept)
10060 if(m_periodicCells == 3) {
10061 exchange();
10062 exchangePeriodic();
10063 }
10064
10065 // Exchange halo/window cell information if multiSolver is enabled
10066 exchange();
10067
10068 if(m_calcLESAverage) {
10069 determineLESAverageCells();
10070 // resetZonalLESAverage();
10071 finalizeLESAverage();
10072 }
10073
10074 if(m_STGSponge) {
10075 initSTGSpongeExchange();
10076 if(m_preliminarySponge) {
10077 readPreliminarySTGSpongeData();
10078 }
10079 }
10080
10081 if(m_STGSponge && globalTimeStep > m_stgSpongeTimeStep) {
10082 loadSpongeData();
10083 }
10084
10085 // Set cut-off boundary conditions
10086 cutOffBoundaryCondition();
10087
10088 // Apply boundary conditions
10089 applyBoundaryCondition();
10090
10091 computeConservativeVariables();
10092
10093 // Calls the scalar limiter if species are calculated
10094 scalarLimiter();
10095
10096 // Compute the cell center slopes here if changed slope calculation activated
10097 if(calcSlopesAfterStep()) {
10098 LSReconstructCellCenter();
10099 m_fvBndryCnd->copySlopesToSmallCells();
10100 m_fvBndryCnd->updateGhostCellSlopesInviscid();
10101 m_fvBndryCnd->updateCutOffSlopesInviscid();
10102 }
10103
10104 if(m_combustion && !m_LSSolver) {
10105 setCellProperties();
10106 computePrimitiveVariablesCoarseGrid();
10107 computeConservativeVariables();
10108 }
10109
10110 if((m_levelSet || m_levelSetRans) && !m_combustion && !m_LSSolver) {
10111 setCellProperties();
10112 }
10113
10114 IF_CONSTEXPR(isEEGas<SysEqn>) {
10115 if(m_EEGas.gasSource != 0) initSourceCells();
10116 grid().findEqualLevelNeighborsParDiagonal(false);
10117 }
10118}
10119
10124template <MInt nDim, class SysEqn>
10125template <class _, std::enable_if_t<isEEGas<SysEqn>, _*>>
10127 MFloat sourceCellVolume = 0.0;
10128 switch(m_EEGas.gasSource) {
10129 case 0:
10130 return;
10131 break;
10132
10133 case 9: // gas Source defined by property gasSourceBox
10134 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
10135 if(a_level(cellId) != maxLevel() || a_isBndryGhostCell(cellId)) continue;
10136 MBool isInAnyBox = false;
10137 for(MInt box = 0; box < m_EEGas.noGasSourceBoxes; box++) {
10138 MBool isInThisBox = true;
10139 for(MInt i = 0; i < nDim; i++) {
10140 if(a_coordinate(cellId, i) < m_EEGas.gasSourceBox[i + box * nDim * 2]
10141 || a_coordinate(cellId, i) > m_EEGas.gasSourceBox[i + nDim + box * nDim * 2]) {
10142 isInThisBox = false;
10143 break;
10144 }
10145 }
10146 if(isInThisBox) {
10147 isInAnyBox = true;
10148 break;
10149 }
10150 }
10151 if(isInAnyBox) {
10152 m_EEGas.gasSourceCells.push_back(cellId);
10153 if(!a_isHalo(cellId)) sourceCellVolume += a_cellVolume(cellId);
10154 }
10155 }
10156 break;
10157
10158 default:
10159 break;
10160 }
10161 MPI_Allreduce(MPI_IN_PLACE, &sourceCellVolume, 1, type_traits<MFloat>::mpiType(), MPI_SUM, mpiComm(), AT_,
10162 "MPI_IN_PLACE", "totalSourceCellVolume");
10163
10164 MFloat massFlow = m_EEGas.gasSourceMassFlow;
10165 m_EEGas.massSource = massFlow / sourceCellVolume;
10166
10167 if(domainId() == 0)
10168 std::cerr << "Volume of gas mass source cells: " << sourceCellVolume
10169 << " \tmass source (rho): " << m_EEGas.massSource << std::endl;
10170}
10171
10177template <MInt nDim_, class SysEqn>
10179 TRACE();
10180
10181 RECORD_TIMER_START(m_timers[Timers::TimeInt]);
10182 RECORD_TIMER_START(m_timers[Timers::LhsBnd]);
10183
10184 if(!g_splitMpiComm) {
10185 mTerm(1, "lhsBndFinish() should only be used with split MPI communication "
10186 "(splitMpiComm) activated.");
10187 }
10188
10189 RECORD_TIMER_START(m_timers[Timers::Exchange]);
10190
10191 RECORD_TIMER_START(m_tcomm);
10192 RECORD_TIMER_START(m_texchange);
10193 finishMpiExchange();
10194 RECORD_TIMER_STOP(m_texchange);
10195 RECORD_TIMER_STOP(m_tcomm);
10196
10197 RECORD_TIMER_STOP(m_timers[Timers::Exchange]);
10198
10199 // These are the remaining calls in lhsBnd() that need to be executed after
10200 // the data exchange finished
10201 // Note: if anything here is changed, make sure to apply the same changes in
10202 // lhsBnd()
10203 computePrimitiveVariablesCoarseGrid();
10204
10205 RECORD_TIMER_START(m_timers[Timers::CutOff]);
10206 cutOffBoundaryCondition();
10207 RECORD_TIMER_STOP(m_timers[Timers::CutOff]);
10208
10209 RECORD_TIMER_START(m_timers[Timers::BndryCnd]);
10210 applyBoundaryCondition();
10211 RECORD_TIMER_STOP(m_timers[Timers::BndryCnd]);
10212
10213 computePrimitiveVariablesCoarseGrid();
10214
10215 // Compute the cell center slopes here if changed slope calculation activated
10216 if(calcSlopesAfterStep()) {
10217 RECORD_TIMER_STOP(m_timers[Timers::LhsBnd]);
10218
10219 RECORD_TIMER_START(m_timers[Timers::Rhs]);
10220 RECORD_TIMER_START(m_timers[Timers::Muscl]);
10221
10222 RECORD_TIMER_START(m_timers[Timers::MusclReconst]);
10223 LSReconstructCellCenter();
10224 RECORD_TIMER_STOP(m_timers[Timers::MusclReconst]);
10225
10226 // copy the slopes from the master to the slave cells
10227 RECORD_TIMER_START(m_timers[Timers::MusclCopy]);
10228 m_fvBndryCnd->copySlopesToSmallCells();
10229 RECORD_TIMER_STOP(m_timers[Timers::MusclCopy]);
10230
10231 // update the ghost cell slopes for reconstruction of the primitive variables
10232 // on the surfaces for the AUSM scheme
10233 RECORD_TIMER_START(m_timers[Timers::MusclGhostSlopes]);
10234 m_fvBndryCnd->updateGhostCellSlopesInviscid();
10235 RECORD_TIMER_STOP(m_timers[Timers::MusclGhostSlopes]);
10236
10237 RECORD_TIMER_START(m_timers[Timers::MusclCutSlopes]);
10238 m_fvBndryCnd->updateCutOffSlopesInviscid();
10239 RECORD_TIMER_STOP(m_timers[Timers::MusclCutSlopes]);
10240 // m_fvBndryCnd->updateGhostCellSlopesViscous();
10241
10242 RECORD_TIMER_STOP(m_timers[Timers::Muscl]);
10243 RECORD_TIMER_STOP(m_timers[Timers::Rhs]);
10244
10245 RECORD_TIMER_START(m_timers[Timers::LhsBnd]);
10246 }
10247
10248 RECORD_TIMER_STOP(m_timers[Timers::LhsBnd]);
10249 RECORD_TIMER_STOP(m_timers[Timers::TimeInt]);
10250}
10251
10256template <MInt nDim_, class SysEqn>
10258 TRACE();
10259
10260 RECORD_TIMER_START(m_timers[Timers::TimeInt]);
10261 RECORD_TIMER_START(m_timers[Timers::LhsBnd]);
10262
10263#if defined _MB_DEBUG_ || !defined NDEBUG
10264 checkDiv();
10265#endif
10266
10267 if(m_noSpecies > 0) {
10268 scalarLimiter();
10269 }
10270
10271 RECORD_TIMER_START(m_timers[Timers::SmallCellCorr]);
10272 smallCellCorrection();
10273 RECORD_TIMER_STOP(m_timers[Timers::SmallCellCorr]);
10274 updateSplitParentVariables();
10275
10276#if defined _MB_DEBUG_
10277 checkDiv();
10278#endif
10279
10280 RECORD_TIMER_START(m_timers[Timers::ComputePV]);
10281 computePV();
10282 RECORD_TIMER_STOP(m_timers[Timers::ComputePV]);
10283
10284 RECORD_TIMER_START(m_timers[Timers::Exchange]);
10285 // periodic exchange (azimuthal periodicity concept)
10286 if(m_periodicCells == 3) {
10287 exchange();
10288 exchangePeriodic();
10289 }
10290
10291 // Cut-off cells are used for azimuthal reconstruction and for non cbc boundaries not part of smallcellcorrection
10292 if(grid().azimuthalPeriodicity()) {
10293 cutOffBoundaryCondition();
10294 if(!m_fvBndryCnd->m_cbcSmallCellCorrection) {
10295 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
10296 if(a_hasProperty(cellId, SolverCell::IsCutOff)) {
10297 sysEqn().computeConservativeVariables(&a_pvariable(cellId, 0), &a_variable(cellId, 0), 0);
10298 }
10299 }
10300 }
10301 }
10302
10303 if(g_splitMpiComm) {
10304 RECORD_TIMER_START(m_tcomm);
10305 RECORD_TIMER_START(m_texchange);
10306 startMpiExchange();
10307 RECORD_TIMER_STOP(m_texchange);
10308 RECORD_TIMER_STOP(m_tcomm);
10309 } else {
10310 exchange();
10311 }
10312 RECORD_TIMER_STOP(m_timers[Timers::Exchange]);
10313
10314 // periodic exchange (azimuthal periodicity concept)
10315 if(m_periodicCells == 1 || m_periodicCells == 2) {
10316 RECORD_TIMER_START(m_timers[Timers::CutOff]);
10317 cutOffBoundaryCondition();
10318 RECORD_TIMER_STOP(m_timers[Timers::CutOff]);
10319
10320 RECORD_TIMER_START(m_timers[Timers::Exchange]);
10321 exchangePeriodic();
10322 RECORD_TIMER_STOP(m_timers[Timers::Exchange]);
10323 }
10324
10325 if(!g_splitMpiComm) {
10326 // Note: if anything here is changed, make sure to apply the same changes in
10327 // lhsBndFinish()
10328 computePrimitiveVariablesCoarseGrid();
10329 // return command for non-combustion computations
10330
10331 RECORD_TIMER_START(m_timers[Timers::CutOff]);
10332 cutOffBoundaryCondition();
10333 RECORD_TIMER_STOP(m_timers[Timers::CutOff]);
10334
10335 RECORD_TIMER_START(m_timers[Timers::BndryCnd]);
10336 applyBoundaryCondition();
10337 RECORD_TIMER_STOP(m_timers[Timers::BndryCnd]);
10338
10339 computePrimitiveVariablesCoarseGrid();
10340 // return command for non-combustion computations
10341 // solver->computeConservativeVariables();
10342
10343 // Compute the cell center slopes here if changed slope calculation
10344 // activated
10345 if(calcSlopesAfterStep()) {
10346 RECORD_TIMER_STOP(m_timers[Timers::LhsBnd]);
10347
10348 RECORD_TIMER_START(m_timers[Timers::Rhs]);
10349 RECORD_TIMER_START(m_timers[Timers::Muscl]);
10350
10351 RECORD_TIMER_START(m_timers[Timers::MusclReconst]);
10352 LSReconstructCellCenter();
10353 RECORD_TIMER_STOP(m_timers[Timers::MusclReconst]);
10354
10355 // copy the slopes from the master to the slave cells
10356 RECORD_TIMER_START(m_timers[Timers::MusclCopy]);
10357 m_fvBndryCnd->copySlopesToSmallCells();
10358 RECORD_TIMER_STOP(m_timers[Timers::MusclCopy]);
10359
10360 // update the ghost cell slopes for reconstruction of the primitive variables
10361 // on the surfaces for the AUSM scheme
10362 RECORD_TIMER_START(m_timers[Timers::MusclGhostSlopes]);
10363 m_fvBndryCnd->updateGhostCellSlopesInviscid();
10364 RECORD_TIMER_STOP(m_timers[Timers::MusclGhostSlopes]);
10365
10366 RECORD_TIMER_START(m_timers[Timers::MusclCutSlopes]);
10367 m_fvBndryCnd->updateCutOffSlopesInviscid();
10368 RECORD_TIMER_STOP(m_timers[Timers::MusclCutSlopes]);
10369 // m_fvBndryCnd->updateGhostCellSlopesViscous();
10370
10371 RECORD_TIMER_STOP(m_timers[Timers::Muscl]);
10372 RECORD_TIMER_STOP(m_timers[Timers::Rhs]);
10373
10374 RECORD_TIMER_START(m_timers[Timers::LhsBnd]);
10375 }
10376 }
10377
10378 RECORD_TIMER_STOP(m_timers[Timers::LhsBnd]);
10379 RECORD_TIMER_STOP(m_timers[Timers::TimeInt]);
10380}
10381
10382
10384template <MInt nDim_, class SysEqn>
10385void FvCartesianSolverXD<nDim_, SysEqn>::getGlobalSolverVars(std::vector<MFloat>& globalFloatVars,
10386 std::vector<MInt>& NotUsed(globalIdVars)) {
10387 TRACE();
10388
10389 // Store global variables that need to be communicated during load balancing with inactive ranks
10390 globalFloatVars.push_back(m_time);
10391 globalFloatVars.push_back(m_timeStep);
10392 globalFloatVars.push_back(m_physicalTime);
10393 // TODO labels:FV,DLB any other variables to be communicated during DLB?
10394}
10395
10396
10398template <MInt nDim_, class SysEqn>
10399void FvCartesianSolverXD<nDim_, SysEqn>::setGlobalSolverVars(std::vector<MFloat>& globalFloatVars,
10400 std::vector<MInt>& NotUsed(globalIdVars)) {
10401 TRACE();
10402
10403 // Set variables in the same order as in getGlobalSolverVars()
10404 m_time = globalFloatVars[0];
10405 m_timeStep = globalFloatVars[1];
10406 m_physicalTime = globalFloatVars[2];
10407}
10408
10409
10414template <MInt nDim_, class SysEqn>
10415void FvCartesianSolverXD<nDim_, SysEqn>::getSolverTimings(std::vector<std::pair<MString, MFloat>>& solverTimings,
10416 const MBool allTimings) {
10417 TRACE();
10418
10419 const MString namePrefix = "b" + std::to_string(solverId()) + "_";
10420
10421 const MFloat load = returnLoadRecord();
10422 const MFloat idle = returnIdleRecord();
10423
10424 solverTimings.emplace_back(namePrefix + "loadFvCartesianSolver", load);
10425 solverTimings.emplace_back(namePrefix + "idleFvCartesianSolver", idle);
10426
10427#ifdef MAIA_TIMER_FUNCTION
10428 solverTimings.emplace_back(namePrefix + "timeIntegration", RETURN_TIMER_TIME(m_timers[Timers::TimeInt]));
10429
10430 if(allTimings) {
10431 // Full set of timings
10432 solverTimings.emplace_back(namePrefix + "rhs", RETURN_TIMER_TIME(m_timers[Timers::Rhs]));
10433 solverTimings.emplace_back(namePrefix + "MUSCL", RETURN_TIMER_TIME(m_timers[Timers::Muscl]));
10434 solverTimings.emplace_back(namePrefix + "reconstructCellCenter", RETURN_TIMER_TIME(m_timers[Timers::MusclReconst]));
10435 solverTimings.emplace_back(namePrefix + "reconstructSrfcData",
10436 RETURN_TIMER_TIME(m_timers[Timers::MusclReconstSrfc]));
10437 if(m_useSandpaperTrip) {
10438 solverTimings.emplace_back(namePrefix + "SandpaperTrip", RETURN_TIMER_TIME(m_timers[Timers::SandpaperTrip]));
10439 }
10440 if(m_wmLES) {
10441 solverTimings.emplace_back(namePrefix + "WMFluxCorrection",
10442 RETURN_TIMER_TIME(m_timers[Timers::WMFluxCorrection]));
10443 solverTimings.emplace_back(namePrefix + "WMSurfaceLoop", RETURN_TIMER_TIME(m_timers[Timers::WMSurfaceLoop]));
10444 solverTimings.emplace_back(namePrefix + "WMExchange", RETURN_TIMER_TIME(m_timers[Timers::WMExchange]));
10445 }
10446
10447 IF_CONSTEXPR(isDetChem<SysEqn>) {
10448 solverTimings.emplace_back(namePrefix + "SurfaceCoefficients",
10449 RETURN_TIMER_TIME(m_timers[Timers::SurfaceCoefficients]));
10450 solverTimings.emplace_back(namePrefix + "SurfaceMeanMolarWeight",
10451 RETURN_TIMER_TIME(m_timers[Timers::SurfaceMeanMolarWeight]));
10452 solverTimings.emplace_back(namePrefix + "SurfaceTransportCoefficients",
10453 RETURN_TIMER_TIME(m_timers[Timers::SurfaceTransportCoefficients]));
10454 solverTimings.emplace_back(namePrefix + "CellCenterCoefficients",
10455 RETURN_TIMER_TIME(m_timers[Timers::CellCenterCoefficients]));
10456 solverTimings.emplace_back(namePrefix + "SpeciesReactionRates",
10457 RETURN_TIMER_TIME(m_timers[Timers::SpeciesReactionRates]));
10458 }
10459
10460 solverTimings.emplace_back(namePrefix + "AUSM", RETURN_TIMER_TIME(m_timers[Timers::Ausm]));
10461 solverTimings.emplace_back(namePrefix + "viscFlux", RETURN_TIMER_TIME(m_timers[Timers::ViscFlux]));
10462 solverTimings.emplace_back(namePrefix + "distrFlux", RETURN_TIMER_TIME(m_timers[Timers::DistFlux]));
10463
10464 solverTimings.emplace_back(namePrefix + "rhsBnd", RETURN_TIMER_TIME(m_timers[Timers::RhsBnd]));
10465 solverTimings.emplace_back(namePrefix + "lhs", RETURN_TIMER_TIME(m_timers[Timers::Lhs]));
10466
10467 solverTimings.emplace_back(namePrefix + "lhsBnd", RETURN_TIMER_TIME(m_timers[Timers::LhsBnd]));
10468 solverTimings.emplace_back(namePrefix + "smallCellCorr", RETURN_TIMER_TIME(m_timers[Timers::SmallCellCorr]));
10469 solverTimings.emplace_back(namePrefix + "computePV", RETURN_TIMER_TIME(m_timers[Timers::ComputePV]));
10470 solverTimings.emplace_back(namePrefix + "exchange", RETURN_TIMER_TIME(m_timers[Timers::Exchange]));
10471 solverTimings.emplace_back(namePrefix + "cutOff", RETURN_TIMER_TIME(m_timers[Timers::CutOff]));
10472 solverTimings.emplace_back(namePrefix + "bndryCnd", RETURN_TIMER_TIME(m_timers[Timers::BndryCnd]));
10473 solverTimings.emplace_back(namePrefix + "SCC-init", RETURN_TIMER_TIME(m_timers[Timers::SCCorrInit]));
10474
10475 if(m_levelSetMb) {
10476 solverTimings.emplace_back(namePrefix + "SCC-Ex1", RETURN_TIMER_TIME(m_timers[Timers::SCCorrExchange1]));
10477 solverTimings.emplace_back(namePrefix + "SCC-Wait1", RETURN_TIMER_TIME(m_timers[Timers::SCCorrExchange1Wait]));
10478 solverTimings.emplace_back(namePrefix + "SCC-int", RETURN_TIMER_TIME(m_timers[Timers::SCCorrInterp]));
10479 solverTimings.emplace_back(namePrefix + "SCC-redist", RETURN_TIMER_TIME(m_timers[Timers::SCCorrRedist]));
10480 solverTimings.emplace_back(namePrefix + "SCC-Ex2", RETURN_TIMER_TIME(m_timers[Timers::SCCorrExchange2]));
10481 solverTimings.emplace_back(namePrefix + "SCC-wait2", RETURN_TIMER_TIME(m_timers[Timers::SCCorrExchange2Wait]));
10482 }
10483 } else {
10484 // TODO labels:FV,TIMERS Reduced/essential set of timings
10485 solverTimings.emplace_back(namePrefix + "smallCellCorr", RETURN_TIMER_TIME(m_timers[Timers::SmallCellCorr]));
10486 solverTimings.emplace_back(namePrefix + "exchange", RETURN_TIMER_TIME(m_timers[Timers::Exchange]));
10487 // solverTimings.emplace_back(namePrefix + "bndryCnd", RETURN_TIMER_TIME(m_timers[Timers::BndryCnd]));
10488 }
10489#endif
10490}
10491
10492
10494template <MInt nDim_, class SysEqn>
10496 // Inactive ranks do not have any data to communicate
10497 if(!isActive()) {
10498 return 0;
10499 }
10500
10501 // Convert to solver cell id and check
10502 const MInt cellId = grid().tree().grid2solver(gridCellId);
10503 if(cellId < 0 || cellId >= noInternalCells()) {
10504 return 0;
10505 }
10506
10507 MInt dataSize = 0;
10508
10509 switch(dataId) {
10510 case 0: // variables
10511 dataSize = CV->noVariables;
10512 break;
10513 /* case 1: // cell properties */
10514 /* dataSize = 1; */
10515 /* break; */
10516 default:
10517 mTerm(1, "Unknown data id.");
10518 break;
10519 }
10520
10521 return dataSize;
10522}
10523
10524
10525// \brief Apply the multilevel correction tau on a coarse level, i.e., add tau as a forcing to the
10526// right hand side
10527template <MInt nDim_, class SysEqn>
10529 TRACE();
10530
10531 const MInt _noInternalCells = grid().noInternalCells();
10532 const MInt noCVars = CV->noVariables;
10533 for(MInt cellId = 0; cellId < _noInternalCells; cellId++) {
10534 for(MInt varId = 0; varId < noCVars; varId++) {
10535 a_rightHandSide(cellId, varId) -= a_tau(cellId, varId);
10536 }
10537 }
10538}
10539
10540
10542template <MInt nDim_, class SysEqn>
10544 std::vector<MInt>& samplingVarIds, std::vector<MInt>& noSamplingVars,
10545 std::vector<std::vector<MString>>& samplingVarNames, const MString featureName) {
10546 TRACE();
10547
10548 // Read sampling variable names
10549 std::vector<MString> varNamesList;
10550 MInt noVars = readSolverSamplingVarNames(varNamesList, featureName);
10551
10552 // Set default sampling variables if none specified
10553 if(noVars == 0) {
10554 varNamesList.emplace_back("FV_PV");
10555 noVars = 1;
10556 }
10557
10558 for(MInt i = 0; i < noVars; i++) {
10559 const MInt samplingVar = string2enum(varNamesList[i]);
10560 std::vector<MString> varNames;
10561
10562 auto samplingVarIt = std::find(samplingVarIds.begin(), samplingVarIds.end(), samplingVar);
10563 if(samplingVarIt != samplingVarIds.end()) {
10564 mTerm(1, "Sampling variable '" + varNamesList[i] + "' already specified.");
10565 }
10566
10567 switch(samplingVar) {
10568 case FV_PV: {
10569 samplingVarIds.push_back(FV_PV);
10570 noSamplingVars.push_back(PV->noVariables);
10571
10572 varNames.resize(PV->noVariables);
10573 varNames[PV->U] = "u";
10574 varNames[PV->V] = "v";
10575 IF_CONSTEXPR(nDim == 3) { varNames[PV->W] = "w"; }
10576 varNames[PV->P] = "p";
10577 varNames[PV->RHO] = "rho";
10578 MInt varCount = nDim + 2;
10579
10580 IF_CONSTEXPR(isDetChem<SysEqn>) {
10581 if(PV->m_noSpecies > 0) {
10582 for(MUint s = 0; s < PV->m_noSpecies; s++) {
10583 MString str = ("Y" + m_speciesName[s]);
10584 MChar* c = new MChar[10];
10585 strcpy(c, str.c_str());
10586 varNames[PV->Y[s]] = c;
10587 varCount++;
10588 }
10589 }
10590 }
10591 else {
10592 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
10593 if(PV->m_noSpecies > 0) {
10594 varNames[PV->C] = "c";
10595 varCount++;
10596 }
10597 }
10598
10599 TERMM_IF_NOT_COND(PV->noVariables == varCount, "Error: variable count mismatch");
10600
10601 samplingVarNames.push_back(varNames);
10602 break;
10603 }
10604 // TODO labels:FV,PP add sampling of gradients?
10605 case FV_VORT: {
10606 // mTerm(1, "Sampling of vorticity not tested.");
10607 samplingVarIds.push_back(FV_VORT);
10608
10609 const MInt noVorticities = (nDim == 2) ? 1 : 3;
10610 noSamplingVars.push_back(noVorticities);
10611
10612 varNames.resize(noVorticities);
10613 IF_CONSTEXPR(nDim == 2) { varNames[0] = "vort_z"; }
10614 else {
10615 varNames[0] = "vort_x";
10616 varNames[1] = "vort_y";
10617 varNames[2] = "vort_z";
10618 }
10619 samplingVarNames.push_back(varNames);
10620
10621 break;
10622 }
10623 case FV_HEAT_RELEASE: {
10624 samplingVarIds.push_back(FV_HEAT_RELEASE);
10625 noSamplingVars.push_back(1);
10626 varNames.resize(1);
10627 varNames[0] = "h";
10628 samplingVarNames.push_back(varNames);
10629 break;
10630 }
10631 default: {
10632 mTerm(1, "Unknown sampling variable: " + varNamesList[i]);
10633 break;
10634 }
10635 }
10636 }
10637}
10638
10639
10641template <MInt nDim_, class SysEqn>
10643 const std::vector<MInt>& noSamplingVars) {
10644 TRACE();
10645
10646 m_samplingVariablesStatus.fill(-1);
10647
10648 // TODO labels:FV enable use with balancing
10649 for(MUint i = 0; i < varIds.size(); i++) {
10650 // No additional storage for primitive variables
10651 if(varIds[i] == FV_PV) {
10652 continue;
10653 }
10654 // Storage for sampling variable already allocated
10655 if(m_samplingVariables[varIds[i]] != nullptr) {
10656 continue;
10657 }
10658
10659 MFloat** varPointer = nullptr;
10660 const MInt dataBlockSize = noSamplingVars[i];
10661 mAlloc(varPointer, a_noCells(), dataBlockSize, "m_samplingVariables_" + std::to_string(varIds[i]), 0.0, AT_);
10662 m_samplingVariables[varIds[i]] = varPointer;
10663 }
10664}
10665
10666
10669template <MInt nDim_, class SysEqn>
10670void FvCartesianSolverXD<nDim_, SysEqn>::calcSamplingVariables(const std::vector<MInt>& varIds, const MBool exchange) {
10671 for(MUint i = 0; i < varIds.size(); i++) {
10672 const MInt varId = varIds[i];
10673 // Note: calcSamplingVariables() can be called from multiple features, check if sampling variable is already
10674 // computed and exchanged for this time step
10675 const MInt statusCurr = globalTimeStep;
10676 const MInt statusCalc = m_samplingVariablesStatus[2 * varId];
10677 const MInt statusExchange = m_samplingVariablesStatus[2 * varId + 1];
10678 TERMM_IF_COND(statusExchange == statusCurr && statusCalc != statusCurr,
10679 "Error: invalid compute/exchange order " + std::to_string(statusCurr) + " "
10680 + std::to_string(statusCalc) + " " + std::to_string(statusExchange));
10681
10682 switch(varId) {
10683 case FV_PV: {
10684 // Nothing to do
10685 break;
10686 }
10687 case FV_VORT: {
10688 MFloat* vortPointer = m_samplingVariables[varId][0];
10689 if(statusCurr != statusCalc) { // Check if already computed for the current time step
10690 m_log << "DEBUG calcSamplingVariables calc FV_VORT " << statusCurr << " " << statusCalc << std::endl;
10691 IF_CONSTEXPR(nDim == 3) { computeVorticity3DT(vortPointer); }
10692 else {
10693 computeVorticity2D(vortPointer);
10694 }
10695 m_samplingVariablesStatus[2 * varId] = statusCurr; // update computed status
10696 }
10697 // Exchange data on window/halo cells if requested (e.g. for least squares interpolation)
10698 if(exchange && statusCurr != statusExchange) { // check if already exchanged for the current time step
10699 constexpr MInt noVort = (nDim == 2) ? 1 : 3;
10700 exchangeDataFV(vortPointer, noVort);
10701 m_samplingVariablesStatus[2 * varId + 1] = statusCurr; // update exchanged status
10702 }
10703 break;
10704 }
10705 case FV_HEAT_RELEASE: {
10706 // heat release should already be computed
10707 break;
10708 }
10709 default: {
10710 mTerm(1, "Invalid variable id");
10711 break;
10712 }
10713 }
10714 }
10715}
10716
10717
10724template <MInt nDim_, class SysEqn>
10725void FvCartesianSolverXD<nDim_, SysEqn>::sensorEntropyGrad(std::vector<std::vector<MFloat>>& sensors,
10726 std::vector<std::bitset<64>>& sensorCellFlag,
10727 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
10728 MInt sen) {
10729 m_log << " - Sensor preparation for the entropy sensor" << endl;
10730
10731 // weightings depending on the refinement
10732 ScratchSpace<MFloat> lengthFactor(maxRefinementLevel() + 1, AT_, "lengthFactor");
10733 for(MInt l = 0; l <= maxRefinementLevel(); l++)
10734 lengthFactor.p[l] = pow(c_cellLengthAtLevel(l), F3B2);
10735
10736 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
10737 ASSERT(!c_isToDelete(cellId), "");
10738 // skip all unnecessary cells
10739 if(a_bndryId(cellId) != -1) continue;
10740 if(a_isBndryGhostCell(cellId)) continue;
10741 if(c_noChildren(cellId) > 0) continue;
10742 if(a_isHalo(cellId)) continue;
10743
10744 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10745 // if ( a_hasProperty( cellId , SolverCell::WasInactive ) ) continue;
10746
10747 // shortcuts
10748 const MInt level = a_level(cellId);
10749 const MInt gridId = grid().tree().solver2grid(cellId);
10750
10751 // compute the magnitude of the temperature gradient (stored in PV->P)
10752 MFloat a2 = sysEqn().temperature_ES(a_pvariable(cellId, PV->RHO), a_pvariable(cellId, PV->P));
10753 MFloat tau = F0;
10754 for(MInt i = 0; i < nDim; i++) {
10755 tau += POW2(a_slope(cellId, PV->P, i) - a_slope(cellId, PV->RHO, i) * a2);
10756 }
10757 tau = sqrt(tau);
10758 tau *= lengthFactor.p[level];
10759 sensors[sensorOffset + sen][gridId] = tau;
10760 sensorCellFlag[gridId][sensorOffset + sen] = 1;
10761 }
10762
10763 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
10764}
10765
10772template <MInt nDim_, class SysEqn>
10773void FvCartesianSolverXD<nDim_, SysEqn>::sensorEntropyQuot(std::vector<std::vector<MFloat>>& sensors,
10774 std::vector<std::bitset<64>>& sensorCellFlag,
10775 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
10776 MInt sen) {
10777 m_log << " - Sensor preparation for the entropy sensor" << endl;
10778
10779 // weightings depending on the refinement
10780 ScratchSpace<MFloat> lengthFactor(maxRefinementLevel() + 1, AT_, "lengthFactor");
10781 for(MInt l = 0; l <= maxRefinementLevel(); l++)
10782 lengthFactor.p[l] = pow(c_cellLengthAtLevel(l), F3B2);
10783
10784 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
10785 ASSERT(!c_isToDelete(cellId), "");
10786 // skip all unnecessary cells
10787 if(a_bndryId(cellId) != -1) continue;
10788 if(a_isBndryGhostCell(cellId)) continue;
10789 if(c_noChildren(cellId) > 0) continue;
10790 if(a_isHalo(cellId)) continue;
10791
10792 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10793 // if ( a_hasProperty( cellId , SolverCell::WasInactive ) ) continue;
10794
10795 // shortcuts
10796 const MInt level = a_level(cellId);
10797 const MInt gridId = grid().tree().solver2grid(cellId);
10798
10799 MFloat tau = F0;
10800 tau = pow(mMax(F0, ((entropy(cellId) - m_SInfinity) / m_SInfinity)), 1.2);
10801 tau *= lengthFactor.p[level];
10802 sensors[sensorOffset + sen][gridId] = tau;
10803 sensorCellFlag[gridId][sensorOffset + sen] = 1;
10804 }
10805
10806 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
10807}
10808
10815template <MInt nDim_, class SysEqn>
10816void FvCartesianSolverXD<nDim_, SysEqn>::sensorVorticity(std::vector<std::vector<MFloat>>& sensors,
10817 std::vector<std::bitset<64>>& sensorCellFlag,
10818 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
10819 MInt sen) {
10820 m_log << " - Sensor preparation for the vorticity sensor" << endl;
10821
10822 // weightings depending on the refinement
10823 ScratchSpace<MFloat> lengthFactor(maxRefinementLevel() + 1, AT_, "lengthFactor");
10824 for(MInt l = 0; l <= maxRefinementLevel(); l++)
10825 lengthFactor.p[l] = pow(c_cellLengthAtLevel(l), F3B2);
10826
10827 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
10828 ASSERT(!c_isToDelete(cellId), "");
10829
10830 // skip all unnecessary cells
10831 if(a_bndryId(cellId) != -1) continue;
10832 if(a_isBndryGhostCell(cellId)) continue;
10833 if(c_noChildren(cellId) > 0) continue;
10834 if(a_isHalo(cellId)) continue;
10835 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10836 // if ( a_hasProperty( cellId , SolverCell::WasInactive ) ) continue;
10837
10838 // shortcuts
10839 const MInt level = a_level(cellId);
10840 const MInt gridId = this->grid().tree().solver2grid(cellId);
10841
10842 MFloat tau = F0;
10843 if(m_euler) {
10844 tau = sqrt(mMax(F1, (entropy(cellId) / m_SInfinity))) - F1;
10845 } else {
10846 IF_CONSTEXPR(nDim == 2) { tau = fabs(a_slope(cellId, PV->V, 0) - a_slope(cellId, PV->U, 1)); }
10847 else {
10848 tau = sqrt(POW2(a_slope(cellId, PV->W, 1) - a_slope(cellId, PV->V, 2))
10849 + POW2(a_slope(cellId, PV->U, 2) - a_slope(cellId, PV->W, 0))
10850 + POW2(a_slope(cellId, PV->V, 0) - a_slope(cellId, PV->U, 1)));
10851 }
10852 }
10853
10854 tau *= lengthFactor.p[level];
10855 sensors[sensorOffset + sen][gridId] = tau;
10856 sensorCellFlag[gridId][sensorOffset + sen] = true;
10857 }
10858
10859 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
10860}
10861
10882template <MInt nDim_, class SysEqn>
10883void FvCartesianSolverXD<nDim_, SysEqn>::sensorDerivative(std::vector<std::vector<MFloat>>& sensors,
10884 std::vector<std::bitset<64>>& sensorCellFlag,
10885 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
10886 MInt sen) {
10887 m_log << " - Sensor preparation for the derivative sensor" << endl;
10888
10889 // weightings depending on the refinement
10890 ScratchSpace<MFloat> lengthFactor(maxRefinementLevel() + 1, AT_, "lengthFactor");
10891 for(MInt l = 0; l <= maxRefinementLevel(); l++) {
10892 lengthFactor[l] = pow(c_cellLengthAtLevel(l), F3B2);
10893 }
10894
10895 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
10896 ASSERT(!c_isToDelete(cellId), "");
10897
10898 // skip all unnecessary cells
10899 if(a_bndryId(cellId) != -1) continue;
10900 if(a_isBndryGhostCell(cellId)) continue;
10901 if(c_noChildren(cellId) > 0) continue;
10902 if(a_isHalo(cellId)) continue;
10903
10904 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
10905 // if ( a_hasProperty( cellId , SolverCell::WasInactive ) ) continue;
10906
10907 if(a_level(cellId) > this->m_maxSensorRefinementLevel[sen]) {
10908 continue;
10909 }
10910
10911 const MInt gridId = this->grid().tree().solver2grid(cellId);
10912
10913 // skip cells outside the bore
10914 if(m_engineSetup) {
10915 if(a_coordinate(cellId, 0) < -0.5 || a_coordinate(cellId, 0) > 0.5) continue;
10916 }
10917
10918 MFloat tau = F0;
10919
10920 // option to trigger velocity magnitude gradient!
10921 if((MInt)this->m_sensorDerivativeVariables[sen] == 10) {
10922 MFloat gradMax = F0;
10923 for(MInt d = 0; d < nDim; d++) {
10924 MFloat grad = 0;
10925 for(MInt i = 0; i < nDim; i++) {
10926 grad += POW2(a_slope(cellId, PV->VV[d], i));
10927 }
10928 if(grad > gradMax) gradMax = grad;
10929 }
10930 tau = sqrt(gradMax);
10931 } else if((MInt)this->m_sensorDerivativeVariables[sen] == 9) {
10932 // largest species gradient if species above 0.001
10933 if(a_pvariable(cellId, PV->Y[0]) > 0.001) {
10934 MFloat gradMax = F0;
10935 for(MInt d = 0; d < nDim; d++) {
10936 MFloat grad = 0;
10937 for(MInt i = 0; i < nDim; i++) {
10938 grad += POW2(a_slope(cellId, PV->Y[0], i));
10939 }
10940 if(grad > gradMax) gradMax = grad;
10941 }
10942 tau = sqrt(gradMax);
10943 }
10944
10945 } else {
10946 // compute the magnitude of the gradient
10947 for(MInt d = 0; d < nDim; d++) {
10948 MFloat grad = a_slope(cellId, this->m_sensorDerivativeVariables[sen], d);
10949 tau += POW2(grad);
10950 }
10951 tau = sqrt(tau);
10952 }
10953
10954 tau *= lengthFactor[a_level(cellId)];
10955
10956 sensors[sensorOffset + sen][gridId] = tau;
10957 sensorCellFlag[gridId][sensorOffset + sen] = true;
10958 }
10959
10960 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
10961}
10962
10963template <MInt nDim_, class SysEqn>
10964void FvCartesianSolverXD<nDim_, SysEqn>::sensorSpecies(std::vector<std::vector<MFloat>>& sensors,
10965 std::vector<std::bitset<64>>& sensorCellFlag,
10966 std::vector<MFloat>& sensorWeight, MInt sensorOffset, MInt sen) {
10967 TRACE();
10968
10976 MFloat speciesLimit = 0.0001;
10977 speciesLimit = Context::getSolverProperty<MFloat>("speciesConLimit", m_solverId, AT_, &speciesLimit);
10978
10979 std::function<MFloat(const MInt)> species = [&](const MInt cellId) { return a_pvariable(cellId, PV->Y[0]); };
10980
10982 sensors, sensorCellFlag, sensorWeight, sensorOffset, sen, species, speciesLimit, &m_bandWidth[0],
10983 m_refineDiagonals);
10984
10985 // reset sensor for inactive cells and outside engine
10986 if(m_levelSetMb) {
10987 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
10988 if(m_linerLvlJump && (a_coordinate(cellId, 0) < -0.515 || a_coordinate(cellId, 0) > 0.515)) {
10989 const MInt gridCellId = grid().tree().solver2grid(cellId);
10990 if(sensors[sensorOffset + sen][gridCellId] > 0) {
10991 sensors[sensorOffset + sen][gridCellId] = 0;
10992 sensorCellFlag[gridCellId][sensorOffset + sen] = false;
10993 }
10994 }
10995 if(!a_isInactive(cellId)) continue;
10996 if(a_levelSetValuesMb(cellId, 0) > -(m_maxLsValue - m_eps)) continue;
10997 const MInt gridCellId = grid().tree().solver2grid(cellId);
10998 if(sensors[sensorOffset + sen][gridCellId] > 0) {
10999 sensors[sensorOffset + sen][gridCellId] = 0;
11000 sensorCellFlag[gridCellId][sensorOffset + sen] = false;
11001 }
11002 }
11003 }
11004}
11005
11013template <MInt nDim_, class SysEqn>
11014void FvCartesianSolverXD<nDim_, SysEqn>::sensorParticle(std::vector<std::vector<MFloat>>& sensors,
11015 std::vector<std::bitset<64>>& sensorCellFlag,
11016 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
11017 MInt sen) {
11018 static constexpr MInt particleLimit = 1;
11019
11020 std::function<MFloat(const MInt)> noPart = [&](const MInt cellId) { return static_cast<MFloat>(a_noPart(cellId)); };
11021
11023 sensors, sensorCellFlag, sensorWeight, sensorOffset, sen, noPart, particleLimit, &m_particleWidth[0],
11024 m_refineDiagonals);
11025
11026 // reset sensor for inactive cells and outside engine
11027 if(m_levelSetMb) {
11028 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
11029 if(m_engineSetup && (a_coordinate(cellId, 0) < -0.515 || a_coordinate(cellId, 0) > 0.515)) {
11030 const MInt gridCellId = grid().tree().solver2grid(cellId);
11031 if(sensors[sensorOffset + sen][gridCellId] > 0) {
11032 sensors[sensorOffset + sen][gridCellId] = 0;
11033 sensorCellFlag[gridCellId][sensorOffset + sen] = false;
11034 }
11035 }
11036 if(!a_isInactive(cellId)) continue;
11037 if(a_levelSetValuesMb(cellId, 0) > -(m_maxLsValue - m_eps)) continue;
11038 const MInt gridCellId = grid().tree().solver2grid(cellId);
11039 if(sensors[sensorOffset + sen][gridCellId] > 0) {
11040 sensors[sensorOffset + sen][gridCellId] = 0;
11041 sensorCellFlag[gridCellId][sensorOffset + sen] = false;
11042 }
11043 }
11044 }
11045}
11046
11051template <MInt nDim_, class SysEqn>
11053 MBoolScratchSpace interfaceCell(a_noCells(), AT_, "interfaceCell");
11054 interfaceCell.fill(0);
11055 vector<MInt> bndCndIds;
11056 bndCndIds.push_back(3003);
11057
11058 this->identifyBoundaryCells(&interfaceCell[0], bndCndIds);
11059
11060 this->setBoundaryDistance(&interfaceCell[0], &m_outerBandWidth[0], distance);
11061
11062 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
11063 // Fix for partition level shift, start reduce operation at internal cell with a halo parent
11064 const MInt parentId = c_parentId(cellId);
11065 const MBool isPartLvlShift = (parentId > -1 && a_isHalo(parentId));
11066
11067 if(a_level(cellId) != minLevel() && !isPartLvlShift) {
11068 continue;
11069 }
11070 // @ansgar PLA TODO labels:FV
11071 // this does not properly reduces the distance for internal pla cells with halo childs!
11072 // reduce starting from partition cells and ignore partition level ancestors?
11073 reduceData(cellId, &distance(0));
11074 }
11075 exchangeDataFV(distance.data());
11076}
11077
11078
11083template <MInt nDim_, class SysEqn>
11085 const MBool average) {
11086 MFloat vol = a_cellVolume(cellId);
11087 if(c_noChildren(cellId) > 0) {
11088 vol = F0;
11089 for(MInt d = 0; d < dataBlockSize; d++) {
11090 data[dataBlockSize * cellId + d] = F0;
11091 }
11092 for(MInt child = 0; child < IPOW2(nDim); child++) {
11093 MInt childId = c_childId(cellId, child);
11094 if(childId < 0) continue;
11095 if(c_noChildren(childId) == 0 && !a_hasProperty(childId, SolverCell::IsOnCurrentMGLevel)) continue;
11096 MFloat volc = reduceData(childId, data, dataBlockSize);
11097 for(MInt d = 0; d < dataBlockSize; d++) {
11098 data[dataBlockSize * cellId + d] += volc * data[dataBlockSize * childId + d];
11099 }
11100 vol += volc;
11101 }
11102 if(average) {
11103 for(MInt d = 0; d < dataBlockSize; d++) {
11104 data[dataBlockSize * cellId + d] /= mMax(1e-14, vol);
11105 }
11106 }
11107 }
11108 return vol;
11109}
11110
11111// --------------------------------------------------------------------------------------
11112
11117template <MInt nDim_, class SysEqn>
11119 TRACE();
11120
11121 NEW_TIMER_GROUP_STATIC(tg_solutionStep, "solution step");
11122 NEW_TIMER_STATIC(t_solutionStep, "solution step", tg_solutionStep);
11123 NEW_SUB_TIMER_STATIC(t_timeIntegration, "time integration", t_solutionStep);
11124 NEW_SUB_TIMER_STATIC(t_lhs, "lhs", t_timeIntegration);
11125 NEW_SUB_TIMER_STATIC(t_lhsBnd, "lhsBnd", t_timeIntegration);
11126 NEW_SUB_TIMER_STATIC(t_rhs, "rhs", t_timeIntegration);
11127 NEW_SUB_TIMER_STATIC(t_rhsBnd, "rhsBnd", t_timeIntegration);
11128
11130 RECORD_TIMER_START(t_solutionStep);
11131 RECORD_TIMER_START(t_timeIntegration);
11132
11133 // Split MPI communication: finish MPI exchange if needed and perform
11134 // the left out part from lhsBnd()
11135 if(g_splitMpiComm && m_splitMpiCommRecv) {
11136 RECORD_TIMER_START(t_lhsBnd);
11137 lhsBndFinish();
11138 RECORD_TIMER_STOP(t_lhsBnd);
11139 }
11140 // Receive data in the next substep
11141 m_splitMpiCommRecv = true;
11142
11144 RECORD_TIMER_START(t_rhs);
11145 rhs();
11146 RECORD_TIMER_STOP(t_rhs);
11147
11149 RECORD_TIMER_START(t_rhsBnd);
11150 rhsBnd();
11151 RECORD_TIMER_STOP(t_rhsBnd);
11152
11154 RECORD_TIMER_START(t_lhs);
11155 const MBool timeStepCompleted = solverStep();
11156 RECORD_TIMER_STOP(t_lhs);
11157
11159 RECORD_TIMER_START(t_lhsBnd);
11160 lhsBnd();
11161 RECORD_TIMER_STOP(t_lhsBnd);
11162
11163 RECORD_TIMER_STOP(t_timeIntegration);
11164 RECORD_TIMER_STOP(t_solutionStep);
11165
11166 return timeStepCompleted;
11167}
11168
11169
11174template <MInt nDim_, class SysEqn>
11176 TRACE();
11177
11178 if(m_calcLESAverage) {
11179 calcLESAverage();
11180 if(globalTimeStep % m_restartInterval == 0) {
11181 saveLESAverage();
11182 }
11183 }
11184 if(m_STGSponge || m_preliminarySponge) {
11185 calcPeriodicSpongeAverage();
11186 }
11187 if(globalTimeStep >= m_stgSpongeTimeStep && m_STGSponge && globalTimeStep % m_restartInterval == 0) {
11188 saveSpongeData();
11189 }
11190 m_timeStepConverged = maxResidual();
11191
11192 if(g_splitMpiComm && m_splitMpiCommRecv) {
11193 // Finish MPI communication in split MPI mode after completed timestep
11194 lhsBndFinish();
11195 // At the beginning of the next timestep there is nothing to receive
11196 m_splitMpiCommRecv = false;
11197 }
11198
11199 m_forceAdaptation = adaptationTrigger();
11200}
11201
11202//----------------------------------------------------------------------------
11203
11204
11209template <MInt nDim_, class SysEqn>
11211 TRACE();
11212 if(m_isEEGas) return;
11213
11214 if(m_hasExternalSource) return;
11215
11216 const MInt noCVars = CV->noVariables;
11217 MInt cellId;
11218 auto* var = (MFloat*)(&(a_variable(0, 0)));
11219 // auto* pvar = (MFloat*)(&(a_pvariable(0, 0)));
11220
11221 for(MInt id = 0; id < m_noActiveCells; id++) {
11222 cellId = m_activeCellIds[id];
11223 for(MInt i = 0; i < m_noSpecies; i++)
11224 var[cellId * noCVars + CV->RHO_Y[i]] =
11225 mMin(var[cellId * noCVars + CV->RHO], mMax(var[cellId * noCVars + CV->RHO_Y[i]], F0));
11226 }
11227}
11228
11229template <MInt nDim_, class SysEqn>
11231 const MFloat dt = timeStep(true);
11232 m_time -= dt;
11233 m_physicalTime -= dt * m_timeRef;
11234 m_RKStep = 0;
11235}
11236
11237template <MInt nDim_, class SysEqn>
11239 TRACE();
11240
11241#ifdef _OPENMP
11242#pragma omp parallel for collapse(2)
11243#endif
11244 // Set implicit coefficient to zero
11245 for(MInt i = 0; i < a_noCells(); i++) {
11246 for(MInt j = 0; j < 2 * nDim; j++) {
11247 a_implicitCoefficient(i, j) = F0;
11248 }
11249 }
11250}
11251
11252template <MInt nDim_, class SysEqn>
11253template <class _, std::enable_if_t<isEEGas<SysEqn>, _*>>
11255 TRACE();
11256 if(nDim != 3) mTerm(1, AT_, "nDim has to be 3 for EEGas simulations");
11257
11258 // gas mass source
11259 if(m_EEGas.gasSource != 0) {
11260 for(auto& sourceCell : m_EEGas.gasSourceCells) {
11261 a_rightHandSide(sourceCell, CV->A_RHO) -= m_EEGas.massSource * a_cellVolume(sourceCell);
11262 }
11263 }
11264
11265// adapted from computeVolumeForces()
11266// Gravity
11267#ifdef _OPENMP
11268#pragma omp parallel for
11269#endif
11270 for(MInt ac = 0; ac < m_noActiveCells; ac++) {
11271 for(MInt i = 0; i < nDim; i++) {
11272 a_rightHandSide(m_activeCellIds[ac], CV->A_RHO_VV[i]) -=
11273 a_pvariable(m_activeCellIds[ac], PV->RHO) * m_volumeAcceleration[i] * a_cellVolume(m_activeCellIds[ac])
11274 * a_pvariable(m_activeCellIds[ac], PV->A);
11275 IF_CONSTEXPR(hasE<SysEqn>)
11276 a_rightHandSide(m_activeCellIds[ac], CV->A_RHO_E) -=
11277 a_pvariable(m_activeCellIds[ac], PV->VV[i]) * a_pvariable(m_activeCellIds[ac], PV->RHO)
11278 * m_volumeAcceleration[i] * a_cellVolume(m_activeCellIds[ac]) * a_pvariable(m_activeCellIds[ac], PV->A);
11279 }
11280 }
11281
11282
11283 // Interface forces between bubbles and liquid
11284 static const MFloat Eo_factor = m_EEGas.Eo0 / (m_EEGas.liquidDensity - m_rhoInfinity);
11285 const MFloat F_D_factor = F3B4 * m_EEGas.liquidDensity / m_EEGas.bubbleDiameter; // = 3/4 * rho_l / d_B
11286 const MFloat F1Bdt = F1 / timeStep(true);
11287 const MFloat F1BdtLiquid =
11288 F1
11289 / (timeStep(true)
11290 * (m_EEGas.interpolationFactor > 0.0 ? m_EEGas.interpolationFactor * m_RKalpha[m_RKStep] : 1.0));
11291 const MFloat* const RESTRICT cellVol = &a_cellVolume(0);
11292#ifdef _OPENMP
11293#pragma omp parallel for
11294#endif
11295 for(MInt ac = 0; ac < m_noActiveCells; ac++) {
11296 const MInt cellId = m_activeCellIds[ac];
11297 if(a_isBndryGhostCell(cellId)) continue;
11298 MFloat F_D_factorCell = 0.0;
11299 MFloat C_D = 0.0;
11300 if(m_EEGas.dragModel == 0) {
11301 const MFloat Eo = Eo_factor * (m_EEGas.liquidDensity - a_pvariable(cellId, PV->RHO)); // Eotvos number
11302 C_D = F2B3 * sqrt(Eo); // only valid in regime of distorted bubbles (see Mohammadi et al. 2019)
11303 F_D_factorCell = F_D_factor * C_D;
11304 } else if(m_EEGas.dragModel == 1) {
11305 MFloat uSlip = 0.0;
11306 for(MInt i = 0; i < nDim; i++) {
11307 uSlip = mMax(uSlip, abs(a_uOtherPhase(cellId, i) - a_pvariable(cellId, PV->VV[i])));
11308 }
11309 const MFloat nu_l = a_nuEffOtherPhase(cellId) - a_nuTOtherPhase(cellId);
11310 const MFloat l_bubbleDiameter = m_EEGas.bubbleDiameter;
11311 C_D = 24.0 * nu_l / (sysEqn().m_Re0 * uSlip * l_bubbleDiameter);
11312 F_D_factorCell = F_D_factor * C_D;
11313 } else if(m_EEGas.dragModel == 2) {
11314 C_D = m_EEGas.CD;
11315 F_D_factorCell = F_D_factor * C_D;
11316 } else if(m_EEGas.dragModel == 3) {
11317 F_D_factorCell = a_alphaGas(cellId) * 18.0 / sysEqn().m_Re0
11318 * (a_nuEffOtherPhase(cellId) - a_nuTOtherPhase(cellId)) * m_EEGas.liquidDensity
11319 / mMin(10.0, 1 - a_alphaGas(cellId)) / m_EEGas.bubbleDiameter / m_EEGas.bubbleDiameter;
11320 }
11321
11322 MFloat u_d[3];
11323 MFloat liftV[3];
11324 for(MInt i = 0; i < 3; i++) {
11325 u_d[i] = a_pvariable(cellId, PV->VV[i]) - a_uOtherPhase(cellId, i);
11326 }
11327 maia::math::cross(&u_d[0], &a_vortOtherPhase(cellId, 0), &liftV[0]);
11328
11329 const MFloat F_L_factorCell = m_EEGas.CL * a_alphaGas(cellId) * m_EEGas.liquidDensity;
11330
11331 MFloat F1BOldrhoAlpha = F0;
11332 if(a_oldVariable(cellId, CV->A_RHO) > -m_EEGas.eps) {
11333 F1BOldrhoAlpha = F1 / max(m_EEGas.eps, a_oldVariable(cellId, CV->A_RHO));
11334 } else {
11335 F1BOldrhoAlpha = F1 / a_oldVariable(cellId, CV->A_RHO);
11336 }
11337 const MFloat F_VM_factorCell = 0.5 * a_alphaGas(cellId) * m_EEGas.liquidDensity;
11338
11339 const MFloat Sc = m_EEGas.schmidtNumber; // Schmidt number
11340 MFloat F_TD_factorCell = 0.0;
11341 if(m_EEGas.dragModel == 3) {
11342 F_TD_factorCell = -18.0 / sysEqn().m_Re0 / sysEqn().m_Re0 / Sc * m_EEGas.liquidDensity / m_EEGas.bubbleDiameter
11343 / m_EEGas.bubbleDiameter * a_nuEffOtherPhase(cellId)
11344 * (a_nuEffOtherPhase(cellId) - a_nuTOtherPhase(cellId)) / mMin(10.0, 1 - a_alphaGas(cellId));
11345 } else {
11346 F_TD_factorCell = -F1 / sysEqn().m_Re0 * F_D_factorCell / Sc * a_nuEffOtherPhase(cellId);
11347 }
11348
11349 const MInt dragModel = m_EEGas.dragModel;
11350
11351 const MFloat C_D0 = F_D_factorCell * m_EEGas.RKSemiImplicitFactor;
11352 const MFloat dt = timeStep(true) * m_RKalpha[m_RKStep];
11353 const MFloat C_VM0 = F_VM_factorCell / dt * m_EEGas.RKSemiImplicitFactor;
11354
11355 for(MInt i = 0; i < nDim; i++) {
11356 // Calculation of the implicit coefficients
11357 MFloat C_D1, C_D2;
11358 const MInt sign = (0.0 < (-u_d[i])) - ((-u_d[i]) < 0.0);
11359 if(dragModel == 3) {
11360 C_D1 = C_D0 * a_uOtherPhase(cellId, i);
11361 C_D2 = -C_D0;
11362 } else {
11363 C_D1 =
11364 C_D0 * a_alphaGas(cellId) * sign * (POW2(a_uOtherPhase(cellId, i)) - POW2(a_pvariable(cellId, PV->VV[i])));
11365 C_D2 = 2.0 * C_D0 * a_alphaGas(cellId) * sign * u_d[i];
11366 }
11367 const MFloat gradAlpha = a_slope(cellId, PV->A, i);
11368 const MFloat C_TD0 = -F1 / sysEqn().m_Re0 * C_D0 / Sc * a_nuEffOtherPhase(cellId) * gradAlpha;
11369 MFloat C_TD1, C_TD2;
11370 if(dragModel == 3) {
11371 C_TD1 = 0.0;
11372 C_TD2 = 0.0;
11373 } else {
11374 C_TD1 = C_TD0 * a_uOtherPhase(cellId, i) * sign;
11375 C_TD2 = -C_TD0 * sign;
11376 }
11377 const MFloat C_VM1 = C_VM0 * a_pvariable(cellId, PV->VV[i]);
11378 const MFloat C_VM2 = -C_VM0;
11379 a_implicitCoefficient(cellId, i * 2) = (C_D1 + C_TD1 + C_VM1) * cellVol[cellId];
11380 a_implicitCoefficient(cellId, i * 2 + 1) = (C_D2 + C_TD2 + C_VM2) * cellVol[cellId];
11381 // Drag force
11382 MFloat F_D = 0.0;
11383 if(m_EEGas.dragModel == 3) {
11384 F_D = F_D_factorCell * -u_d[i];
11385 } else {
11386 F_D = F_D_factorCell * a_alphaGas(cellId) * -u_d[i] * abs(u_d[i]);
11387 }
11388
11389 // Lift force
11390 // Mohammadi et al. 2019
11391 const MFloat F_L = F_L_factorCell * liftV[i];
11392
11393 // buoyancy force
11394 // F_B = - alpha_g * rho_l * g_vec
11395 const MFloat F_B =
11396 m_EEGas.depthCorrection ? -a_alphaGas(cellId) * m_EEGas.liquidDensity * m_EEGas.gravity[i] : 0.0;
11397
11398 // Virtual mass force
11399 // Mohammadi et al. 2019
11400 MFloat duOtherPhaseDt = (a_uOtherPhase(cellId, i) - a_uOtherPhaseOld(cellId, i)) * F1BdtLiquid;
11401 MFloat duDt = 0.0;
11402 if(m_RKStep == 0) {
11403 duDt = (a_pvariable(cellId, PV->VV[i]) - a_oldVariable(cellId, CV->A_RHO_VV[i]) * F1BOldrhoAlpha) * F1Bdt;
11404 } else {
11405 duDt = (a_pvariable(cellId, PV->VV[i]) - a_oldVariable(cellId, CV->A_RHO_VV[i]) * F1BOldrhoAlpha) * F1Bdt
11406 / m_RKalpha[m_RKStep - 1];
11407 }
11408 const MFloat F_VM_I = (F1BOldrhoAlpha > F1 / m_EEGas.eps * 0.999 || F1BOldrhoAlpha < -F1 / m_EEGas.eps * 0.999)
11409 ? 0.0
11410 : -F_VM_factorCell * duDt;
11411 const MFloat F_VM_E = F_VM_factorCell
11412 * ((duOtherPhaseDt + a_uOtherPhase(cellId, 0) * a_gradUOtherPhase(cellId, i, 0)
11413 + a_uOtherPhase(cellId, 1) * a_gradUOtherPhase(cellId, i, 1)
11414 + a_uOtherPhase(cellId, 2) * a_gradUOtherPhase(cellId, i, 2))
11415 - (a_pvariable(cellId, PV->VV[0]) * a_slope(cellId, PV->VV[i], 0)
11416 + a_pvariable(cellId, PV->VV[1]) * a_slope(cellId, PV->VV[i], 1)
11417 + a_pvariable(cellId, PV->VV[2]) * a_slope(cellId, PV->VV[i], 2)));
11418
11419 // Turbulent dispersion force
11420 // Mohammadi et al. 2019
11421 MFloat F_TD = 0.0;
11422 if(m_EEGas.dragModel == 3) {
11423 F_TD = F_TD_factorCell * a_slope(cellId, PV->A, i);
11424 } else {
11425 F_TD = F_TD_factorCell * abs(u_d[i]) * a_slope(cellId, PV->A, i);
11426 }
11427 const MFloat explicitFF = 1.0 - m_EEGas.RKSemiImplicitFactor;
11428
11429 a_rightHandSide(cellId, CV->A_RHO_VV[i]) -= // (-) because rhs is substracted from cell value in RK-step
11430 (F_D * explicitFF + F_L + F_VM_I * explicitFF + F_VM_E + F_TD * (m_EEGas.dragModel == 3 ? 1.0 : explicitFF)
11431 + F_B)
11432 * a_cellVolume(cellId);
11433 }
11434 }
11435}
11436
11437
11438// works only with zeroth level-set function!
11439template <MInt nDim_, class SysEqn>
11441 TRACE();
11442 // #define debugOutput
11443 const MInt noCells = a_noCells();
11444 MInt gc;
11445 MFloat factor, Psi, xi = F0, cbar, a = F0, a1 = F0, a2 = F0, b = F0, b2 = F0, b1 = F0, c1 = F0, FD, Rr,
11446 sigma; //,d,omega
11447 MFloat reactionEnthalpy;
11448 const MFloat gammaMinusOne = m_gamma - F1;
11449 const MFloat FgammaMinusOne = F1 / gammaMinusOne;
11450 // MFloat denominator;
11451 MFloat FlaminarFlameThickness = F1 / m_laminarFlameThickness;
11452 // MFloat rhoU, Dth;
11453 MFloat rhoUFrhoB = m_burntUnburntTemperatureRatio;
11454 // MFloat rhoBurnt = m_rhoInfinity / m_burntUnburntTemperatureRatio;
11455 MFloat rhoJump = F1 / m_burntUnburntTemperatureRatio - F1;
11456 // MFloat FrhoBurnt = m_burntUnburntTemperatureRatio;
11457 MFloat factor1 = m_c0 / (F1 - m_c0);
11458 MFloat echekkiFerzigerPrefactor = F1 / (F1 - m_c0) * (F1 / (F1 - m_c0) - F1);
11459 const MFloat sq1F2 = sqrt(F1B2);
11460 const MFloat eps = c_cellLengthAtLevel(maxRefinementLevel()) * 0.00000000001;
11461 // MFloat levelSetNegative = F0, levelSetPlus = F0;
11462
11463 //---
11464 // reset
11465 m_maxReactionRate = F0;
11466 m_totalHeatReleaseRate = F0;
11467 // compute the heat release
11468 reactionEnthalpy = (m_burntUnburntTemperatureRatio - F1) * FgammaMinusOne;
11469 // save old reaction rate
11470 if(m_RKStep == 0) {
11471 // if(hasReactionRates() && hasReactionRatesBackup())
11472 memcpy(&a_reactionRateBackup(0, 0), &a_reactionRate(0, 0), sizeof(MFloat) * noInternalCells());
11473 }
11474 // reset
11475 for(MInt c = 0; c < noCells; c++) {
11476 a_reactionRate(c, 0) = F0;
11477 }
11478 // compute the subfilter variance
11479 sigma = m_subfilterVariance * c_cellLengthAtLevel(maxLevel());
11480 factor = F1 / (sqrt(F2) * sigma);
11481 // return for no-heat release combustion
11482 if(reactionEnthalpy < m_rhoEInfinity * 0.00001) {
11483 return;
11484 }
11485 switch(m_initialCondition) {
11486 case 17516: {
11492 MInt diverged = 0;
11493 MFloat diffTimeStep = 50000;
11494 if(m_temperatureChange && (globalTimeStep - m_restartTimeStep) <= diffTimeStep) {
11495 MFloat diffTemp = (m_burntUnburntTemperatureRatioEnd - m_burntUnburntTemperatureRatioStart);
11496 m_burntUnburntTemperatureRatio =
11497 (diffTemp / diffTimeStep) * (globalTimeStep - m_restartTimeStep) + m_burntUnburntTemperatureRatioStart;
11498 }
11499 // rhoBurnt = m_rhoFlameTube / m_burntUnburntTemperatureRatio;
11500 // FrhoBurnt = m_burntUnburntTemperatureRatio * F1 / m_rhoFlameTube;
11501 rhoJump = F1 - m_burntUnburntTemperatureRatio;
11502 for(MInt c = 0; c < m_bndryGhostCellsOffset; c++) {
11503 if(grid().tree().hasProperty(c, Cell::IsHalo)) {
11504 continue;
11505 }
11506 if(!a_hasProperty(c, SolverCell::IsOnCurrentMGLevel)) {
11507 continue;
11508 }
11509 MInt cLs = c;
11510 if(cLs < 0) {
11511 continue;
11512 }
11513 gc = cLs;
11514 // continue if the g cell is out of the band
11515 // the source term is in this case zero
11516 if(a_levelSetFunction(c, 0) < -999998) { // TODO labels:FV,toenhance!
11517 continue;
11518 }
11519 // compute the Echekki-Ferziger constant
11520 // - compute the inverse eddy viscosity (s/m^2)
11521 // - - density of the unburnt gas rho^u = m_rhoInfinity
11522 // - - assuming m_TInfinity is the temperature of the unburnt gas -> muInf=SUTHERLANDLAW(m_TInfinity)
11523 // - - DthInf = muInf^u / ( rho^u *Pr )
11524 FD = F1 / m_DthInfinity;
11525 // - compute Rr
11526 // levelSetNegative = a_levelSetFunction(gc, 0) - m_noReactionCells;
11527 // levelSetPlus = a_levelSetFunction(gc, 0) + m_noReactionCells;
11528
11529
11530 Rr = echekkiFerzigerPrefactor * POW2(a_flameSpeed(gc, 0) * (F1 - a_curvatureG(gc, 0) * m_marksteinLength)) * FD;
11531
11532 // damp out the reaction rate to the wall w(y=0.0341) = 0 by damping the model constant Rr(y=0.0341)=0
11533 if(m_heatReleaseDamp) {
11534 if(c_coordinate(gc, 1) < (0.0234 + m_dampingDistanceFlameBase)) {
11535 if(c_coordinate(gc, 1) > 0.0234) {
11536 Rr *= 1. / m_dampingDistanceFlameBase * (c_coordinate(gc, 1) - 0.0234);
11537 }
11538 }
11539 if(c_coordinate(gc, 1) < 0.0234) {
11540 Rr = F0;
11541 }
11542 }
11543 // compute Psi
11544 // - compute xi
11545 xi = a_levelSetFunction(gc, 0) * factor; //< xi = G(x,t)/(sigma*sqrt(2))
11546
11547 // - compute c bar
11548 a = xi - sq1F2 * factor1 * sigma * FlaminarFlameThickness;
11549 a1 = F1B2 * (POW2(sigma * factor1 * FlaminarFlameThickness))
11550 - SQRT2 * xi * sigma * factor1 * FlaminarFlameThickness;
11551 if(a > F3) {
11552 a2 = (F1 - m_c0) * exp(a1) * F1B2 * (-erfc(a) + F2); // erfc computes 1-erf and is more accurate for large a
11553 } else {
11554 a2 = (F1 - m_c0) * exp(a1) * F1B2 * (erf(a) + F1);
11555 }
11556 b = xi + sq1F2 * sigma * FlaminarFlameThickness;
11557 b1 = F1B2 * POW2(sigma * FlaminarFlameThickness) + SQRT2 * xi * sigma * FlaminarFlameThickness;
11558 if(b > F3) {
11559 b2 = m_c0 * exp(b1) * F1B2 * (-erfc(b)); // erfc computes 1-erf and is more accurate for large b
11560 } else {
11561 b2 = m_c0 * exp(b1) * F1B2 * (erf(b) - F1);
11562 }
11563 c1 = F1B2 * (erf(xi) - F1);
11564 cbar = F1 - (a2 + b2 - c1);
11565
11566 // - compute Psi
11567 if(ABS(F1 - cbar) < eps) {
11568 Psi = F1;
11569 } else {
11570 Psi = a2 / ((F1 - cbar) * POW2((rhoUFrhoB + cbar * rhoJump)));
11571 }
11572
11573 a_psi(c) = Psi;
11574
11575 IF_CONSTEXPR(hasPV_C<SysEqn>::value) {
11576 // compute rhoBar
11577 const MFloat rhoBar = m_rhoUnburnt / (1 - a_pvariable(c, PV->C) * rhoJump);
11578
11579 // compute the source term
11580 a_reactionRate(c, 0) = sysEqn().m_Re0 * rhoBar * rhoUFrhoB * Rr * (F1 - a_pvariable(c, PV->C)) * Psi;
11581 }
11582
11583 // catch nan reaction rate
11584 if(!(a_reactionRate(c, 0) >= F0) && !(a_reactionRate(c, 0) <= F0)) {
11585 diverged = 1;
11586 cerr << "reaction rate is nan!!!" << endl;
11587 }
11588
11589 // compute the source terms
11590 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
11591 a_rightHandSide(c, CV->RHO_C) -= a_reactionRate(c, 0) * a_cellVolume(c);
11592 a_rightHandSide(c, CV->RHO_E) -= a_reactionRate(c, 0) * a_cellVolume(c) * reactionEnthalpy;
11593
11594 // compute the maximum reaction rate and the total heat release
11595 if(!a_hasProperty(c, Cell::IsHalo)) {
11596 m_maxReactionRate = mMax(a_reactionRate(c, 0), m_maxReactionRate);
11597 m_totalHeatReleaseRate += a_reactionRate(c, 0) * a_cellVolume(c) * reactionEnthalpy;
11598 }
11599 }
11600 MPI_Allreduce(MPI_IN_PLACE, &diverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "diverged");
11601 if(diverged == 1) {
11602 cerr << "Solution diverged (computeSourceTerms)" << endl;
11603 MString errorMessage = "reaction rate is nan";
11604 mTerm(1, AT_, errorMessage);
11605 }
11606
11607 break;
11608 }
11609 case 1751600: {
11610 MInt diverged = 0;
11611 MFloat diffTimeStep = 50000;
11612 if(m_temperatureChange && (globalTimeStep - m_restartTimeStep) <= diffTimeStep) {
11613 MFloat diffTemp = (m_burntUnburntTemperatureRatioEnd - m_burntUnburntTemperatureRatioStart);
11614 m_burntUnburntTemperatureRatio =
11615 (diffTemp / diffTimeStep) * (globalTimeStep - m_restartTimeStep) + m_burntUnburntTemperatureRatioStart;
11616 }
11617 // rhoBurnt = m_rhoFlameTube / m_burntUnburntTemperatureRatio;
11618 // FrhoBurnt = m_burntUnburntTemperatureRatio * F1 / m_rhoFlameTube;
11619 rhoJump = F1 - m_burntUnburntTemperatureRatio;
11620 for(MInt c = 0; c < m_bndryGhostCellsOffset; c++) {
11621 if(grid().tree().hasProperty(c, Cell::IsHalo)) {
11622 continue;
11623 }
11624 if(!a_hasProperty(c, SolverCell::IsOnCurrentMGLevel)) {
11625 continue;
11626 }
11627 MInt cLs = c;
11628 if(cLs < 0) {
11629 continue;
11630 }
11631 gc = cLs;
11632 if(gc == -1) {
11633 continue;
11634 }
11635 // continue if the g cell is out of the band
11636 // the source term is in this case zero
11637 if(a_levelSetFunction(gc, 0) < -99998) {
11638 continue;
11639 }
11640 // compute the Echekki-Ferziger constant
11641 // - compute the inverse eddy viscosity (s/m^2)
11642 // - - density of the unburnt gas rho^u = m_rhoInfinity
11643 // - - assuming m_TInfinity is the temperature of the unburnt gas -> muInf=SUTHERLANDLAW(m_TInfinity)
11644 // - - DthInf = muInf^u / ( rho^u *Pr )
11645 FD = F1 / m_DthInfinity;
11646 // - compute Rr
11647 // levelSetNegative = lsSolver().a_levelSetFunctionG(gc, 0) - m_noReactionCells;
11648 // levelSetPlus = lsSolver().a_levelSetFunctionG(gc, 0) + m_noReactionCells;
11649
11650 Rr = echekkiFerzigerPrefactor * POW2(a_flameSpeed(gc, 0) * (F1 - a_curvatureG(gc, 0) * m_marksteinLength)) * FD;
11651
11652 // damp out the reaction rate to the wall w(y=0.0341) = 0 by damping the model constant Rr(y=0.0341)=0
11653 if(m_heatReleaseDamp) {
11654 if(c_coordinate(gc, 1) < (m_yOffsetFlameTube + m_dampingDistanceFlameBase)) {
11655 if(c_coordinate(gc, 1) > m_yOffsetFlameTube) {
11656 Rr *= 1. / m_dampingDistanceFlameBase * (c_coordinate(gc, 1) - m_yOffsetFlameTube);
11657 }
11658 }
11659 if(c_coordinate(gc, 1) < m_yOffsetFlameTube) {
11660 Rr = F0;
11661 }
11662 }
11663
11664 xi = a_levelSetFunction(gc, 0) * factor; //< xi = G(x,t)/(sigma*sqrt(2))
11665
11666 // - compute c bar
11667 a = xi - sq1F2 * factor1 * sigma * FlaminarFlameThickness;
11668 a1 = F1B2 * (POW2(sigma * factor1 * FlaminarFlameThickness))
11669 - SQRT2 * xi * sigma * factor1 * FlaminarFlameThickness;
11670 if(a > F3) {
11671 a2 = (F1 - m_c0) * exp(a1) * F1B2 * (-erfc(a) + F2); // erfc computes 1-erf and is more accurate for large a
11672 } else {
11673 a2 = (F1 - m_c0) * exp(a1) * F1B2 * (erf(a) + F1);
11674 }
11675 b = xi + sq1F2 * sigma * FlaminarFlameThickness;
11676 b1 = F1B2 * POW2(sigma * FlaminarFlameThickness) + SQRT2 * xi * sigma * FlaminarFlameThickness;
11677 if(b > F3) {
11678 b2 = m_c0 * exp(b1) * F1B2 * (-erfc(b)); // erfc computes 1-erf and is more accurate for large b
11679 } else {
11680 b2 = m_c0 * exp(b1) * F1B2 * (erf(b) - F1);
11681 }
11682 c1 = F1B2 * (erf(xi) - F1);
11683 cbar = F1 - (a2 + b2 - c1);
11684
11685 // - compute Psi
11686 if(ABS(F1 - cbar) < eps) {
11687 Psi = F1;
11688 } else {
11689 Psi = a2 / ((F1 - cbar) * POW2((rhoUFrhoB + cbar * rhoJump)));
11690 }
11691
11692 a_psi(c) = Psi;
11693
11694 IF_CONSTEXPR(hasPV_C<SysEqn>::value) {
11695 // compute rhoBar
11696 const MFloat rhoBar = m_rhoUnburnt / (1 - a_pvariable(c, PV->C) * rhoJump);
11697
11698 // compute the source term
11699 a_reactionRate(c, 0) = sysEqn().m_Re0 * rhoBar * rhoUFrhoB * Rr * (F1 - a_pvariable(c, PV->C)) * Psi;
11700 }
11701
11702 // catch nan reaction rate
11703 if(!(a_reactionRate(c, 0) >= F0) && !(a_reactionRate(c, 0) <= F0)) {
11704 diverged = 1;
11705 }
11706
11707 // compute the source terms
11708 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
11709 a_rightHandSide(c, CV->RHO_C) -= a_reactionRate(c, 0) * a_cellVolume(c);
11710 a_rightHandSide(c, CV->RHO_E) -= a_reactionRate(c, 0) * a_cellVolume(c) * reactionEnthalpy;
11711
11712 // compute the maximum reaction rate and the total heat release
11713 if(!a_hasProperty(c, Cell::IsHalo)) {
11714 m_maxReactionRate = mMax(a_reactionRate(c, 0), m_maxReactionRate);
11715 m_totalHeatReleaseRate += a_reactionRate(c, 0) * a_cellVolume(c) * reactionEnthalpy;
11716 }
11717 }
11718 MPI_Allreduce(MPI_IN_PLACE, &diverged, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "diverged");
11719 if(diverged == 1) {
11720 // m_log << "Solution diverged, writing NETCDF file for debugging" << endl;
11721 MString errorMessage = "reaction rate is nan";
11722 mTerm(1, AT_, errorMessage);
11723 }
11724
11725 break;
11726 }
11727
11728
11729 default: {
11730 cerr << "dont use the default in computeSourceTerms (FV) !!!" << endl;
11731 break;
11732 }
11733 }
11734 if(noDomains() > 1) {
11735 MPI_Allreduce(MPI_IN_PLACE, &m_totalHeatReleaseRate, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
11736 "m_totalHeatReleaseRate");
11737 MPI_Allreduce(MPI_IN_PLACE, &m_maxReactionRate, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
11738 "m_maxReactionRate");
11739 }
11740}
11741
11742template <MInt nDim_, class SysEqn>
11744 TRACE();
11745
11746 const MFloat kappa = 0.4;
11747 const MFloat B = 5.5;
11748
11749 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
11750 const MInt bndrySrfcId = m_wmSurfaces[wmSrfcId].m_bndrySrfcId;
11751 const MInt cellId = m_bndryCells->a[bndryCellId].m_cellId;
11752
11753 if(!m_wmSurfaces[wmSrfcId].m_wmHasImgCell) {
11754 return F0;
11755 }
11756
11757 MFloat tau_wm = F0;
11758 MFloat mue_wm = F0;
11759
11760 MFloat nx = m_bndryCells->a[bndryCellId].m_srfcs[bndrySrfcId]->m_normalVector[0];
11761 MFloat ny = m_bndryCells->a[bndryCellId].m_srfcs[bndrySrfcId]->m_normalVector[1];
11762 MFloat u_img = 0.0;
11763 MFloat v_img = 0.0;
11764 MFloat u_II = 0.0;
11765 MFloat u_II_bndry = 0.0;
11766 MFloat dn_img = m_wmDistance;
11767
11768 u_img = m_wmSurfaces[wmSrfcId].m_wmImgVars[PV->VV[0]];
11769 v_img = m_wmSurfaces[wmSrfcId].m_wmImgVars[PV->VV[1]];
11770
11771 // compute wall parallel velocities, depending on surface orientation
11772 if(abs(ny) < m_eps) return F0; // close to vertical wall, can't decide proper flow direction here
11773
11774 u_II = maia::math::sgn(ny) * (u_img * ny - v_img * nx);
11775 u_II_bndry = maia::math::sgn(ny) * (a_pvariable(cellId, PV->U) * ny - a_pvariable(cellId, PV->V) * nx);
11776
11777 if(u_II > 0.0 && u_II_bndry > 0.0) {
11778 const MInt ghostCellId = m_bndryCells->a[bndryCellId].m_srfcVariables[bndrySrfcId]->m_ghostCellId;
11779 const MFloat rho_surf = F1B2 * (a_pvariable(cellId, PV->RHO) + a_pvariable(ghostCellId, PV->RHO));
11780 const MFloat p_surf = F1B2 * (a_pvariable(cellId, PV->P) + a_pvariable(ghostCellId, PV->P));
11781 const MFloat T_surf = sysEqn().temperature_ES(rho_surf, p_surf);
11782 const MFloat mue = SUTHERLANDLAW(T_surf);
11783
11784 const MFloat Re0 = sysEqn().m_Re0;
11785
11786 // Time filter to reduce fluctuations in the wall shear stress which are normally dampened by the viscous sublayer
11787 MFloat u_tau = m_wmSurfaces[wmSrfcId].m_wmUTAU;
11788
11789 if(m_wmTimeFilter) {
11790 // see "Integral wall model for large large eddy simulations of wall-bounded turbulent flows" (Yang et al. 2015)
11791 const MFloat theta = 1.0;
11792 const MFloat twall = theta * m_wmDistance / (kappa * u_tau);
11793 const MFloat E = m_timeStep / twall; // constant for exponential moving average
11794 const MFloat u_II_last = m_wmSurfaces[wmSrfcId].m_wmUII;
11795
11796 // floating average with time constant based on shear velocity
11797 u_II = E * u_II + (F1 - E) * u_II_last;
11798 }
11799
11800 // save u_II for restart purposes (before van Driest Transformation!)
11801 m_wmSurfaces[wmSrfcId].m_wmUII = u_II;
11802
11803 if(m_Ma > 1.3) {
11804 // van Driest transform for compressible flows
11805 const MFloat b = sysEqn().vanDriest(m_Ma);
11806 u_II = m_UInfinity / b * asin(b * u_II / m_UInfinity);
11807 }
11808
11809 // iteration of spalding wall function
11810 MFloat res = 9999.0;
11811 while(res > 1e-6) {
11812 MFloat eKB = exp(-kappa * B);
11813 MFloat spalding = u_II / u_tau
11814 + eKB
11815 * (exp(kappa * u_II / u_tau) - 1 - (kappa * u_II / u_tau)
11816 - 1.0 / 2.0 * pow(kappa * u_II / u_tau, 2) - 1.0 / 6.0 * pow(kappa * u_II / u_tau, 3))
11817 - abs(dn_img) * u_tau * (rho_surf / mue) * Re0;
11818 MFloat d_spalding =
11819 -u_II / pow(u_tau, 2)
11820 + eKB
11821 * ((-kappa * u_II / pow(u_tau, 2)) * exp(kappa * u_II / u_tau) + (kappa * u_II / u_tau) / u_tau
11822 + pow(kappa * u_II / u_tau, 2) / u_tau + 1.0 / 2.0 * pow(kappa * u_II / u_tau, 3) / u_tau)
11823 - abs(dn_img) * (rho_surf / mue) * Re0;
11824
11825 MFloat delta = -spalding / d_spalding;
11826
11827 u_tau += delta;
11828 res = abs(delta / u_tau);
11829 m_wmIterator++;
11830 }
11831
11832 // save u_tau for restart purposes
11833 m_wmSurfaces[wmSrfcId].m_wmUTAU = u_tau;
11834
11835 if(std::isnan(u_tau)) {
11836 cout << "WARNING: Wall model u_tau is NaN!" << endl;
11837 return F0;
11838 }
11839
11840 tau_wm = rho_surf * pow(u_tau, 2);
11841
11842 MFloat dudn = m_bndryCells->a[bndryCellId].m_srfcVariables[bndrySrfcId]->m_normalDeriv[PV->VV[0]];
11843 MFloat dvdn = m_bndryCells->a[bndryCellId].m_srfcVariables[bndrySrfcId]->m_normalDeriv[PV->VV[1]];
11844 MFloat grad = maia::math::sgn(ny) * (dudn * ny - dvdn * nx);
11845 MFloat tau_w = mue * grad / Re0;
11846
11847 if(tau_w / tau_wm > m_eps) mue_wm = ((tau_wm / tau_w) - 1.0) * mue;
11848 if(mue_wm > 50.0 * mue) mue_wm = 50.0 * mue;
11849 }
11850
11851 m_wmSurfaces[wmSrfcId].m_wmTauW = tau_wm;
11852 m_wmSurfaces[wmSrfcId].m_wmMUEWM = mue_wm;
11853
11854 return mue_wm;
11855}
11856
11857
11858template <MInt nDim_, class SysEqn>
11860 TRACE();
11861
11862 const MFloat kappa = 0.4;
11863 const MFloat B = 5.5;
11864
11865 MInt bndryCellId = a_bndryId(cellId);
11866 if(!m_bndryCells->a[bndryCellId].m_wmBCVars->m_wmHasImgCell) return F0;
11867
11868 MFloat tau_wm = F0;
11869 MFloat mue_wm = F0;
11870
11871 MFloat* normalVec = m_bndryCells->a[bndryCellId].m_srfcs[0]->m_normalVector;
11872 MFloat* imgVar = m_bndryCells->a[bndryCellId].m_wmBCVars->m_wmImgVars;
11873 MFloat* normalDeriv = m_bndryCells->a[bndryCellId].m_srfcVariables[0]->m_normalDeriv;
11874
11875 MFloat vvII[3] = {0.0, 0.0, 0.0};
11876 MFloat vvn[3] = {0.0, 0.0, 0.0};
11877 MFloat dvvII_dn[3] = {0.0, 0.0, 0.0};
11878 MFloat dvvn_dn[3] = {0.0, 0.0, 0.0};
11879
11880 MFloat Vn = 0.0;
11881 MFloat VII = 0.0;
11882 MFloat dVn_dn = 0.0;
11883 MFloat dVII_dn = 0.0;
11884
11885 MFloat dn_img = m_wmDistance;
11886
11887 // decompose 3D velocity and gradients into wall-parallel and orthogonal components
11888 for(MInt d = 0; d < nDim; d++) {
11889 Vn += imgVar[PV->VV[d]] * normalVec[d];
11890 dVn_dn += normalDeriv[PV->VV[d]] * normalVec[d];
11891 }
11892
11893 for(MInt d = 0; d < nDim; d++) {
11894 vvn[d] = Vn * normalVec[d];
11895 vvII[d] = imgVar[PV->VV[d]] - vvn[d];
11896
11897 dvvn_dn[d] = dVn_dn * normalVec[d];
11898 dvvII_dn[d] = normalDeriv[PV->VV[d]] - dvvn_dn[d];
11899 }
11900
11901 for(MInt d = 0; d < nDim; d++) {
11902 VII += POW2(vvII[d]);
11903 dVII_dn += POW2(dvvII_dn[d]);
11904 }
11905
11906 VII = sqrt(VII);
11907 dVII_dn = sqrt(dVII_dn);
11908
11909 // close to vertical wall, can't decide proper flow direction here, probably stagnation point
11910 if(F1 - abs(normalVec[0]) < m_eps) return F0;
11911
11912 // check for attached flow with respect to mean flow in x direction)
11913 if(vvII[0] > 0.0 && dvvII_dn[0] > 0.0) {
11914 const MInt ghostCellId = m_bndryCells->a[bndryCellId].m_srfcVariables[0]->m_ghostCellId;
11915 const MFloat rho_surf = F1B2 * (a_pvariable(cellId, PV->RHO) + a_pvariable(ghostCellId, PV->RHO));
11916 const MFloat p_surf = F1B2 * (a_pvariable(cellId, PV->P) + a_pvariable(ghostCellId, PV->P));
11917 const MFloat T_surf = sysEqn().temperature_ES(rho_surf, p_surf);
11918 const MFloat mue = SUTHERLANDLAW(T_surf);
11919
11920 const MFloat Re0 = sysEqn().m_Re0;
11921
11922 if(m_Ma > 1.3) {
11923 // van Driest transform for compressible flows
11924 const MFloat b = sysEqn().vanDriest(m_Ma);
11925 VII = m_UInfinity / b * asin(b * VII / m_UInfinity);
11926 }
11927
11928 // iteration of spalding wall function
11929 MFloat u_tau = m_bndryCells->a[bndryCellId].m_wmBCVars->m_wmUTAU;
11930 MFloat res = 9999.0;
11931
11932 while(res > 1e-6) {
11933 MFloat eKB = exp(-kappa * B);
11934 MFloat spalding = VII / u_tau
11935 + eKB
11936 * (exp(kappa * VII / u_tau) - 1 - (kappa * VII / u_tau)
11937 - 1.0 / 2.0 * pow(kappa * VII / u_tau, 2) - 1.0 / 6.0 * pow(kappa * VII / u_tau, 3))
11938 - abs(dn_img) * u_tau * (rho_surf / mue) * Re0;
11939 MFloat d_spalding =
11940 -VII / pow(u_tau, 2)
11941 + eKB
11942 * ((-kappa * VII / pow(u_tau, 2)) * exp(kappa * VII / u_tau) + (kappa * VII / u_tau) / u_tau
11943 + pow(kappa * VII / u_tau, 2) / u_tau + 1.0 / 2.0 * pow(kappa * VII / u_tau, 3) / u_tau)
11944 - abs(dn_img) * (rho_surf / mue) * Re0;
11945 MFloat delta = -spalding / d_spalding;
11946 u_tau += delta;
11947 res = abs(delta / u_tau);
11948 m_wmIterator++;
11949 }
11950
11951 tau_wm = rho_surf * pow(u_tau, 2);
11952
11953 m_bndryCells->a[bndryCellId].m_wmBCVars->m_wmUTAU = u_tau;
11954
11955 MFloat tau_w = mue * dVII_dn / Re0;
11956
11957 if(tau_w / tau_wm > m_eps) mue_wm = ((tau_wm / tau_w) - 1.0) * mue;
11958 if(mue_wm > 50.0 * mue) mue_wm = 50.0 * mue; // USE MAX FUNCTION MAYBE?
11959 }
11960
11961 if(m_wmOutput) {
11962 m_bndryCells->a[bndryCellId].m_wmBCVars->m_wmUII = VII;
11963 m_bndryCells->a[bndryCellId].m_wmBCVars->m_wmTauW = tau_wm;
11964 m_bndryCells->a[bndryCellId].m_wmBCVars->m_wmMUEWM = mue_wm;
11965 }
11966
11967 return mue_wm;
11968}
11969
11970template <MInt nDim_, class SysEqn>
11972 TRACE();
11973
11974 m_wmLES = Context::getSolverProperty<MBool>("wmLES", m_solverId, AT_, &m_wmLES);
11975
11976 if(m_wmLES) {
11977 m_log << endl << "Reading WM properties ... " << endl;
11978
11979 if(Context::propertyExists("wmUseInterpolation", m_solverId)) {
11980 m_wmUseInterpolation =
11981 Context::getSolverProperty<MBool>("wmUseInterpolation", m_solverId, AT_, &m_wmUseInterpolation);
11982 } else {
11983 m_wmUseInterpolation = true;
11984 }
11985
11986 if(Context::propertyExists("wmDistance", m_solverId)) {
11987 m_wmDistance = Context::getSolverProperty<MFloat>("wmDistance", m_solverId, AT_, &m_wmDistance);
11988 } else {
11989 m_wmDistance = 2.0 * c_cellLengthAtLevel(maxLevel());
11990 }
11991
11992 if(Context::propertyExists("wmOutput", m_solverId)) {
11993 m_wmOutput = Context::getSolverProperty<MBool>("wmOutput", m_solverId, AT_, &m_wmOutput);
11994 } else {
11995 m_wmOutput = false;
11996 }
11997
11998 if(Context::propertyExists("wmSurfaceProbeInterval", m_solverId)) {
11999 m_wmSurfaceProbeInterval =
12000 Context::getSolverProperty<MInt>("wmSurfaceProbeInterval", m_solverId, AT_, &m_wmSurfaceProbeInterval);
12001 } else {
12002 m_wmSurfaceProbeInterval = 0;
12003 }
12004
12005 if(Context::propertyExists("wmTimeFilter", m_solverId)) {
12006 m_wmTimeFilter = Context::getSolverProperty<MBool>("wmTimeFilter", m_solverId, AT_, &m_wmTimeFilter);
12007 } else {
12008 m_wmTimeFilter = false;
12009 }
12010
12011 m_log << "wmDistance = " << m_wmDistance << endl;
12012 m_log << "wmUseInterpolation = " << m_wmUseInterpolation << endl;
12013 m_log << "wmOutput = " << m_wmOutput << endl;
12014 m_log << "wmSurfaceProbeInterval = " << m_wmSurfaceProbeInterval << endl;
12015 m_log << "done.";
12016 }
12017}
12018
12019template <MInt nDim_, class SysEqn>
12021 TRACE();
12022
12023 const MInt noPVars = PV->noVariables;
12024
12025 // gather
12026 gatherWMVars();
12027
12028 // send
12029 MInt sendBufSize = 0;
12030 MInt sendOffset = 0;
12031
12032 for(MInt dom = 0; dom < m_wmNoDomains; dom++) {
12033 sendBufSize = m_noWMImgPointsSend[dom] * noPVars;
12034 MPI_Issend(&m_wmImgSendBuffer[sendOffset], sendBufSize, MPI_DOUBLE, dom, 0, m_comm_wm, &m_mpi_wmSendReq[dom], AT_,
12035 "m_wmImgSendBuffer[sendOffset]");
12036 sendOffset += sendBufSize;
12037 }
12038
12039 // receive
12040 MInt recvOffset = 0;
12041 MInt recvBufSize = 0;
12042
12043 for(MInt dom = 0; dom < m_wmNoDomains; dom++) {
12044 recvBufSize = m_noWMImgPointsRecv[dom] * noPVars;
12045 MPI_Irecv(&m_wmImgRecvBuffer[recvOffset], recvBufSize, MPI_DOUBLE, dom, 0, m_comm_wm, &m_mpi_wmRecvReq[dom], AT_,
12046 "m_wmImgRecvBuffer[recvOffset]");
12047 recvOffset += recvBufSize;
12048 }
12049 MPI_Waitall(m_wmNoDomains, &m_mpi_wmSendReq[0], MPI_STATUSES_IGNORE, AT_);
12050 MPI_Waitall(m_wmNoDomains, &m_mpi_wmRecvReq[0], MPI_STATUSES_IGNORE, AT_);
12051
12052 scatterWMVars();
12053}
12054
12055
12056// interpolation must occur beforehand, a data structure to save the interplolated variables is necessary
12057template <MInt nDim_, class SysEqn>
12059 TRACE();
12060 const MInt noPVars = PV->noVariables;
12061 MInt sendBufferCounter = 0;
12062
12063 if(m_wmUseInterpolation) {
12064 MFloatScratchSpace interpolatedVars(noPVars, AT_, "interpolatedVars");
12065 for(MInt dom = 0; dom < m_wmNoDomains; dom++) {
12066#ifdef _OPENMP
12067#pragma omp parallel for
12068#endif
12069 for(MInt ip = 0; ip < m_noWMImgPointsSend[dom]; ip++) {
12070 const MInt imgCellId = m_wmImgCellIds[dom][ip];
12071 const MFloat* imgCoords = &m_wmImgCoords[dom][nDim * ip];
12072 getInterpolatedVariablesInCell(imgCellId, &imgCoords[0], &interpolatedVars[0]);
12073 for(MInt v = 0; v < noPVars; v++) {
12074 m_wmImgSendBuffer[sendBufferCounter + (ip * noPVars) + v] = interpolatedVars[v];
12075 }
12076 }
12077 // moving the counter out of the loop allows openmp parallelization
12078 sendBufferCounter += m_noWMImgPointsSend[dom] * noPVars;
12079 }
12080 } else {
12081 for(MInt dom = 0; dom < m_wmNoDomains; dom++) {
12082 for(MInt ip = 0; ip < m_noWMImgPointsSend[dom]; ip++) {
12083 const MInt imgCellId = m_wmImgCellIds[dom][ip];
12084 for(MInt v = 0; v < noPVars; v++) {
12085 m_wmImgSendBuffer[sendBufferCounter + (ip * noPVars) + v] = a_pvariable(imgCellId, v);
12086 }
12087 }
12088 // moving the counter out of the loop allows openmp parallelization
12089 sendBufferCounter += m_noWMImgPointsSend[dom] * noPVars;
12090 }
12091 }
12092}
12093
12094
12095template <MInt nDim_, class SysEqn>
12097 TRACE();
12098 const MInt noPVars = PV->noVariables;
12099 MInt bufSize = 0;
12100 MInt offset = 0;
12101
12102 for(MInt dom = 0; dom < noDomains(); dom++) {
12103 bufSize = m_noWMImgPointsSend[dom] * noPVars;
12104 MPI_Issend(&m_wmImgSendBuffer[offset], bufSize, MPI_DOUBLE, dom, 0, mpiComm(), &m_mpi_wmRequest[dom], AT_,
12105 "m_wmImgSendBuffer[offset]");
12106 offset += bufSize;
12107 }
12108}
12109
12110template <MInt nDim_, class SysEqn>
12112 TRACE();
12113 const MInt noPVars = PV->noVariables;
12114 MInt offset = 0;
12115 MInt bufSize = 0;
12116 MPI_Status status;
12117
12118 // TODO labels:FV,COMM switch to Irecv + Waitall
12119 for(MInt dom = 0; dom < noDomains(); dom++) {
12120 bufSize = m_noWMImgPointsRecv[dom] * noPVars;
12121 MPI_Recv(&m_wmImgRecvBuffer[offset], bufSize, MPI_DOUBLE, dom, 0, mpiComm(), &status, AT_,
12122 "m_wmImgRecvBuffer[offset]");
12123 offset += bufSize;
12124 }
12125 for(MInt dom = 0; dom < noDomains(); dom++) {
12126 MPI_Wait(&m_mpi_wmRequest[dom], &status, AT_);
12127 }
12128}
12129
12130template <MInt nDim_, class SysEqn>
12132 TRACE();
12133
12134 if(PV->noVariables > 5) mTerm(1, AT_, "WMLES not implemented for noPVars > 5");
12135
12136 const MInt noPVars = mMin(PV->noVariables, 5);
12137 MInt ipCounter = 0;
12138
12139 for(MInt dom = 0; dom < m_wmNoDomains; dom++) {
12140#ifdef _OPENMP
12141#pragma omp parallel for
12142#endif
12143 for(MInt ip = 0; ip < m_noWMImgPointsRecv[dom]; ip++) {
12144 const MInt wmSrfcId = m_wmImgRecvIdMap[ipCounter + ip];
12145 for(MInt v = 0; v < noPVars; v++) {
12146 m_wmSurfaces[wmSrfcId].m_wmImgVars[v] = m_wmImgRecvBuffer[noPVars * (ipCounter + ip) + v];
12147 }
12148 // ipCounter++;
12149 }
12150 // moving the counter out of the loop allows openmp parallelization
12151 ipCounter += m_noWMImgPointsRecv[dom];
12152 }
12153}
12154
12155template <MInt nDim_, class SysEqn>
12157 TRACE();
12158
12159 mDeallocate(m_noWMImgPointsSend);
12160 mDeallocate(m_noWMImgPointsRecv);
12161 mDeallocate(m_wmImgSendBuffer);
12162 mDeallocate(m_wmImgRecvBuffer);
12163 mDeallocate(m_wmImgRecvIdMap);
12164 mDeallocate(m_mpi_wmRequest);
12165 mDeallocate(m_mpi_wmSendReq);
12166 mDeallocate(m_mpi_wmRecvReq);
12167
12168 m_wmImgCellIds.clear();
12169 m_wmImgWMSrfcIds.clear();
12170 m_wmImgCoords.clear();
12171
12172 const MInt noPVars = PV->noVariables;
12173 const MInt noWMSurfaces = m_wmSurfaces.size();
12174
12175 std::vector<MFloat> localWMImgCoords;
12176 std::vector<MInt> localWMImgPointRootIds;
12177 std::vector<MInt> localWMSrfcIds;
12178
12179 for(MInt wmSrfcId = 0; wmSrfcId < noWMSurfaces; wmSrfcId++) {
12180 MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
12181 MInt bndrySrfcId = m_wmSurfaces[wmSrfcId].m_bndrySrfcId;
12182
12183 for(MInt dim = 0; dim < nDim; dim++) {
12184 MFloat imgCoord = 0.0;
12185 imgCoord += m_bndryCells->a[bndryCellId].m_srfcs[bndrySrfcId]->m_coordinates[dim];
12186 imgCoord += m_wmDistance * m_bndryCells->a[bndryCellId].m_srfcs[bndrySrfcId]->m_normalVector[dim];
12187 localWMImgCoords.push_back(imgCoord);
12188 }
12189 localWMImgPointRootIds.push_back(domainId());
12190 localWMSrfcIds.push_back(wmSrfcId);
12191 }
12192
12193 ScratchSpace<MInt> localNoWMImgPoints(noDomains(), AT_, "localNoWMImgPoints");
12194 localNoWMImgPoints.fill(0);
12195 ScratchSpace<MInt> localNoWMImgCoords(noDomains(), AT_, "localNoWMImgCoords");
12196 localNoWMImgCoords.fill(0);
12197
12198 localNoWMImgPoints[domainId()] = localWMImgPointRootIds.size();
12199
12200 MPI_Allgather(&localNoWMImgPoints[domainId()], 1, MPI_INT, &localNoWMImgPoints[0], 1, MPI_INT, mpiComm(), AT_,
12201 "localNoWMImgPoints", "localNoWMImgPoints");
12202
12203 for(MInt dom = 0; dom < noDomains(); dom++) {
12204 localNoWMImgCoords[dom] = localNoWMImgPoints[dom] * nDim;
12205 }
12206
12207 // sum up all imagePoints to check if there is any imgPoint to be found, otherwise there is probably something wrong
12208 MInt globalNoWMImgPoints = 0;
12209 for(MInt dom = 0; dom < noDomains(); dom++) {
12210 globalNoWMImgPoints += localNoWMImgPoints[dom];
12211 }
12212
12213 if(!(globalNoWMImgPoints > 0)) {
12214 mTerm(-1, "No WM Image Points were found within the entire geometry! Please check if you have assigned any WM-BC "
12215 "in the geometry file");
12216 }
12217
12218 std::vector<std::vector<MInt>> wmImgCellIds;
12219 std::vector<std::vector<MInt>> wmImgWMSrfcIds;
12220 std::vector<std::vector<MFloat>> wmImgCoords;
12221
12222 wmImgCellIds.resize(noDomains());
12223 wmImgWMSrfcIds.resize(noDomains());
12224 wmImgCoords.resize(noDomains());
12225
12226 ScratchSpace<MInt> noWMImgPointsSend(noDomains(), AT_, "noWMImgPointsSend");
12227 noWMImgPointsSend.fill(0);
12228 ScratchSpace<MInt> noWMImgPointsRecv(noDomains(), AT_, "noWMImgPointsRecv");
12229 noWMImgPointsRecv.fill(0);
12230
12231 // now treat all domains sequentially to avoid massive allocation of memory
12232 MInt totalNoWMImgPointsSend = 0;
12233 MInt outsideImagePoints = 0;
12234 for(MInt dom = 0; dom < noDomains(); dom++) {
12235 if(localNoWMImgPoints[dom] == 0) continue; // this domain has no wmBndryCells
12236
12237 // allocate temp memory to communicate the image points to every other domain
12238 ScratchSpace<MFloat> domWMImgCoords(nDim * localNoWMImgPoints[dom], AT_, "domWMImgCoords");
12239 ScratchSpace<MInt> domWMImgPointRootIds(localNoWMImgPoints[dom], AT_, "domWMImgPointRootIds");
12240 ScratchSpace<MInt> domWMSrfcIds(localNoWMImgPoints[dom], AT_, "domWMSrfcIds");
12241
12242 if(domainId() == dom) {
12243 // sending domain, fill array with actual values
12244 for(MInt ip = 0; ip < localNoWMImgPoints[dom]; ip++) {
12245 for(MInt dim = 0; dim < nDim; dim++) {
12246 domWMImgCoords[nDim * ip + dim] = localWMImgCoords[nDim * ip + dim];
12247 }
12248 domWMImgPointRootIds[ip] = localWMImgPointRootIds[ip];
12249 domWMSrfcIds[ip] = localWMSrfcIds[ip];
12250 }
12251 } else {
12252 // receiving domain, fill with dummy values
12253 domWMImgCoords.fill(-9999.9999);
12254 domWMImgPointRootIds.fill(-1);
12255 domWMSrfcIds.fill(-1);
12256 }
12257
12258 // Broadcast coordinates, rootIds and wmSrfcIds to everyone to allow searching
12259 MPI_Bcast(&domWMImgCoords[0], localNoWMImgCoords[dom], MPI_DOUBLE, dom, mpiComm(), AT_, "domWMImgCoords[0]");
12260 MPI_Bcast(&domWMImgPointRootIds[0], localNoWMImgPoints[dom], MPI_INT, dom, mpiComm(), AT_,
12261 "domWMImgPointRootIds[0]");
12262 MPI_Bcast(&domWMSrfcIds[0], localNoWMImgPoints[dom], MPI_INT, dom, mpiComm(), AT_, "domWMSrfcIds[0]");
12263
12264 // now search for image points of dom in the local domain
12265 for(MInt ip = 0; ip < localNoWMImgPoints[dom]; ip++) {
12266 MFloat imgCoords[nDim];
12267 MInt dummyId = -1;
12268 for(MInt dim = 0; dim < nDim; dim++) {
12269 imgCoords[dim] = domWMImgCoords[nDim * ip + dim];
12270 }
12271 dummyId = grid().findContainingLeafCell(imgCoords);
12272 if(dummyId > -1) {
12273 wmImgCellIds[dom].push_back(dummyId);
12274 wmImgWMSrfcIds[dom].push_back(domWMSrfcIds[ip]);
12275 for(MInt dim = 0; dim < nDim; dim++) {
12276 wmImgCoords[dom].push_back(imgCoords[dim]);
12277 }
12278 if(m_wmUseInterpolation) initInterpolationForCell(dummyId);
12279 a_isWMImgCell(dummyId) = true;
12280 noWMImgPointsSend[dom]++;
12281 totalNoWMImgPointsSend++;
12282 if(dom != domainId()) outsideImagePoints++;
12283 }
12284 }
12285
12286 // communicate found points to receiving domain (dom)
12287 MPI_Gather(&noWMImgPointsSend[dom], 1, MPI_INT, &noWMImgPointsRecv[0], 1, MPI_INT, dom, mpiComm(), AT_,
12288 "&noWMImgPointsSend[dom]", "noWMImgPointsRecv[0]");
12289 }
12290
12291 MPI_Allreduce(MPI_IN_PLACE, &outsideImagePoints, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
12292 "outsideImagePoints");
12293
12294 m_log << "initWMExchange() found " << outsideImagePoints << " non-local image points!";
12295
12296 MInt totalNoWMImgPointsRecv = 0;
12297 for(MInt dom = 0; dom < noDomains(); dom++) {
12298 totalNoWMImgPointsRecv += noWMImgPointsRecv[dom];
12299 }
12300
12301 // every domain now knows if it has to send or receive imgPointVars
12302 // we can now create a sub-communicator only containing the relevant ranks
12303 if(totalNoWMImgPointsRecv > 0 || totalNoWMImgPointsSend > 0) {
12304 MPI_Comm_split(mpiComm(), 0, 0, &m_comm_wm, AT_, "m_comm_wm");
12305 MPI_Comm_rank(m_comm_wm, &m_wmDomainId);
12306 MPI_Comm_size(m_comm_wm, &m_wmNoDomains);
12307 } else {
12308 MPI_Comm_split(mpiComm(), MPI_UNDEFINED, 0, &m_comm_wm, AT_, "m_comm_wm");
12309 m_wmDomainId = -1;
12310 m_wmNoDomains = 0;
12311 }
12312
12313 // ranks uninvolved in the wmExchange can now return
12314 if(m_wmDomainId < 0) return;
12315
12316 // =========================================================================
12317 // ===================== ONLY INVOLVED RANKS FROM HERE =====================
12318 // =========================================================================
12319
12320 // to reduce the data structures of the imgPoints we need to map the ranks from m_comm_wm to mpiComm()
12321 ScratchSpace<MInt> wmIdToWorldId(m_wmNoDomains, AT_, "wmIdToWorldId");
12322 MInt domId = domainId();
12323 MPI_Allgather(&domId, 1, MPI_INT, &wmIdToWorldId[0], 1, MPI_INT, m_comm_wm, AT_, "domId", "wmIdToWorldId");
12324
12325 if(totalNoWMImgPointsSend > 0) {
12326 mAlloc(m_wmImgSendBuffer, noPVars * totalNoWMImgPointsSend, "m_wmImgSendBuffer", 0.0, AT_);
12327 }
12328
12329 if(totalNoWMImgPointsRecv > 0) {
12330 mAlloc(m_wmImgRecvBuffer, noPVars * totalNoWMImgPointsRecv, "m_wmImgPointsRecvBuffer", 0.0, AT_);
12331 mAlloc(m_wmImgRecvIdMap, totalNoWMImgPointsRecv, "m_wmImgRecvIdMap", -1, AT_);
12332 }
12333
12334 m_wmImgCellIds.resize(m_wmNoDomains);
12335 m_wmImgWMSrfcIds.resize(m_wmNoDomains);
12336 m_wmImgCoords.resize(m_wmNoDomains);
12337
12338 mAlloc(m_noWMImgPointsSend, m_wmNoDomains, "m_noWMImgPointsSend", 0, AT_);
12339 mAlloc(m_noWMImgPointsRecv, m_wmNoDomains, "m_noWMImgPointsRecv", 0, AT_);
12340 mAlloc(m_mpi_wmRequest, m_wmNoDomains, "m_mpi_wmRequest", AT_);
12341 mAlloc(m_mpi_wmSendReq, m_wmNoDomains, "m_mpi_wmSendReq", AT_);
12342 mAlloc(m_mpi_wmRecvReq, m_wmNoDomains, "m_mpi_wmRecvReq", AT_);
12343
12344 // create reduced data structures in the order of the dedicated wm communicator
12345 for(MInt wmDom = 0; wmDom < m_wmNoDomains; wmDom++) {
12346 const MInt dom = wmIdToWorldId[wmDom];
12347 m_noWMImgPointsSend[wmDom] = noWMImgPointsSend[dom];
12348 m_noWMImgPointsRecv[wmDom] = noWMImgPointsRecv[dom];
12349 for(MInt ip = 0; ip < noWMImgPointsSend[dom]; ip++) {
12350 m_wmImgCellIds[wmDom].push_back(wmImgCellIds[dom][ip]);
12351 m_wmImgWMSrfcIds[wmDom].push_back(wmImgWMSrfcIds[dom][ip]);
12352 for(MInt dim = 0; dim < nDim; dim++) {
12353 m_wmImgCoords[wmDom].push_back(wmImgCoords[dom][nDim * ip + dim]);
12354 }
12355 }
12356 }
12357
12358 // now communicate the receive map by means of the WM communicator
12359 for(MInt wmDom = 0; wmDom < m_wmNoDomains; wmDom++) {
12360 MPI_Issend(&m_wmImgWMSrfcIds[wmDom][0], m_noWMImgPointsSend[wmDom], MPI_INT, wmDom, 0, m_comm_wm,
12361 &m_mpi_wmRequest[wmDom], AT_, "&m_wmImgSrfcIds[wmDom][0]");
12362 }
12363
12364 MPI_Status status;
12365 MInt offset = 0;
12366 for(MInt wmDom = 0; wmDom < m_wmNoDomains; wmDom++) {
12367 MPI_Recv(&m_wmImgRecvIdMap[offset], m_noWMImgPointsRecv[wmDom], MPI_INT, wmDom, 0, m_comm_wm, &status, AT_,
12368 "&m_wmImgRecvIdMap[offset]");
12369 offset += m_noWMImgPointsRecv[wmDom];
12370 }
12371
12372 for(MInt wmDom = 0; wmDom < m_wmNoDomains; wmDom++) {
12373 MPI_Wait(&m_mpi_wmRequest[wmDom], &status, AT_);
12374 }
12375
12376 // set flag in wmBndryCells that an imgCell has been found and a communication mapping has been setup correctly
12377 // cells without an img cell will need special treatment (return 0.0) in the wmViscosity computation.
12378 MInt ipCounter = 0;
12379 for(MInt dom = 0; dom < m_wmNoDomains; dom++) {
12380#ifdef _OPENMP
12381#pragma omp parallel for
12382#endif
12383 for(MInt ip = 0; ip < m_noWMImgPointsRecv[dom]; ip++) {
12384 const MInt wmSrfcId = m_wmImgRecvIdMap[ipCounter + ip];
12385 m_wmSurfaces[wmSrfcId].m_wmHasImgCell = true;
12386 }
12387 ipCounter += m_noWMImgPointsRecv[dom];
12388 }
12389 m_log << "ok." << endl;
12390}
12391
12392
12393// only for y-normal surface
12394template <MInt nDim_, class SysEqn>
12396 TRACE();
12397
12398 // read cell coordinates from property file and find cells
12399 MInt noVars = 13;
12400
12401 MInt noSurfaceProbes = Context::propertyLength("wmSurfaceProbesX", m_solverId);
12402
12403 if(noSurfaceProbes != Context::propertyLength("wmSurfaceProbesZ", m_solverId))
12404 mTerm(1, "no of coordinates for WM Surface probes must be equal for X and Z");
12405
12406 for(MInt p = 0; p < noSurfaceProbes; p++) {
12407 MFloat probeCoord[3] = {0.0, 0.0, 0.0};
12408 probeCoord[0] = Context::getSolverProperty<MFloat>("wmSurfaceProbesX", m_solverId, AT_, &probeCoord[0], p);
12409 probeCoord[2] = Context::getSolverProperty<MFloat>("wmSurfaceProbesZ", m_solverId, AT_, &probeCoord[2], p);
12410
12411 for(MInt bCellId = 0; bCellId < m_bndryCells->size(); bCellId++) {
12412 MInt cellId = m_bndryCells->a[bCellId].m_cellId;
12413 MFloat cellCoord[3] = {0.0, 0.0, 0.0};
12414 for(MInt dim = 0; dim < nDim; dim++) {
12415 cellCoord[dim] = a_coordinate(cellId, dim);
12416 }
12417 if(abs(cellCoord[0] - probeCoord[0]) < F1B2 * c_cellLengthAtLevel(maxRefinementLevel()) + m_eps
12418 && abs(cellCoord[2] - probeCoord[2]) < F1B2 * c_cellLengthAtLevel(maxRefinementLevel()) + m_eps) {
12419 if(!a_isHalo(cellId)) {
12420 for(MInt srfc = 0; srfc < m_bndryCells->a[bCellId].m_noSrfcs; srfc++) {
12421 if(m_bndryCells->a[bCellId].m_srfcs[srfc]->m_bndryCndId == 3399) {
12422 m_wmSurfaceProbeIds.push_back(cellId);
12423 m_wmSurfaceProbeSrfcs.push_back(srfc);
12424 break;
12425 }
12426 }
12427 }
12428 }
12429 }
12430 }
12431
12432 mAlloc(m_wmLocalNoSrfcProbeIds, noDomains(), "m_wmLocalNoSrfcProbeIds", 0, AT_);
12433 m_wmLocalNoSrfcProbeIds[domainId()] = m_wmSurfaceProbeIds.size();
12434 MPI_Allgather(&m_wmLocalNoSrfcProbeIds[domainId()], 1, MPI_INT, &m_wmLocalNoSrfcProbeIds[0], 1, MPI_INT, mpiComm(),
12435 AT_, "m_wmLocalNoSrfcProbeIds", "m_wmLocalNoSrfcProbeIds");
12436
12437 m_wmGlobalNoSrfcProbeIds = 0;
12438 for(MInt dom = 0; dom < noDomains(); dom++) {
12439 m_wmGlobalNoSrfcProbeIds += m_wmLocalNoSrfcProbeIds[dom];
12440 }
12441
12442 if(m_wmLocalNoSrfcProbeIds[domainId()] > 0) {
12443 mAlloc(m_wmSrfcProbeSendBuffer, noVars * m_wmLocalNoSrfcProbeIds[domainId()], "m_wmSrfcProbeSendBuffer", 0.0, AT_);
12444 }
12445 if(domainId() == 0) {
12446 mAlloc(m_wmSrfcProbeRecvBuffer, noVars * m_wmGlobalNoSrfcProbeIds, "m_wmSrfcProbeRecvBuffer", 0.0, AT_);
12447 }
12448}
12449
12450template <MInt nDim_, class SysEqn>
12452 TRACE();
12453
12454 MInt noVars = 13;
12455
12456 // Computing and Gathering variables:
12457 for(MInt p = 0; p < m_wmLocalNoSrfcProbeIds[domainId()]; p++) {
12458 MInt cellId = m_wmSurfaceProbeIds[p];
12459 MInt srfc = m_wmSurfaceProbeSrfcs[p];
12460 MInt bCellId = a_bndryId(cellId);
12461 MInt ghostCellId = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_ghostCellId;
12462
12463 MFloat pSurface = F1B2 * (a_pvariable(cellId, PV->P) + a_pvariable(ghostCellId, PV->P));
12464 MFloat rhoSurface = F1B2 * (a_pvariable(cellId, PV->RHO) + a_pvariable(ghostCellId, PV->RHO));
12465 MFloat TSurface = sysEqn().temperature_ES(rhoSurface, pSurface);
12466 MFloat mue = SUTHERLANDLAW(TSurface);
12467
12468 m_wmSrfcProbeSendBuffer[noVars * p + 0] = cellId;
12469 m_wmSrfcProbeSendBuffer[noVars * p + 1] = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_coordinates[0];
12470 m_wmSrfcProbeSendBuffer[noVars * p + 2] = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_coordinates[1];
12471 m_wmSrfcProbeSendBuffer[noVars * p + 3] = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_coordinates[2];
12472 m_wmSrfcProbeSendBuffer[noVars * p + 4] = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_normalVector[0];
12473 m_wmSrfcProbeSendBuffer[noVars * p + 5] = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_normalVector[1];
12474 m_wmSrfcProbeSendBuffer[noVars * p + 6] = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_normalVector[2];
12475 m_wmSrfcProbeSendBuffer[noVars * p + 7] = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[0]];
12476 m_wmSrfcProbeSendBuffer[noVars * p + 8] = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[1]];
12477 m_wmSrfcProbeSendBuffer[noVars * p + 9] = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[2]];
12478 m_wmSrfcProbeSendBuffer[noVars * p + 10] = mue;
12479 m_wmSrfcProbeSendBuffer[noVars * p + 11] = m_bndryCells->a[bCellId].m_wmBCVars->m_wmMUEWM;
12480 m_wmSrfcProbeSendBuffer[noVars * p + 12] = m_bndryCells->a[bCellId].m_wmBCVars->m_wmTauW;
12481 }
12482
12483 // Sending variables
12484 MPI_Issend(&m_wmSrfcProbeSendBuffer[0], m_wmLocalNoSrfcProbeIds[domainId()] * noVars, MPI_DOUBLE, 0, 0, mpiComm(),
12485 &m_mpi_wmRequest[0], AT_, "&m_wmSrfcProbeSendBuffer[0]");
12486
12487 // Receiving variables
12488 MPI_Status status;
12489 MInt offset = 0;
12490 if(domainId() == 0) {
12491 for(MInt dom = 0; dom < noDomains(); dom++) {
12492 MPI_Recv(&m_wmSrfcProbeRecvBuffer[offset], m_wmLocalNoSrfcProbeIds[dom] * noVars, MPI_DOUBLE, dom, 0, mpiComm(),
12493 &status, AT_, "&m_wmSrfcProbeRecvBuffer[offset]");
12494 offset += m_wmLocalNoSrfcProbeIds[dom] * noVars;
12495 }
12496
12497 FILE* datei;
12498 stringstream filename;
12499 filename << outputDir() << "wmSurfaceProbes_" << globalTimeStep;
12500 datei = fopen(filename.str().c_str(), "w+");
12501
12502 // print header
12503 fprintf(datei, "cellId");
12504 fprintf(datei, " x");
12505 fprintf(datei, " y");
12506 fprintf(datei, " z");
12507 fprintf(datei, " nx");
12508 fprintf(datei, " ny");
12509 fprintf(datei, " nz");
12510 fprintf(datei, " dudn");
12511 fprintf(datei, " dvdn");
12512 fprintf(datei, " dwdn");
12513 fprintf(datei, " mue");
12514 fprintf(datei, " mue_wm");
12515 fprintf(datei, " tau_wm");
12516 fprintf(datei, "\n");
12517
12518 for(MInt p = 0; p < m_wmGlobalNoSrfcProbeIds; p++) {
12519 for(MInt v = 0; v < noVars; v++) {
12520 fprintf(datei, "%f ", m_wmSrfcProbeRecvBuffer[p * noVars + v]);
12521 }
12522 fprintf(datei, "\n");
12523 }
12524 fclose(datei);
12525 }
12526}
12527
12528
12529//-----------------------------------------------------------------------------
12530
12531template <MInt nDim_, class SysEqn>
12533 TRACE();
12534 const MInt noFVars = FV->noVariables;
12535 //---
12536
12537
12538 // reset rhs rot periodic cells (azimuthal periodicity concept)
12539 if(m_periodicCells == 1 || m_periodicCells == 2 || m_periodicCells == 3) {
12540#ifdef _OPENMP
12541#pragma omp parallel for collapse(2)
12542#endif
12543 for(MInt c = 0; c < m_sortedPeriodicCells->size(); c++) {
12544 for(MInt v = 0; v < noFVars; v++) {
12545 a_rightHandSide(m_sortedPeriodicCells->a[c], v) = F0;
12546 }
12547 }
12548 }
12549
12550// reset rhs of cutoff boundary cells
12551#ifdef _OPENMP
12552#pragma omp parallel for
12553#endif
12554 for(MInt bcId = 0; bcId < m_fvBndryCnd->m_noCutOffBndryCndIds; bcId++) {
12555 const MInt noCutOffCells = m_fvBndryCnd->m_sortedCutOffCells[bcId]->size();
12556 for(MInt scc = 0; scc < noCutOffCells; scc++) {
12557 for(MInt v = 0; v < noFVars; v++) {
12558 a_rightHandSide(m_fvBndryCnd->m_sortedCutOffCells[bcId]->a[scc], v) = F0;
12559 }
12560 }
12561 }
12562}
12563
12564
12565// --------------------------------------------------------------------------------------
12566
12567
12576template <MInt nDim_, class SysEqn>
12578 const MInt noCells = a_noCells();
12579 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
12580 const MInt noSrfcs = a_noSurfaces();
12581 MFloat* area = &a_surfaceArea(0);
12582 MFloatScratchSpace cellSurfaceAreas(noCells, nDim, AT_, "cellSurfaceAreas");
12583 MInt cellId0, cellId1;
12584 MFloat eps = 1e-20; // allow for a small difference which can be due to roundoff errors
12585 stringstream filename;
12586
12587 //---
12588
12589 // reset
12590 for(MInt cellId = 0; cellId < noCells; cellId++) {
12591 for(MInt i = 0; i < nDim; i++) {
12592 cellSurfaceAreas(cellId, i) = F0;
12593 }
12594 }
12595
12596 // compute the total area
12597 for(MInt s = 0; s < noSrfcs; s++) {
12598 cellId0 = a_surfaceNghbrCellId(s, 0);
12599 cellId1 = a_surfaceNghbrCellId(s, 1);
12600 if(cellId0 > noCells) continue;
12601 if(cellId1 > noCells) continue;
12602 cellSurfaceAreas(cellId0, a_surfaceOrientation(s)) += area[s];
12603 cellSurfaceAreas(cellId1, a_surfaceOrientation(s)) -= area[s];
12604 }
12605
12606 // correct surfaces which are connected to small cells
12607 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
12608 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == -1) continue;
12609 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > noCells) continue;
12610 for(MInt dir = 0; dir < nDim; dir++) {
12611 cellSurfaceAreas(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId, dir) +=
12612 cellSurfaceAreas(m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId, dir);
12613 cellSurfaceAreas(m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId, dir) = F0;
12614 }
12615 }
12616
12617 for(MInt cellId = 0; cellId < noCells; cellId++) {
12618 for(MInt dir = 0; dir < nDim; dir++) {
12619 // only check cells which are regular computing cells (no ghost cells, multisolver halo cells etc...) -> can be
12620 // extended to moving boundary active cells
12621 if(abs(cellSurfaceAreas(cellId, dir)) > eps && a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)
12622 && !a_hasProperty(cellId, SolverCell::IsPeriodicWithRot) && (!a_isBndryGhostCell(cellId))
12623 && (!a_hasProperty(cellId, SolverCell::IsNotGradient)) && (!a_isHalo(cellId))) {
12624 // m_log << "[" << domainId() << "]: Cell Surfaces are not balanced! " <<
12625 // endl; m_log << "[" << domainId() << "]: CellId: " << cellId << ", Area: "
12626 // << cellSurfaceAreas(cellId, dir) << ", direction:" << dir << endl; m_log <<
12627 // "["
12628 // << domainId() << "]: ... is a boundary cell:" << (a_bndryId(cellId) >
12629 // -1) << endl;
12630 }
12631 }
12632 }
12633}
12634
12635
12636template <MInt nDim_, class SysEqn>
12638 TRACE();
12639
12640 m_fvBndryCnd->copyVarsToSmallCells();
12641}
12642
12643
12644// ---------------------------------------------------------------------------
12645
12646
12651template <MInt nDim_, class SysEqn>
12653 const MFloat* const RESTRICT pvars = &a_pvariable(cellId, 0);
12654 MFloat* const RESTRICT cvars = &a_variable(cellId, 0);
12655 const MFloat* const RESTRICT avars = hasAV ? &a_avariable(cellId, 0) : nullptr;
12656
12657 IF_CONSTEXPR(isDetChem<SysEqn>) setMeanMolarWeight_PV(cellId);
12658
12659 sysEqn().computeConservativeVariables(pvars, cvars, avars);
12660}
12661
12662template <MInt nDim, class SysEqn>
12663template <class _, std::enable_if_t<isEEGas<SysEqn>, _*>>
12665 if(m_EEGas.depthCorrectionCoefficients.size() != nDim)
12666 mTerm(1, AT_, "depthCorrectionCoefficients initialized incorrectly!");
12667 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
12668 MFloat depthCorrectionValue = 0.0;
12669 for(MInt i = 0; i < nDim; i++) {
12670 const MFloat deltaH = a_coordinate(cellId, i) - m_EEGas.gravityRefCoords[i];
12671 depthCorrectionValue += m_EEGas.liquidDensity * m_EEGas.depthCorrectionCoefficients[i] * deltaH;
12672 }
12673 a_avariable(cellId, AV->DC) = depthCorrectionValue;
12674 }
12675}
12676
12677
12678// ---------------------------------------------------------------------------
12679
12680
12687template <MInt nDim_, class SysEqn>
12689 TRACE();
12690
12691 if(m_fvBndryCnd->m_cellMerging) return;
12692
12693 if(noNeighborDomains() == 0 && grid().noAzimuthalNeighborDomains() == 0
12694 && m_azimuthalRemappedNeighborDomains.size() == 0)
12695 return;
12696
12697#ifndef NDEBUG
12698 MInt test0 = 0;
12699 MInt test1 = 0;
12700 for(MInt i = 0; i < noNeighborDomains(); i++) {
12701 test0 += m_noMaxLevelHaloCells[i];
12702 test1 += m_noMaxLevelWindowCells[i];
12703 }
12704 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
12705 test0 += m_azimuthalMaxLevelHaloCells[i].size();
12706 test1 += m_azimuthalMaxLevelWindowCells[i].size();
12707 }
12708 if(test0 == 0 && test1 == 0) {
12709 mTerm(1, AT_, "Max level exchange has not yet been initialized.");
12710 }
12711#endif
12712
12713 MIntScratchSpace activeFlag(a_noCells(), AT_, "activeFlag");
12714 MIntScratchSpace sendBufferCnts(noNeighborDomains(), AT_, "sendBufferCnts");
12715 MIntScratchSpace recvBufferCnts(noNeighborDomains(), AT_, "recvBufferCnts");
12716 ScratchSpace<MPI_Request> sendReq(noNeighborDomains(), AT_, "sendReq");
12717 ScratchSpace<MPI_Request> recvReq(noNeighborDomains(), AT_, "recvReq");
12718
12719 sendBufferCnts.fill(0);
12720 recvBufferCnts.fill(0);
12721 sendReq.fill(MPI_REQUEST_NULL);
12722 recvReq.fill(MPI_REQUEST_NULL);
12723 for(MInt i = 0; i < noNeighborDomains(); i++) {
12724 m_fvBndryCnd->m_nearBoundaryWindowCells[i].clear();
12725 m_fvBndryCnd->m_nearBoundaryHaloCells[i].clear();
12726 }
12727
12728 activeFlag.fill(0);
12729
12730 setActiveFlag(activeFlag, mode, offset);
12731
12732 setAdditionalActiveFlag(activeFlag);
12733
12734 if(grid().azimuthalPeriodicity()) {
12735 initAzimuthalNearBoundaryExchange(activeFlag);
12736 }
12737
12738 for(MInt i = 0; i < noNeighborDomains(); i++) {
12739 MInt sendBufferCounter = 0;
12740 for(MInt j = 0; j < m_noMaxLevelHaloCells[i]; j++) {
12741 MInt cellId = m_maxLevelHaloCells[i][j];
12742 m_receiveBuffers[i][sendBufferCounter] = F0;
12743 if(activeFlag(cellId)) {
12744 m_receiveBuffers[i][sendBufferCounter] = F1;
12745 m_fvBndryCnd->m_nearBoundaryHaloCells[i].push_back(cellId);
12746 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) {
12747 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
12748 if(cellId != m_splitCells[sc]) continue;
12749 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
12750 m_fvBndryCnd->m_nearBoundaryHaloCells[i].push_back(m_splitChilds[sc][ssc]);
12751 }
12752 }
12753 }
12754 }
12755 sendBufferCounter++;
12756 }
12757 ASSERT(sendBufferCounter == m_noMaxLevelHaloCells[i], "");
12758 sendBufferCnts(i) = sendBufferCounter;
12759 recvBufferCnts(i) = m_noMaxLevelWindowCells[i];
12760 }
12761
12762 if(noNeighborDomains() > 0) {
12763 if(m_nonBlockingComm) {
12764 for(MInt i = 0; i < noNeighborDomains(); i++) {
12765 ASSERT(recvBufferCnts(i) <= m_noMaxLevelWindowCells[i] * m_dataBlockSize, "");
12766 MPI_Irecv(m_sendBuffers[i], recvBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 2, mpiComm(), &recvReq[i], AT_,
12767 "m_sendBuffers[i]");
12768 }
12769 for(MInt i = 0; i < noNeighborDomains(); i++) {
12770 ASSERT(sendBufferCnts(i) <= m_noMaxLevelHaloCells[i] * m_dataBlockSize, "");
12771 MPI_Isend(m_receiveBuffers[i], sendBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 2, mpiComm(), &sendReq[i], AT_,
12772 "m_receiveBuffers[i]");
12773 }
12774 MPI_Waitall(noNeighborDomains(), &recvReq[0], MPI_STATUSES_IGNORE, AT_);
12775 MPI_Waitall(noNeighborDomains(), &sendReq[0], MPI_STATUSES_IGNORE, AT_);
12776 } else {
12777 for(MInt i = 0; i < noNeighborDomains(); i++) {
12778 ASSERT(sendBufferCnts(i) <= m_noMaxLevelHaloCells[i] * m_dataBlockSize, "");
12779 MPI_Issend(m_receiveBuffers[i], sendBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 2, mpiComm(), &sendReq[i],
12780 AT_, "m_receiveBuffers[i]");
12781 }
12782 for(MInt i = 0; i < noNeighborDomains(); i++) {
12783 ASSERT(recvBufferCnts(i) <= m_noMaxLevelWindowCells[i] * m_dataBlockSize, "");
12784 MPI_Recv(m_sendBuffers[i], recvBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 2, mpiComm(), MPI_STATUS_IGNORE,
12785 AT_, "m_sendBuffers[i]");
12786 }
12787 MPI_Waitall(noNeighborDomains(), &sendReq[0], MPI_STATUSES_IGNORE, AT_);
12788 }
12789
12790 for(MInt i = 0; i < noNeighborDomains(); i++) {
12791 MInt recvBufferCounter = 0;
12792 for(MInt j = 0; j < m_noMaxLevelWindowCells[i]; j++) {
12793 MInt cellId = m_maxLevelWindowCells[i][j];
12794 if((MInt)m_sendBuffers[i][recvBufferCounter]) {
12795 m_fvBndryCnd->m_nearBoundaryWindowCells[i].push_back(cellId);
12796 ASSERT(c_noChildren(cellId) == 0, "");
12797 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) {
12798 for(MUint sc = 0; sc < m_splitCells.size(); sc++) {
12799 if(cellId != m_splitCells[sc]) continue;
12800 for(MUint ssc = 0; ssc < m_splitChilds[sc].size(); ssc++) {
12801 m_fvBndryCnd->m_nearBoundaryWindowCells[i].push_back(m_splitChilds[sc][ssc]);
12802 }
12803 }
12804 }
12805 }
12806 recvBufferCounter++;
12807 }
12808 }
12809 }
12810
12811
12812#ifdef _MB_DEBUG_
12813 if(globalTimeStep % 100 == 0) {
12814 MLong totalMaxLevelHaloCells = 0;
12815 MLong totalMaxLevelWindowCells = 0;
12816 MLong totalNearBoundaryHaloCells = 0;
12817 MLong totalNearBoundaryWindowCells = 0;
12818 m_log << "Near-boundary exchange size:" << endl;
12819 for(MInt i = 0; i < noNeighborDomains(); i++) {
12820 m_log << "D" << neighborDomain(i) << ":"
12821 << " " << m_fvBndryCnd->m_nearBoundaryWindowCells[i].size() << "/" << m_noMaxLevelWindowCells[i] << " "
12822 << m_fvBndryCnd->m_nearBoundaryHaloCells[i].size() << "/" << m_noMaxLevelHaloCells[i] << endl;
12823 totalMaxLevelHaloCells += m_noMaxLevelHaloCells[i];
12824 totalMaxLevelWindowCells += m_noMaxLevelWindowCells[i];
12825 totalNearBoundaryHaloCells += (signed)m_fvBndryCnd->m_nearBoundaryHaloCells[i].size();
12826 totalNearBoundaryWindowCells += (signed)m_fvBndryCnd->m_nearBoundaryWindowCells[i].size();
12827 }
12828 MPI_Allreduce(MPI_IN_PLACE, &totalMaxLevelHaloCells, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
12829 "totalMaxLevelHaloCells");
12830 MPI_Allreduce(MPI_IN_PLACE, &totalMaxLevelWindowCells, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
12831 "totalMaxLevelWindowCells");
12832 MPI_Allreduce(MPI_IN_PLACE, &totalNearBoundaryHaloCells, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
12833 "totalNearBoundaryHaloCells");
12834 MPI_Allreduce(MPI_IN_PLACE, &totalNearBoundaryWindowCells, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
12835 "totalNearBoundaryWindowCells");
12836 m_log << "Global near-boundary exchange size: " << totalNearBoundaryWindowCells << "/" << totalMaxLevelWindowCells
12837 << " (" << 100.0 * ((MFloat)totalNearBoundaryWindowCells / (MFloat)totalMaxLevelWindowCells) << "%)"
12838 << " - " << totalNearBoundaryHaloCells << "/" << totalMaxLevelHaloCells << " ("
12839 << 100.0 * ((MFloat)totalNearBoundaryHaloCells / (MFloat)totalMaxLevelHaloCells) << "%)" << endl;
12840 }
12841#endif
12842}
12843
12844
12847template <MInt nDim_, class SysEqn>
12849 const MInt offset) {
12850 TRACE();
12851
12852 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
12853 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
12854 // maxLevelChange!
12855 const MFloat vfrac = a_cellVolume(cellId) / grid().cellVolumeAtLevel(maxLevel());
12856 MBool atWall = false;
12857 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
12858 if(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId / 1000 == 3) atWall = true;
12859 }
12860 const MFloat volumeLimit = atWall ? m_fvBndryCnd->m_volumeLimitWall : m_fvBndryCnd->m_volumeLimitOther;
12861 if(mode == 0 && vfrac > volumeLimit) continue;
12862 if(mode == 1 && bndryId < offset && vfrac > volumeLimit) continue;
12863 activeFlag(cellId) = 1;
12864 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
12865 const MUint noRecNghbrs = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size();
12866 for(MUint n = noSrfcs; n < noRecNghbrs; n++) {
12867 MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
12868 if(nghbrId < 0) continue;
12869 activeFlag(nghbrId) = 1;
12870 if(a_hasProperty(nghbrId, SolverCell::IsSplitChild)) {
12871 activeFlag(getAssociatedInternalCell(nghbrId)) = 1;
12872 }
12873 }
12874 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && !a_hasProperty(cellId, SolverCell::IsSplitClone)) {
12875 for(MInt dir = 0; dir < m_noDirs; dir++) {
12876 if(checkNeighborActive(cellId, dir) && a_hasNeighbor(cellId, dir)) {
12877 activeFlag(c_neighborId(cellId, dir)) = 1;
12878 }
12879 }
12880 }
12881 }
12882}
12883
12884
12885// ---------------------------------------------------------------------------
12886
12887
12888#ifndef NDEBUG
12889template <MInt nDim_, class SysEqn>
12891 MBool solutionDiverged = false;
12892 const MInt noCVars = CV->noVariables;
12893
12894 for(MInt i = 0; i < noNeighborDomains(); i++) {
12895 if(m_fvBndryCnd->m_nearBoundaryHaloCells[i].empty()) {
12896 continue;
12897 }
12898 for(MUint j = 0; j < m_fvBndryCnd->m_nearBoundaryHaloCells[i].size(); j++) {
12899 MInt cellId = m_fvBndryCnd->m_nearBoundaryHaloCells[i][j];
12900 const MInt rootId =
12901 (a_hasProperty(cellId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(cellId) : cellId;
12902 IF_CONSTEXPR(!isEEGas<SysEqn>) {
12903 for(MInt v = 0; v < noCVars; v++) {
12904 if(!(a_variable(cellId, v) >= F0 || a_variable(cellId, v) < F0) || std::isnan(a_variable(cellId, v))) {
12905 cerr << domainId() << ": EXC1 " << i << " " << j << " " << c_globalId(cellId) << " " << a_bndryId(cellId)
12906 << " " << a_level(cellId) << " /v " << a_cellVolume(cellId) / grid().gridCellVolume(a_level(rootId))
12907 << " "
12908 << (a_bndryId(cellId) > -1 ? m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_volume
12909 / grid().gridCellVolume(a_level(rootId))
12910 : 99999)
12911 << " " << v << " " << a_variable(cellId, v) << " " << a_coordinate(cellId, 0) << " "
12912 << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, nDim - 1) << " "
12913 << a_hasProperty(cellId, SolverCell::IsSplitChild) << " "
12914 << a_hasProperty(cellId, SolverCell::IsSplitCell) << endl;
12915 solutionDiverged = true;
12916 }
12917 }
12918 }
12919 if(a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) > m_fvBndryCnd->m_volumeLimitWall) {
12920 setPrimitiveVariables(cellId);
12921 if(a_pvariable(cellId, PV->RHO) < F0 || a_pvariable(cellId, PV->P) < F0) {
12922 cerr << domainId() << ": EXC1 " << i << " " << j << " " << c_globalId(cellId) << " " << a_bndryId(cellId)
12923 << " " << a_level(cellId) << " /r " << a_pvariable(cellId, PV->RHO) << " /p "
12924 << a_pvariable(cellId, PV->P) << " /v " << a_cellVolume(cellId) / grid().gridCellVolume(a_level(rootId))
12925 << " "
12926 << (a_bndryId(cellId) > -1 ? m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_volume
12927 / grid().gridCellVolume(a_level(rootId))
12928 : 99999)
12929 << " " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " "
12930 << a_coordinate(cellId, nDim - 1) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild) << " "
12931 << a_hasProperty(cellId, SolverCell::IsSplitCell) << endl;
12932 cerr << " vel " << a_pvariable(cellId, PV->VV[0]) << " " << a_pvariable(cellId, PV->VV[1]) << " "
12933 << a_pvariable(cellId, PV->VV[nDim - 1]) << endl;
12934 solutionDiverged = true;
12935 }
12936 }
12937 }
12938 }
12939
12940 if(grid().azimuthalPeriodicity()) {
12941 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
12942 if(m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i].empty()) {
12943 continue;
12944 }
12945 for(MUint j = 0; j < m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i].size(); j++) {
12946 MInt cellId = m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i][j];
12947 const MInt rootId =
12948 (a_hasProperty(cellId, SolverCell::IsSplitChild)) ? getAssociatedInternalCell(cellId) : cellId;
12949 for(MInt v = 0; v < noCVars; v++) {
12950 if(!(a_variable(cellId, v) >= F0 || a_variable(cellId, v) < F0) || std::isnan(a_variable(cellId, v))) {
12951 cerr << domainId() << ": EXC1 Azi " << i << " " << j << " " << c_globalId(cellId) << " "
12952 << a_bndryId(cellId) << " " << a_level(cellId) << " /v "
12953 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(rootId)) << " "
12954 << (a_bndryId(cellId) > -1 ? m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_volume
12955 / grid().gridCellVolume(a_level(rootId))
12956 : 99999)
12957 << " " << v << " " << a_variable(cellId, v) << " " << a_coordinate(cellId, 0) << " "
12958 << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, nDim - 1) << " "
12959 << a_hasProperty(cellId, SolverCell::IsSplitChild) << " "
12960 << a_hasProperty(cellId, SolverCell::IsSplitCell) << endl;
12961 solutionDiverged = true;
12962 }
12963 }
12964 if(a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) > m_fvBndryCnd->m_volumeLimitWall) {
12965 setPrimitiveVariables(cellId);
12966 if(a_pvariable(cellId, m_sysEqn.PV->RHO) < F0 || a_pvariable(cellId, m_sysEqn.PV->P) < F0) {
12967 cerr << domainId() << ": EXC1 Azi " << i << " " << j << " " << c_globalId(cellId) << " "
12968 << a_bndryId(cellId) << " " << a_level(cellId) << " /r " << a_pvariable(cellId, m_sysEqn.PV->RHO)
12969 << " /p " << a_pvariable(cellId, m_sysEqn.PV->P) << " /v "
12970 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(rootId)) << " "
12971 << (a_bndryId(cellId) > -1 ? m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_volume
12972 / grid().gridCellVolume(a_level(rootId))
12973 : 99999)
12974 << " " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " "
12975 << a_coordinate(cellId, nDim - 1) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild) << " "
12976 << a_hasProperty(cellId, SolverCell::IsSplitCell) << endl;
12977 cerr << " vel " << a_pvariable(cellId, m_sysEqn.PV->VV[0]) << " " << a_pvariable(cellId, m_sysEqn.PV->VV[1])
12978 << " " << a_pvariable(cellId, m_sysEqn.PV->VV[nDim - 1]) << endl;
12979 solutionDiverged = true;
12980 }
12981 }
12982 }
12983 }
12984 }
12985 if(solutionDiverged) {
12986 cerr << "Solution diverged (BEXC" << x << ") at solver " << domainId() << " " << globalTimeStep << " " << m_RKStep
12987 << endl;
12988 }
12989 if(noDomains() > 1) {
12990 // Convert data to MInt before MPI call and copy back afterwards
12991 MInt tmp = solutionDiverged;
12992 MPI_Allreduce(MPI_IN_PLACE, &tmp, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "tmp");
12993 solutionDiverged = tmp;
12994 }
12995 if(solutionDiverged) {
12996 saveSolverSolution(1);
12997 MPI_Barrier(mpiComm(), AT_);
12998 mTerm(1, AT_, "Solution diverged after near boundary exchange.");
12999 }
13000}
13001#endif
13002
13013template <MInt nDim_, class SysEqn>
13015 TRACE();
13016
13017 if(m_fvBndryCnd->m_cellMerging || m_fvBndryCnd->m_smallCellRHSCorrection) {
13018 return;
13019 }
13020
13021 RECORD_TIMER_START(m_timers[Timers::SCCorrInit]);
13022
13023 // Claudia Note: Hier pruefen! -> TINA transient braucht ab und zu conservation = false um weiterzulaufen (kleine
13024 // Ventilspalte)
13025 const MBool conservation = (m_RKStep == 0);
13026 // the final Runge-Kutta step is sufficient to maintain conservation, however, steady-state
13027 // solutions are then dependent on the time step size! (Lennart)
13028 const MInt noSmallCells = (signed)m_fvBndryCnd->m_smallCutCells.size();
13029 const MInt noCVars = CV->noVariables;
13030 const MInt noPVars = PV->noVariables;
13031 const MInt noAVars = AV->noVariables;
13032 const MInt volFactor = nDim == 3 ? 4 : 2;
13033
13034 MFloatScratchSpace redistFac(noSmallCells, AT_, "redistFac");
13035 MFloatScratchSpace delta(noSmallCells, noCVars, AT_, "delta");
13036 MIntScratchSpace sendBufferCnts(mMax(1, noNeighborDomains()), AT_, "sendBufferCnts");
13037 MIntScratchSpace recvBufferCnts(mMax(1, noNeighborDomains()), AT_, "recvBufferCnts");
13038 ScratchSpace<MPI_Request> sendReq(mMax(1, noNeighborDomains()), AT_, "sendReq");
13039 ScratchSpace<MPI_Request> recvReq(mMax(1, noNeighborDomains()), AT_, "recvReq");
13040
13041 //-------------
13042
13043 // 0. Init
13044 redistFac.fill(F0);
13045 delta.fill(F0);
13046
13047 RECORD_TIMER_STOP(m_timers[Timers::SCCorrInit]);
13048 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange1]);
13049
13050 // azimuthal periodicity concept
13051 if(m_periodicCells == 2 || m_periodicCells == 3) {
13052 computePV();
13053 exchangePeriodic();
13054 }
13055
13056 // 2. Request conservative variables of involved halo cells
13057 {
13058 sendReq.fill(MPI_REQUEST_NULL);
13059 recvReq.fill(MPI_REQUEST_NULL);
13060 sendBufferCnts.fill(0);
13061 recvBufferCnts.fill(0);
13062 for(MInt i = 0; i < noNeighborDomains(); i++) {
13063 sendBufferCnts(i) = noCVars * (signed)m_fvBndryCnd->m_nearBoundaryWindowCells[i].size();
13064 recvBufferCnts(i) = noCVars * (signed)m_fvBndryCnd->m_nearBoundaryHaloCells[i].size();
13065 if(m_fvBndryCnd->m_nearBoundaryWindowCells[i].empty()) continue;
13066 MInt sendBufferCounter = 0;
13067 for(MUint j = 0; j < m_fvBndryCnd->m_nearBoundaryWindowCells[i].size(); j++) {
13068 MInt cellId = m_fvBndryCnd->m_nearBoundaryWindowCells[i][j];
13069 for(MInt v = 0; v < noCVars; v++) {
13070 m_sendBuffers[i][sendBufferCounter] = a_variable(cellId, v);
13071 sendBufferCounter++;
13072 }
13073 }
13074 }
13075
13076 MInt sendCnt = 0;
13077 MInt recvCnt = 0;
13078 if(m_nonBlockingComm) {
13079 for(MInt i = 0; i < noNeighborDomains(); i++) {
13080 if(sendBufferCnts(i) == 0) continue;
13081 ASSERT(sendBufferCnts(i) <= m_noMaxLevelWindowCells[i] * m_dataBlockSize, "");
13082 MPI_Isend(m_sendBuffers[i], sendBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 12, mpiComm(), &sendReq[sendCnt],
13083 AT_, "m_sendBuffers[i]");
13084 sendCnt++;
13085 }
13086 for(MInt i = 0; i < noNeighborDomains(); i++) {
13087 if(recvBufferCnts(i) == 0) continue;
13088 ASSERT(recvBufferCnts(i) <= m_noMaxLevelHaloCells[i] * m_dataBlockSize, "");
13089 MPI_Irecv(m_receiveBuffers[i], recvBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 12, mpiComm(),
13090 &recvReq[recvCnt], AT_, "m_receiveBuffers[i]");
13091 recvCnt++;
13092 }
13093 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange1Wait]);
13094 if(recvCnt > 0) MPI_Waitall(recvCnt, &recvReq[0], MPI_STATUSES_IGNORE, AT_);
13095 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange1Wait]);
13096 } else {
13097 for(MInt i = 0; i < noNeighborDomains(); i++) {
13098 if(sendBufferCnts(i) == 0) continue;
13099 ASSERT(sendBufferCnts(i) <= m_noMaxLevelWindowCells[i] * m_dataBlockSize, "");
13100 MPI_Issend(m_sendBuffers[i], sendBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 12, mpiComm(), &sendReq[sendCnt],
13101 AT_, "m_sendBuffers[i]");
13102 sendCnt++;
13103 }
13104 for(MInt i = 0; i < noNeighborDomains(); i++) {
13105 if(recvBufferCnts(i) == 0) continue;
13106 ASSERT(recvBufferCnts(i) <= m_noMaxLevelHaloCells[i] * m_dataBlockSize, "");
13107 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange1Wait]);
13108 MPI_Recv(m_receiveBuffers[i], recvBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 12, mpiComm(),
13109 MPI_STATUS_IGNORE, AT_, "m_receiveBuffers[i]");
13110 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange1Wait]);
13111 recvCnt++;
13112 }
13113 }
13114 for(MInt i = 0; i < noNeighborDomains(); i++) {
13115 if(m_fvBndryCnd->m_nearBoundaryHaloCells[i].empty()) continue;
13116 MInt recvBufferCounter = 0;
13117 for(MUint j = 0; j < m_fvBndryCnd->m_nearBoundaryHaloCells[i].size(); j++) {
13118 MInt cellId = m_fvBndryCnd->m_nearBoundaryHaloCells[i][j];
13119 for(MInt v = 0; v < noCVars; v++) {
13120 a_variable(cellId, v) = m_receiveBuffers[i][recvBufferCounter];
13121 recvBufferCounter++;
13122 }
13123 }
13124 }
13125 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange1Wait]);
13126 if(sendCnt > 0) MPI_Waitall(sendCnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
13127 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange1Wait]);
13128
13129 if(grid().azimuthalPeriodicity()) {
13130 azimuthalNearBoundaryExchange();
13131 }
13132
13133
13134#ifndef NDEBUG
13135 divCheck(1);
13136#endif
13137 }
13138
13139 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange1]);
13140 RECORD_TIMER_START(m_timers[Timers::SCCorrInterp]);
13141
13142 // 3. Compute stable update for internal small cells
13143#if !defined NDEBUG || defined _MB_DEBUG_
13144 MInt nanCnt = 0;
13145#endif
13146
13147 // doesnot work correctly with openmp
13148 // 0) Compute the volume-sum for all reconstruction-neighbors of the small-cell
13149 for(MInt smallc = 0; smallc < noSmallCells; smallc++) {
13150 const MInt bndryId = m_fvBndryCnd->m_smallCutCells[(unsigned)smallc];
13151 ASSERT(std::count(m_fvBndryCnd->m_smallCutCells.begin(), m_fvBndryCnd->m_smallCutCells.end(), bndryId) == 1, "");
13152 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
13153 if(a_isPeriodic(cellId)) {
13154 continue;
13155 }
13156 if(a_isHalo(cellId)) {
13157 continue;
13158 }
13159 if(a_hasProperty(cellId, SolverCell::IsPeriodicWithRot)) {
13160 continue;
13161 }
13162 // correct for cbc cutOff cells!
13163 if(a_hasProperty(cellId, SolverCell::IsCutOff) && !m_fvBndryCnd->m_cbcSmallCellCorrection) continue;
13164
13165 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
13166 const MUint noRecNghbrs = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size();
13167 if(noRecNghbrs == 0) {
13168 cerr << domainId() << ": Warning: no reconstruction posible in small cell " << cellId << endl;
13169 continue;
13170 }
13171 MFloat sum = F0;
13172 // MFloat sum0 = F0;
13173 for(MUint n = (unsigned)noSrfcs + 1; n < noRecNghbrs; n++) {
13174 const MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
13175 if(nghbrId < 0) {
13176 continue;
13177 }
13178 // consider volume of cbc cutOff cells
13179 if(a_hasProperty(nghbrId, SolverCell::IsCutOff) && !m_fvBndryCnd->m_cbcSmallCellCorrection) continue;
13180 // for a smallcell cbc cutOff cell, all corresponding noncutOff cells
13181 // should be skipped for interpolation!
13182
13183 // MFloat dx = F0;
13184 // for ( MInt i = 0; i < nDim; i++ ) {
13185 // dx += POW2( a_coordinate( nghbrId , i ) - a_coordinate( cellId , i ) );
13186 //}
13187 // sum0 += a_cellVolume( nghbrId );
13188 sum += a_cellVolume(nghbrId); // * RBF( dx, POW2( cellLength[ a_level(cellId) ] ) ) ;
13189 }
13190 // if ( sum0 < F1B2* grid().gridCellVolume( a_level(cellId) ) ) cerr << "Warning: redistribution small vol. " <<
13191 // cellId
13192 // << " " << sum0/ grid().gridCellVolume( a_level(cellId) ) << endl;
13193 for(auto n = (unsigned)noSrfcs; n < noRecNghbrs; n++) {
13194 setPrimitiveVariables(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n]);
13195 }
13196
13197 MFloatScratchSpace pvars(noPVars, AT_, "pvars");
13198 for(MInt v = 0; v < noPVars; v++) {
13199 pvars[v] = F0;
13200 MInt stencil = 0;
13201 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
13202 const MInt bc = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v];
13203
13204 if(bc != BC_DIRICHLET) {
13205 stencil += IPOW2(srfc);
13206 }
13207
13208 switch(bc) {
13209 case BC_DIRICHLET:
13210 a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[srfc],
13211 v) =
13212 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v]; // set the dummy vars
13213 break;
13214 case BC_NEUMANN:
13215 a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[srfc],
13216 v) =
13217 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[v]; // set the dummy vars
13218 break;
13219 case BC_ROBIN:
13220 case BC_ISOTHERMAL:
13221 a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[srfc],
13222 v) = F0; // m_fvBndryCnd->m_bndryCell[ bndryId ].m_srfcVariables[srfc]->m_normalDeriv[v]; //set
13223 // the dummy vars
13224 break;
13225 case BC_UNSET:
13226 default:
13227 mTerm(1, AT_,
13228 "Invalid BC type in FvCartesianSolverXD::smallCellCorrection(). "
13229 + to_string(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId) + " "
13230 + to_string(cellId) + " " + to_string(noSrfcs));
13231 }
13232 }
13233 pvars[v] = F0;
13234 for(MUint n = 0; n < noRecNghbrs; n++) {
13235 if(fabs(m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + stencil]) > m_eps) {
13236 pvars[v] += m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + stencil]
13237 * a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], v);
13238
13239
13240#if !defined NDEBUG || defined _MB_DEBUG_
13241 if(nanCnt < 100
13242 && (std::isnan(m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + stencil])
13243 || std::isnan(a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], v)))) {
13244 cerr << domainId() << ": "
13245 << " nan detected in smallCellCorrection " << globalTimeStep << "/" << m_RKStep << " "
13246 << " " << cellId << "(" << c_globalId(cellId) << ")"
13247 << " " << n << "/" << noRecNghbrs << " " << v << " " << stencil << " "
13248 << m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n] << "("
13249 << c_globalId(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n]) << ")"
13250 << " " << m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + stencil] << " "
13251 << a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], v) << " "
13252 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << " "
13253 << a_cellVolume(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n])
13254 / grid().gridCellVolume(a_level(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n]))
13255 << endl;
13256 nanCnt++;
13257 if(nanCnt == 100) cerr << domainId() << ": More than 100 nan's, not reporting any more." << endl;
13258 }
13259#endif
13260 }
13261 }
13262 }
13263
13264
13265 //====================
13266 // labels:FV EULER hack
13267 if(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcs[0]->m_bndryCndId == 3007) {
13268 MFloat pvars2[5];
13269 for(MInt i = 0; i < nDim; i++) {
13270 MInt stencil = 1;
13271 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
13272 a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[srfc], PV->VV[i]) = F0;
13273 }
13274 pvars2[PV->VV[i]] = F0;
13275 for(MUint n = 0; n < noRecNghbrs; n++) {
13276 pvars2[PV->VV[i]] += m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + stencil]
13277 * a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->VV[i]);
13278 }
13279 }
13280 MFloat vel[3];
13281 for(MInt i = 0; i < nDim; i++) {
13282 vel[i] = pvars2[PV->VV[i]];
13283 for(MInt j = 0; j < nDim; j++) {
13284 vel[i] += m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] * (pvars[PV->VV[j]] - pvars2[PV->VV[j]])
13285 * m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[j];
13286 }
13287 }
13288 for(MInt i = 0; i < nDim; i++) {
13289 pvars[PV->VV[i]] = vel[i];
13290 }
13291 }
13292 if(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[0]->m_variablesType[PV->RHO] == BC_ISOTHERMAL) {
13293 MInt stencil = 0;
13294 for(MInt v = 0; v < noPVars; v++) {
13295 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
13296 a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[srfc], v) =
13297 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[v];
13298 }
13299 }
13300 MFloat Tc = F0;
13301 for(MUint n = 0; n < noRecNghbrs; n++) {
13302 if(fabs(m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + stencil]) > m_eps) {
13303 MFloat Tn = F0;
13304 IF_CONSTEXPR(isDetChem<SysEqn>) {
13305 Tn = a_avariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], AV->W_MEAN)
13306 * a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->P)
13307 / (a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->RHO) * m_gasConstant);
13308 }
13309 else {
13310 Tn = sysEqn().temperature_ES(a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->RHO),
13311 a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->P));
13312 }
13313 // if ( (signed)n < noSrfcs ) Tn = m_bodyTemperature[
13314 // m_internalBodyId[m_bndryCells->a[bndryId].m_srfcs[n]->m_bodyId[0]] ];
13315 Tc += m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + stencil] * Tn;
13316 }
13317 }
13318
13319 IF_CONSTEXPR(isDetChem<SysEqn>) {
13320 MFloatScratchSpace avars(noAVars, AT_, "avars");
13321 avars[AV->W_MEAN] = [&] {
13322 MFloat fRecMeanMolarWeight = F0;
13323 for(MUint s = 0; s < PV->m_noSpecies; ++s) {
13324 fRecMeanMolarWeight += pvars[PV->Y[s]] * sysEqn().m_species->fMolarMass[s];
13325 }
13326 const MFloat recMeanMolarWeight = F1 / fRecMeanMolarWeight;
13327 return recMeanMolarWeight;
13328 }();
13329 pvars[PV->RHO] = avars[AV->W_MEAN] * pvars[PV->P] / (Tc * m_gasConstant);
13330 }
13331 else {
13332 pvars[PV->RHO] = sysEqn().density_ES(pvars[PV->P], Tc);
13333 }
13334
13335
13336 } else if(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcs[0]->m_bndryCndId == 3067) {
13337 MBool& first = m_static_smallCellCorrection_first;
13338 MInt& slipDirection = m_static_smallCellCorrection_slipDirection;
13339 MFloat& slipCoordinate = m_static_smallCellCorrection_slipCoordinate;
13340
13341 // TODO labels:FV,DOC cleanup this mess!
13353 if(first) {
13354 first = false;
13355 slipDirection = Context::getSolverProperty<MInt>("slipDirection", m_solverId, AT_);
13356 slipCoordinate = Context::getSolverProperty<MFloat>("slipCoordinate", m_solverId, AT_);
13357 }
13358 MInt slipDim = slipDirection / 2;
13359 MFloat slipSign = F1;
13360 if(slipDirection % 2 == 1) {
13361 slipSign = -F1;
13362 }
13363
13364 if((a_coordinate(cellId, slipDim) - slipCoordinate) * slipSign < F0) {
13365 MFloat pvars2[5];
13366 for(MInt i = 0; i < nDim; i++) {
13367 MInt stencil = 1;
13368 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
13369 a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[srfc], PV->VV[i]) = F0;
13370 }
13371 pvars2[PV->VV[i]] = F0;
13372 for(MUint n = 0; n < noRecNghbrs; n++) {
13373 pvars2[PV->VV[i]] += m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n + stencil]
13374 * a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], PV->VV[i]);
13375 }
13376 }
13377 MFloat vel[3];
13378 for(MInt i = 0; i < nDim; i++) {
13379 vel[i] = pvars2[PV->VV[i]];
13380 for(MInt j = 0; j < nDim; j++) {
13381 vel[i] += m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i] * (pvars[PV->VV[j]] - pvars2[PV->VV[j]])
13382 * m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[j];
13383 }
13384 }
13385 for(MInt i = 0; i < nDim; i++) {
13386 pvars[PV->VV[i]] = vel[i];
13387 }
13388 }
13389 }
13390 //====================
13391 MFloatScratchSpace cvars(noCVars, AT_, "cvars");
13392 MFloatScratchSpace avars(noAVars, AT_, "avars");
13393 IF_CONSTEXPR(isDetChem<SysEqn>) {
13394 // Only meanMolarMass is needed
13395 avars[AV->W_MEAN] = [&] {
13396 MFloat fRecMeanMolarWeight = F0;
13397 for(MUint s = 0; s < PV->m_noSpecies; ++s) {
13398 fRecMeanMolarWeight += pvars[PV->Y[s]] * sysEqn().m_species->fMolarMass[s];
13399 }
13400 const MFloat recMeanMolarWeight = F1 / fRecMeanMolarWeight;
13401 return recMeanMolarWeight;
13402 }();
13403 }
13404
13405 // Avoid passing zero-sized vector
13406 sysEqn().computeConservativeVariables(&pvars[0], &cvars[0], isDetChem<SysEqn> ? &avars[0] : nullptr);
13407
13408 ASSERT(maxLevel() >= maxUniformRefinementLevel() && maxLevel() <= maxRefinementLevel(), "");
13409
13410 // commented version also applies smallCellCorrection for cutCells on lower levels, however
13411 // they only need to be stabilised if their volume falls below the threshold of the fines cells!
13412 // maxLevelChange
13413 MFloat vfrac = a_cellVolume(cellId) / grid().gridCellVolume(maxLevel());
13414 MFloat volumeLimit = m_fvBndryCnd->m_volumeLimitWall;
13415
13416 if(a_level(cellId) < maxLevel() && m_bndryLevelJumps) {
13417 volumeLimit = volumeLimit * volFactor * (maxLevel() - a_level(cellId));
13418 }
13419 if(m_localTS) {
13420 vfrac = a_cellVolume(cellId) / c_cellVolumeAtLevel(a_level(cellId));
13421 }
13422
13423 const MFloat fac = maia::math::deltaFun(vfrac, 1e-8, volumeLimit);
13424
13425 for(MInt v = 0; v < noCVars; v++) {
13426 // if ( fabs(a_variable( cellId , v )) < 1e-12 ) continue;
13427 delta(smallc, v) = (F1 - fac) * (cvars[v] - a_variable(cellId, v));
13428 }
13429 redistFac(smallc) = a_cellVolume(cellId) / sum;
13430 }
13431
13432 RECORD_TIMER_STOP(m_timers[Timers::SCCorrInterp]);
13433 RECORD_TIMER_START(m_timers[Timers::SCCorrRedist]);
13434
13435 // 4. Reset buffer for flux redistribution over domain boundaries
13436 if(conservation) {
13437 for(MInt i = 0; i < noNeighborDomains(); i++) {
13438 if(m_fvBndryCnd->m_nearBoundaryHaloCells[i].empty()) continue;
13439 for(MUint j = 0; j < m_fvBndryCnd->m_nearBoundaryHaloCells[i].size(); j++) {
13440 MInt cellId = m_fvBndryCnd->m_nearBoundaryHaloCells[i][j];
13441 for(MInt v = 0; v < noCVars; v++) {
13442 a_variable(cellId, v) = F0;
13443 }
13444 }
13445 }
13446
13447 if(grid().azimuthalPeriodicity()) {
13448 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
13449 for(MUint j = 0; j < m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i].size(); j++) {
13450 MInt cellId = m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i][j];
13451 for(MInt v = 0; v < noCVars; v++) {
13452 a_variable(cellId, v) = F0;
13453 }
13454 }
13455 }
13456 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
13457 for(MUint j = 0; j < m_azimuthalRemappedHaloCells[i].size(); j++) {
13458 MInt cellId = m_azimuthalRemappedHaloCells[i][j];
13459 for(MInt v = 0; v < noCVars; v++) {
13460 a_variable(cellId, v) = F0;
13461 }
13462 }
13463 }
13464 }
13465 }
13466
13467 // azimuthal periodicity concept
13468 if(conservation && (m_periodicCells == 2 || m_periodicCells == 3)) {
13469 // reset periodic cells
13470 for(MInt c = 0; c < m_sortedPeriodicCells->size(); c++) {
13471 a_variable(m_sortedPeriodicCells->a[c], CV->RHO) = F0;
13472 IF_CONSTEXPR(hasE<SysEqn>)
13473 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_E) = F0;
13474 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_U) = F0;
13475 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_V) = F0;
13476 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_W) = F0;
13477
13478 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
13479 for(MInt r = 0; r < m_noRansEquations; r++) {
13480 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_NN[r]) = F0;
13481 }
13482 }
13483 }
13484 }
13485
13486 // 5. Apply stable update to internal small cells
13487 for(MInt smallc = 0; smallc < noSmallCells; smallc++) {
13488 const MInt bndryId = m_fvBndryCnd->m_smallCutCells[(unsigned)smallc];
13489 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
13490 if(a_isPeriodic(cellId)) continue;
13491 if(a_isHalo(cellId)) continue;
13492 if(a_hasProperty(cellId, SolverCell::IsPeriodicWithRot)) continue;
13493 // stabilize small cbc cutOff cells!
13494 if(a_hasProperty(cellId, SolverCell::IsCutOff) && !m_fvBndryCnd->m_cbcSmallCellCorrection) continue;
13495
13496 for(MInt v = 0; v < noCVars; v++) {
13497 a_variable(cellId, v) += delta(smallc, v);
13498 // a_rightHandSide( cellId , v ) = a_cellVolume( cellId ) * ( a_variable( cellId , v ) - a_oldVariable( cellId
13499 // , v ) ) / ( m_RKalpha[m_RKStep] * timeStep() );
13500#if !defined NDEBUG || defined _MB_DEBUG_
13501
13502 IF_CONSTEXPR(hasE<SysEqn>)
13503 if(std::isnan(a_variable(cellId, v))
13504 || (((v == CV->RHO && a_variable(cellId, CV->RHO) < F0)
13505 || (v == CV->RHO_E && a_variable(cellId, CV->RHO_E) < F0))
13506 && !isDetChem<SysEqn> && !m_isEEGas)) {
13507 cerr << domainId() << ": small cell correction failed " << globalTimeStep << " " << cellId << " "
13508 << c_globalId(cellId) << " " << v << " " << a_level(cellId) << " " << a_variable(cellId, v) << " "
13509 << delta(smallc, v) << " " << setprecision(12)
13510 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << " "
13511 << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << endl;
13512 }
13513#endif
13514 }
13515 }
13516
13517 // 6. Redistribute flux defect to adjacent cells to re-establish conservation
13518 if(conservation) {
13519 for(MInt smallc = 0; smallc < noSmallCells; smallc++) {
13520 const MInt bndryId = m_fvBndryCnd->m_smallCutCells[(unsigned)smallc];
13521 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
13522 if(a_isPeriodic(cellId)) continue;
13523 // no-mass conservation at the cut-off - no redistribution from cutoff cells
13524 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
13525 if(a_isHalo(cellId)) continue;
13526 if(a_hasProperty(cellId, SolverCell::IsPeriodicWithRot)) continue;
13527 if(a_hasProperty(cellId, SolverCell::IsSplitCell)) continue;
13528 if(redistFac(smallc) < 1e-14) continue;
13529 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
13530 const MUint noRecNghbrs = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size();
13531 if(noRecNghbrs == 0) continue;
13532 // loop over all reconstruction neighbors and apply update to those cells!
13533 for(MUint n = (unsigned)noSrfcs + 1; n < noRecNghbrs; n++) {
13534 MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
13535 if(nghbrId < 0) continue;
13536 ASSERT(a_hasProperty(nghbrId, SolverCell::IsSplitChild) || c_noChildren(nghbrId) == 0, "");
13537 // non-conservation at the cutOff - no redistribution into cutOff cells
13538 if(a_hasProperty(nghbrId, SolverCell::IsCutOff)) continue;
13539 for(MInt v = 0; v < noCVars; v++) {
13540 a_variable(nghbrId, v) -= redistFac(smallc) * delta(smallc, v);
13541 }
13542#if !defined NDEBUG || defined _MB_DEBUG_
13543 IF_CONSTEXPR(hasE<SysEqn>)
13544 if(!a_isHalo(nghbrId) && !m_isEEGas
13545 && (a_variable(nghbrId, CV->RHO) < F0 || ((a_variable(nghbrId, CV->RHO_E) < F0) && (!isDetChem<SysEqn>)))) {
13546 cerr << domainId() << ": flux redist failed " << globalTimeStep << " " << cellId << " " << c_globalId(cellId)
13547 << " " << a_level(cellId) << " " << nghbrId << " " << c_globalId(nghbrId) << " "
13548 << a_variable(nghbrId, CV->RHO) << " " << a_variable(nghbrId, CV->RHO_E) << " " << noRecNghbrs << " "
13549 << redistFac(smallc) << " " << delta(smallc, CV->RHO) << " " << delta(smallc, CV->RHO_E) << " "
13550 << setprecision(12) << a_cellVolume(cellId) / grid().gridCellVolume(a_level(cellId)) << endl;
13551 }
13552#endif
13553 }
13554 }
13555 }
13556
13557 RECORD_TIMER_STOP(m_timers[Timers::SCCorrRedist]);
13558 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange2]);
13559
13560 // 7. Send back flux redistributed over domain boundaries, i.e., from halos -> windows, send and receive buffers are
13561 // switched on purpose
13562 if(conservation) {
13563 if(grid().azimuthalPeriodicity()) azimuthalNearBoundaryReverseExchange();
13564
13565 sendReq.fill(MPI_REQUEST_NULL);
13566 recvReq.fill(MPI_REQUEST_NULL);
13567 sendBufferCnts.fill(0);
13568 recvBufferCnts.fill(0);
13569 for(MInt i = 0; i < noNeighborDomains(); i++) {
13570 sendBufferCnts(i) = noCVars * (signed)m_fvBndryCnd->m_nearBoundaryHaloCells[i].size();
13571 recvBufferCnts(i) = noCVars * (signed)m_fvBndryCnd->m_nearBoundaryWindowCells[i].size();
13572 if(m_fvBndryCnd->m_nearBoundaryHaloCells[i].empty()) continue;
13573 MInt sendBufferCounter = 0;
13574 for(MUint j = 0; j < m_fvBndryCnd->m_nearBoundaryHaloCells[i].size(); j++) {
13575 MInt cellId = m_fvBndryCnd->m_nearBoundaryHaloCells[i][j];
13576 for(MInt v = 0; v < noCVars; v++) {
13577 m_receiveBuffers[i][sendBufferCounter] = a_variable(cellId, v);
13578 sendBufferCounter++;
13579 }
13580 }
13581 }
13582 MInt sendCnt = 0;
13583 MInt recvCnt = 0;
13584 if(m_nonBlockingComm) {
13585 for(MInt i = 0; i < noNeighborDomains(); i++) {
13586 if(sendBufferCnts(i) == 0) continue;
13587 ASSERT(sendBufferCnts(i) <= m_noMaxLevelHaloCells[i] * m_dataBlockSize, "");
13588 MPI_Isend(m_receiveBuffers[i], sendBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 13, mpiComm(),
13589 &sendReq[sendCnt], AT_, "m_receiveBuffers[i]");
13590 sendCnt++;
13591 }
13592 for(MInt i = 0; i < noNeighborDomains(); i++) {
13593 if(recvBufferCnts(i) == 0) continue;
13594 ASSERT(recvBufferCnts(i) <= m_noMaxLevelWindowCells[i] * m_dataBlockSize, "");
13595 MPI_Irecv(m_sendBuffers[i], recvBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 13, mpiComm(), &recvReq[recvCnt],
13596 AT_, "m_sendBuffers[i]");
13597 recvCnt++;
13598 }
13599 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange2Wait]);
13600 if(recvCnt > 0) MPI_Waitall(recvCnt, &recvReq[0], MPI_STATUSES_IGNORE, AT_);
13601 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange2Wait]);
13602 } else {
13603 for(MInt i = 0; i < noNeighborDomains(); i++) {
13604 if(sendBufferCnts(i) == 0) continue;
13605 ASSERT(sendBufferCnts(i) <= m_noMaxLevelHaloCells[i] * m_dataBlockSize, "");
13606 MPI_Issend(m_receiveBuffers[i], sendBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 13, mpiComm(),
13607 &sendReq[sendCnt], AT_, "m_receiveBuffers[i]");
13608 sendCnt++;
13609 }
13610 for(MInt i = 0; i < noNeighborDomains(); i++) {
13611 if(recvBufferCnts(i) == 0) continue;
13612 ASSERT(recvBufferCnts(i) <= m_noMaxLevelWindowCells[i] * m_dataBlockSize, "");
13613 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange2Wait]);
13614 MPI_Recv(m_sendBuffers[i], recvBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 13, mpiComm(), MPI_STATUS_IGNORE,
13615 AT_, "m_sendBuffers[i]");
13616 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange2Wait]);
13617 recvCnt++;
13618 }
13619 }
13620 for(MInt i = 0; i < noNeighborDomains(); i++) {
13621 if(m_fvBndryCnd->m_nearBoundaryWindowCells[i].empty()) continue;
13622 MInt recvBufferCounter = 0;
13623 for(MUint j = 0; j < m_fvBndryCnd->m_nearBoundaryWindowCells[i].size(); j++) {
13624 MInt cellId = m_fvBndryCnd->m_nearBoundaryWindowCells[i][j];
13625 for(MInt v = 0; v < noCVars; v++) {
13626 // if( (!a_isPeriodic(cellId)) && (!a_hasProperty( cellId , SolverCell::IsCutOff)) ){ // ?
13627 a_variable(cellId, v) += m_sendBuffers[i][recvBufferCounter];
13628 //}
13629 // a_rightHandSide( cellId , v ) = a_cellVolume( cellId ) * ( a_variable( cellId , v ) - a_oldVariable(
13630 // cellId , v ) ) / ( m_RKalpha[m_RKStep] * timeStep() );
13631 recvBufferCounter++;
13632 }
13633 }
13634 }
13635 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange2Wait]);
13636 if(sendCnt > 0) MPI_Waitall(sendCnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
13637
13638 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange2Wait]);
13639 }
13640
13641 // azimuthal periodicity concept
13642 if(conservation && (m_periodicCells == 2 || m_periodicCells == 3)) {
13643 // reset halo cells
13644 for(MInt c = 0; c < m_sortedPeriodicCells->size(); c++) {
13645 if(a_isHalo(m_sortedPeriodicCells->a[c])) {
13646 a_variable(m_sortedPeriodicCells->a[c], CV->RHO) = F0;
13647 IF_CONSTEXPR(hasE<SysEqn>)
13648 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_E) = F0;
13649 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_U) = F0;
13650 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_V) = F0;
13651 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_W) = F0;
13652
13653 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
13654 for(MInt r = 0; r < m_noRansEquations; ++r) {
13655 a_variable(m_sortedPeriodicCells->a[c], CV->RHO_NN[r]) = F0;
13656 }
13657 }
13658 }
13659 }
13660
13661 for(MInt d = 0; d < noDomains(); d++) {
13662 for(MInt c = 0; c < m_noPerCellsToReceive[d]; c++) {
13663 const auto sortedId = static_cast<MInt>(m_periodicDataToReceive[d][5 + c * m_noPeriodicData]);
13664 const MInt cell_Id = m_sortedPeriodicCells->a[sortedId];
13665
13666 m_periodicDataToReceive[d][0 + c * m_noPeriodicData] = a_variable(cell_Id, CV->RHO);
13667 m_periodicDataToReceive[d][1 + c * m_noPeriodicData] = a_variable(cell_Id, CV->RHO_U);
13668 m_periodicDataToReceive[d][2 + c * m_noPeriodicData] = a_variable(cell_Id, CV->RHO_V);
13669 m_periodicDataToReceive[d][3 + c * m_noPeriodicData] = a_variable(cell_Id, CV->RHO_W);
13670 IF_CONSTEXPR(hasE<SysEqn>)
13671 m_periodicDataToReceive[d][4 + c * m_noPeriodicData] = a_variable(cell_Id, CV->RHO_E);
13672 }
13673 }
13674
13675 // set Data for current domain
13676 for(MInt c = 0; c < m_noPerCellsToReceive[domainId()]; c++) {
13677 for(MInt v = 0; v < m_noPeriodicData; v++) {
13678 m_periodicDataToSend[domainId()][v + c * m_noPeriodicData] =
13679 m_periodicDataToReceive[domainId()][v + c * m_noPeriodicData];
13680 }
13681 }
13682
13683 {
13684 // exchange interpolated PV Variables
13685 ScratchSpace<MPI_Request> send_Req(noDomains(), AT_, "sendReq");
13686 ScratchSpace<MPI_Request> recv_Req(noDomains(), AT_, "recvReq");
13687 send_Req.fill(MPI_REQUEST_NULL);
13688 recv_Req.fill(MPI_REQUEST_NULL);
13689
13690 for(MInt snd = 0; snd < domainId(); snd++) {
13691 if(m_noPerCellsToSend[snd] > 0) {
13692 MInt bufSize = m_noPerCellsToSend[snd] * m_noPeriodicData;
13693 MPI_Irecv(m_periodicDataToSend[snd], bufSize, MPI_DOUBLE, snd, 0, mpiComm(), &recv_Req[snd], AT_,
13694 "m_periodicDataToSend[snd]");
13695 }
13696 }
13697 for(MInt rcv = 0; rcv < noDomains(); rcv++) {
13698 if(m_noPerCellsToReceive[rcv] > 0 && rcv != domainId()) {
13699 MInt bufSize = m_noPerCellsToReceive[rcv] * m_noPeriodicData;
13700 MPI_Isend(m_periodicDataToReceive[rcv], bufSize, MPI_DOUBLE, rcv, 0, mpiComm(), &send_Req[rcv], AT_,
13701 "m_periodicDataToReceive[rcv]");
13702 }
13703 }
13704
13705 if(domainId() < noDomains() - 1) {
13706 for(MInt snd = domainId() + 1; snd < noDomains(); snd++) {
13707 if(m_noPerCellsToSend[snd] > 0) {
13708 MInt bufSize = m_noPerCellsToSend[snd] * m_noPeriodicData;
13709 MPI_Irecv(m_periodicDataToSend[snd], bufSize, MPI_DOUBLE, snd, 0, mpiComm(), &recv_Req[snd], AT_,
13710 "m_periodicDataToSend[snd]");
13711 }
13712 }
13713 }
13714
13715 RECORD_TIMER_START(m_timers[Timers::SCCorrExchange2Wait]);
13716 MPI_Waitall(noDomains(), &recv_Req[0], MPI_STATUSES_IGNORE, AT_);
13717 MPI_Waitall(noDomains(), &send_Req[0], MPI_STATUSES_IGNORE, AT_);
13718 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange2Wait]);
13719 }
13720
13721
13722 for(MInt d = 0; d < noDomains(); d++) {
13723 for(MInt c = 0; c < m_noPerCellsToSend[d]; c++) {
13724 const auto cell_Id = static_cast<MInt>(m_periodicDataToSend[d][6 + c * m_noPeriodicData]);
13725
13726 a_variable(cell_Id, CV->RHO) += m_periodicDataToSend[d][0 + c * m_noPeriodicData];
13727 a_variable(cell_Id, CV->RHO_U) += m_periodicDataToSend[d][1 + c * m_noPeriodicData];
13728 a_variable(cell_Id, CV->RHO_V) += m_periodicDataToSend[d][2 + c * m_noPeriodicData];
13729 a_variable(cell_Id, CV->RHO_W) += m_periodicDataToSend[d][3 + c * m_noPeriodicData];
13730 IF_CONSTEXPR(hasE<SysEqn>)
13731 a_variable(cell_Id, CV->RHO_E) += m_periodicDataToSend[d][4 + c * m_noPeriodicData];
13732 }
13733 }
13734 }
13735
13736 RECORD_TIMER_STOP(m_timers[Timers::SCCorrExchange2]);
13737}
13738
13739//-------------------------------------------------------------------------------------
13740
13741
13759template <MInt nDim_, class SysEqn>
13760template <MInt diag, MBool recorrectBndryCellCoords>
13762 MIntScratchSpace& adjacentCells,
13763 MIntScratchSpace& layerId) {
13764 if(recorrectBndryCellCoords != m_fvBndryCnd->m_cellCoordinatesCorrected) {
13765 return getAdjacentLeafCells<diag, !recorrectBndryCellCoords>(cellId, noLayers, adjacentCells, layerId);
13766 }
13767#ifndef NDEBUG
13768 if(recorrectBndryCellCoords && !m_fvBndryCnd->m_cellCoordinatesCorrected)
13769 mTerm(1, AT_, "Corrected cell coordinates are expected.");
13770 if(!recorrectBndryCellCoords && m_fvBndryCnd->m_cellCoordinatesCorrected)
13771 mTerm(1, AT_, "Uncorrected cell coordinates are expected.");
13772#endif
13773 std::array<std::array<MInt, 4>, nDim> tmpNghbrs;
13774
13775 MInt gridcell = cellId;
13776 if(a_hasProperty(cellId, SolverCell::IsSplitClone)) {
13777 gridcell = m_splitChildToSplitCell.find(cellId)->second;
13778 }
13779 if(!a_hasProperty(cellId, SolverCell::IsSplitChild) && c_noChildren(gridcell) > 0) return 0;
13780 map<MInt, MInt> nghbrs;
13781 nghbrs.insert(pair<MInt, MInt>(cellId, 0));
13782 for(MInt layer = 1; layer <= noLayers; layer++) {
13783 set<MInt> nextLayer;
13784 for(auto& nghbr : nghbrs) {
13785 MInt nghbrId = nghbr.first;
13786 for(MInt dir0 = 0; dir0 < 2 * nDim; dir0++) {
13787 const MInt cnt0 = getNghbrLeafCells<recorrectBndryCellCoords>(nghbrId, cellId, layer, &tmpNghbrs[0][0], dir0);
13788 for(MInt c0 = 0; c0 < cnt0; c0++) {
13789 nextLayer.insert(tmpNghbrs[0][c0]);
13790 if(diag > 0) {
13791 for(MInt dir1 = 0; dir1 < 2 * nDim; dir1++) {
13792 if((dir1 / 2) == (dir0 / 2)) {
13793 continue;
13794 }
13795 const MInt cnt1 = getNghbrLeafCells<recorrectBndryCellCoords>(tmpNghbrs[0][c0], cellId, layer,
13796 &tmpNghbrs[1][0], dir1, dir0);
13797 for(MInt c1 = 0; c1 < cnt1; c1++) {
13798 nextLayer.insert(tmpNghbrs[1][c1]);
13799 IF_CONSTEXPR(nDim == 3 && diag == 2) {
13800 for(MInt dir2 = 0; dir2 < 2 * nDim; dir2++) {
13801 if(((dir2 / 2) == (dir0 / 2)) || ((dir2 / 2) == (dir1 / 2))) continue;
13802 const MInt cnt2 = getNghbrLeafCells<recorrectBndryCellCoords>(tmpNghbrs[1][c1], cellId, layer,
13803 &tmpNghbrs[2][0], dir2, dir1, dir0);
13804 for(MInt c2 = 0; c2 < cnt2; c2++) {
13805 nextLayer.insert(tmpNghbrs[2][c2]);
13806 }
13807 }
13808 }
13809 }
13810 }
13811 }
13812 }
13813 }
13814 }
13815 for(MInt it : nextLayer) {
13816 nghbrs.insert(pair<MInt, MInt>(it, layer));
13817 }
13818 }
13819 nghbrs.erase(cellId);
13820 MInt cnt = 0;
13821 for(auto it = nghbrs.begin(); it != nghbrs.end(); it++) {
13822 ASSERT(cnt < (signed)adjacentCells.size(),
13823 to_string(cellId) + " " + to_string(nghbrs.size()) + " " + to_string(a_isHalo(cellId)) + " "
13824 + to_string(a_isWindow(cellId)) + " " + to_string(adjacentCells.size()));
13825 if(a_hasProperty(it->first, SolverCell::IsSplitCell)) {
13826 auto it2 = find(m_splitCells.begin(), m_splitCells.end(), it->first);
13827 if(it2 == m_splitCells.end()) mTerm(1, AT_, "split cells inconsistency.");
13828 const MInt pos = distance(m_splitCells.begin(), it2);
13829 ASSERT(m_splitCells[pos] == it->first, "");
13830 for(MUlong c = 0; c < m_splitChilds[pos].size(); c++) {
13831 adjacentCells[cnt] = m_splitChilds[pos][c];
13832 layerId[cnt] = it->second;
13833 ASSERT(adjacentCells[cnt] > -1, "");
13834 ASSERT(a_hasProperty(adjacentCells[cnt], SolverCell::IsSplitChild) || c_noChildren(adjacentCells[cnt]) == 0,
13835 "");
13836 cnt++;
13837 }
13838 } else {
13839 adjacentCells[cnt] = it->first;
13840 layerId[cnt] = it->second;
13841 ASSERT(adjacentCells[cnt] > -1, "");
13842 ASSERT(c_noChildren(adjacentCells[cnt]) == 0, "");
13843 cnt++;
13844 }
13845 }
13846 return cnt;
13847}
13848
13849// ---------------------------------------------------------------------------
13850
13851
13857template <MInt nDim_, class SysEqn>
13858template <MBool recorrectBndryCellCoords>
13860 MInt dir, MInt dir1, MInt dir2) const {
13861 MInt count = 0;
13862 // set cellId of split child
13863 const MInt gridcellId =
13864 a_hasProperty(cellId, SolverCell::IsSplitClone) ? m_splitChildToSplitCell.find(cellId)->second : cellId;
13865
13866 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
13867 return 0;
13868 }
13869
13870 if(checkNeighborActive(gridcellId, dir) && a_hasNeighbor(gridcellId, dir) > 0) {
13871 const MInt nextId = c_neighborId(gridcellId, dir);
13872 if(nextId < 0) return 0;
13873
13874 if(c_noChildren(nextId) > 0) {
13875 for(MInt child = 0; child < IPOW2(nDim); child++) {
13876 if(!childCode[dir][child]) continue;
13877 if(dir1 > -1 && !childCode[dir1][child]) continue;
13878 if(dir2 > -1 && !childCode[dir2][child]) continue;
13879 const MInt childId = c_childId(nextId, child);
13880 if(childId < 0) continue;
13881 if(c_noChildren(childId) > 0) continue;
13882 if(a_hasProperty(childId, SolverCell::IsOnCurrentMGLevel)) {
13883 nghbrs[count] = childId;
13884 count++;
13885 }
13886 }
13887 } else if(a_hasProperty(nextId, SolverCell::IsOnCurrentMGLevel)) {
13888 nghbrs[0] = nextId;
13889 count = 1;
13890 }
13891 } else if(c_parentId(gridcellId) > -1) {
13892 if(a_hasNeighbor(c_parentId(gridcellId), dir) > 0) {
13893 const MInt nextId = c_neighborId(c_parentId(gridcellId), dir);
13894 if(nextId < 0 || c_noChildren(nextId) > 0) {
13895 return 0;
13896 }
13897 if(a_hasProperty(nextId, SolverCell::IsOnCurrentMGLevel)) {
13898 nghbrs[0] = nextId;
13899 count = 1;
13900 }
13901 }
13902 }
13903
13904 std::array<MFloat, nDim> coord0{};
13905 for(MInt i = 0; i < nDim; i++) {
13906 coord0[i] = a_coordinate(refCell, i)
13907 - ((recorrectBndryCellCoords && a_bndryId(refCell) > -1)
13908 ? m_fvBndryCnd->m_bndryCells->a[a_bndryId(refCell)].m_coordinates[i]
13909 : F0);
13910 }
13911
13912 for(MInt c = 0; c < count; c++) {
13913 const MFloat delta = ((MFloat)layer) * 0.5005 * (c_cellLengthAtCell(nghbrs[c]) + c_cellLengthAtCell(refCell));
13914
13915 for(MInt i = 0; i < nDim; i++) {
13916 const MFloat correctedCoord = a_coordinate(nghbrs[c], i)
13917 - ((recorrectBndryCellCoords && a_bndryId(nghbrs[c]) > -1)
13918 ? m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrs[c])].m_coordinates[i]
13919 : F0);
13920 if(std::abs(correctedCoord - coord0[i]) > delta) {
13921 nghbrs[c] = nghbrs[count - 1];
13922 count--;
13923 c--;
13924 break;
13925 }
13926 }
13927 }
13928
13929 return count;
13930}
13931
13932// ---------------------------------------------------------------------------
13933
13934template <MInt nDim_, class SysEqn>
13936 MIntScratchSpace& nghbrList,
13937 MIntScratchSpace& layerId) {
13938 return getAdjacentLeafCells<0>(cellId, noLayers, nghbrList, layerId);
13939}
13940template <MInt nDim_, class SysEqn>
13942 MIntScratchSpace& nghbrList,
13943 MIntScratchSpace& layerId) {
13944 return getAdjacentLeafCells<1>(cellId, noLayers, nghbrList, layerId);
13945}
13946template <MInt nDim_, class SysEqn>
13948 MIntScratchSpace& nghbrList,
13949 MIntScratchSpace& layerId) {
13950 return getAdjacentLeafCells<2>(cellId, noLayers, nghbrList, layerId);
13951}
13952template <MInt nDim_, class SysEqn>
13954 MIntScratchSpace& nghbrList,
13955 MIntScratchSpace& layerId) {
13956 return getAdjacentLeafCells<0, true>(cellId, noLayers, nghbrList, layerId);
13957}
13958template <MInt nDim_, class SysEqn>
13960 MIntScratchSpace& nghbrList,
13961 MIntScratchSpace& layerId) {
13962 return getAdjacentLeafCells<1, true>(cellId, noLayers, nghbrList, layerId);
13963}
13964template <MInt nDim_, class SysEqn>
13966 MIntScratchSpace& nghbrList,
13967 MIntScratchSpace& layerId) {
13968 return getAdjacentLeafCells<2, true>(cellId, noLayers, nghbrList, layerId);
13969}
13970
13971//-------------------------------------------------------------------------------------
13972
13973
13983template <MInt nDim_, class SysEqn>
13985 TRACE();
13986
13987 // Note: flamespeed is abused here to detect if Stephans flame stuff is running
13988 if(m_levelSet && m_combustion && abs(m_flameSpeed) <= 0) {
13989 m_log << "WARNING: applyBoundaryCondition() " << endl;
13990 return;
13991 }
13992
13993 // MFloat ipChange = 10000000.0;
13994 // MFloat eps = 1e-5; // just a guess for a suitable value - should be changed to some sophisticated value
13995 MInt iter = 0;
13996
13997 if(m_fvBndryCnd->m_multipleGhostCells) {
13998 // compute Interpolated Variables - initial guess
13999 m_fvBndryCnd->updateImagePointVariables(0);
14000 }
14001
14002 if(m_fvBndryCnd->m_multipleGhostCells && m_fvBndryCnd->m_ipVariableIterative) {
14003 // while(ipChange > eps && iter < m_fvBndryCnd->m_noImagePointIterations){
14004 while(iter < m_fvBndryCnd->m_noImagePointIterations) {
14005 // apply Dirichlet boundary conditions
14006 m_fvBndryCnd->updateGhostCellVariables();
14007 // apply von Neumann boundary conditions
14008 m_fvBndryCnd->applyNeumannBoundaryCondition();
14009 // compute cell center gradients
14010 LSReconstructCellCenter_Boundary();
14011 // compute Interpolated Variables
14012 /* ipChange = */ m_fvBndryCnd->updateImagePointVariables(1);
14013 // cerr << "[ " << domainId() << " ]: " << " iteration: " << iter << " max. rel. change in image point
14014 // variables: " << ipChange << endl;
14015 iter++;
14016 }
14017 }
14018 // apply Dirichlet boundary conditions
14019 m_fvBndryCnd->updateGhostCellVariables();
14020
14021 // apply von Neumann boundary conditions
14022 m_fvBndryCnd->applyNeumannBoundaryCondition();
14023}
14024
14025
14026// --------------------------------------------------------------------------------------
14027
14028
14032template <MInt nDim_, class SysEqn>
14034 TRACE();
14035
14036 const MBool diagonalCellAddition = m_fvBndryCnd->m_cellMerging && (nDim == 3);
14037 const MInt maxNoNghbrs = 100;
14038 MIntScratchSpace nghbrList(maxNoNghbrs, AT_, "nghbrList");
14039 MIntScratchSpace layerId(maxNoNghbrs, AT_, "layerId");
14040
14041 m_fvBndryCnd->recorrectCellCoordinates();
14042
14043 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14044 const MInt bndryId = a_bndryId(cellId);
14045 MInt gridcell = cellId;
14046 if(a_hasProperty(cellId, SolverCell::IsSplitClone)) {
14047 gridcell = m_splitChildToSplitCell.find(cellId)->second;
14048 }
14049
14050 a_noReconstructionNeighbors(cellId) = 0;
14051
14052 if(a_isBndryGhostCell(cellId)) continue;
14053 if(c_noChildren(gridcell) > 0) continue;
14054 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
14055 // if( a_hasProperty( cellId , SolverCell::IsCutOff) ) continue;
14056 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
14057 if(a_hasProperty(cellId, SolverCell::IsInvalid)) continue;
14058
14059 // const MInt counter = ( bndryId > -1 || m_orderOfReconstruction == 2 ) ? getAdjacentLeafCells<1>( cellId, 1,
14060 // nghbrList, layerId ) : getAdjacentLeafCells<0>( cellId, 1, nghbrList, layerId ); MBool ext = false; if ( bndryId
14061 // > -1 ) if ( m_fvBndryCnd->m_bndryCells->a[ bndryId ].m_volume / pow(c_cellLengthAtCell(cellId),(MFloat)nDim) <
14062 // F1B2 ) ext = true; const MInt counter = ( ext || m_orderOfReconstruction == 2 ) ? getAdjacentLeafCells<1>(
14063 // cellId, 1, nghbrList, layerId ) : getAdjacentLeafCells<0>( cellId, 1, nghbrList, layerId );
14064 const MInt counter = getAdjacentLeafCells<0>(cellId, 1, nghbrList, layerId);
14065 if(counter > maxNoNghbrs) mTerm(1, AT_, "too many nghbrs " + to_string(counter));
14066 if(bndryId > -1) {
14067 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
14068 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) =
14069 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
14070 a_noReconstructionNeighbors(cellId)++;
14071 }
14072 }
14073 MBool atInterface = false;
14074 for(MInt k = 0; k < counter; k++) {
14075 MInt nghbrId = nghbrList[k];
14076 if(nghbrId < 0) continue;
14077 if(a_hasProperty(nghbrId, SolverCell::IsInvalid)) continue;
14078 // if ( a_noReconstructionNeighbors( cellId ) >= m_cells.noRecNghbrs()) continue;
14079 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) = nghbrId;
14080 a_noReconstructionNeighbors(cellId)++;
14081 if(a_noReconstructionNeighbors(cellId) > m_cells.noRecNghbrs()) {
14082 mTerm(1, AT_, "too many rec nghbrs " + to_string(cellId) + " " + to_string(counter));
14083 }
14084 if(a_level(nghbrId) < a_level(cellId)) atInterface = true;
14085 }
14086 if(diagonalCellAddition && atInterface) {
14087 const MInt counter2 = getAdjacentLeafCells<2>(cellId, 1, nghbrList, layerId);
14088 for(MInt k = 0; k < counter2; k++) {
14089 MInt nghbrId = nghbrList[k];
14090 if(nghbrId < 0) continue;
14091 if(a_hasProperty(nghbrId, SolverCell::IsInvalid)) continue;
14092 if(a_level(nghbrId) >= a_level(cellId)) continue;
14093 MBool exist = false;
14094 for(MInt i = 0; i < a_noReconstructionNeighbors(cellId); i++) {
14095 if(a_reconstructionNeighborId(cellId, i) == nghbrId) {
14096 exist = true;
14097 break;
14098 }
14099 }
14100 if(!exist) {
14101 a_reconstructionNeighborId(cellId, a_noReconstructionNeighbors(cellId)) = nghbrId;
14102 a_noReconstructionNeighbors(cellId)++;
14103 }
14104 if(a_noReconstructionNeighbors(cellId) > m_cells.noRecNghbrs()) {
14105 mTerm(1, AT_, "too many rec nghbrs " + to_string(cellId) + " " + to_string(counter));
14106 }
14107 }
14108 }
14109 }
14110
14111 if(m_fvBndryCnd->m_cellMerging) {
14112 // internal master cells
14113 // add the slave ghost cells and neighbor boundary cells
14114 MInt noSmallCells = m_fvBndryCnd->m_smallBndryCells->size();
14115 for(MInt smallId = 0; smallId < noSmallCells; smallId++) {
14116 MInt smallCell = m_fvBndryCnd->m_smallBndryCells->a[smallId];
14117 MInt smallCellId = m_fvBndryCnd->m_bndryCells->a[smallCell].m_cellId;
14118 MInt masterCellId = m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId;
14119 if(a_bndryId(masterCellId) == -1) {
14120 for(MInt i = 0; i < a_noReconstructionNeighbors(smallCellId); i++) {
14121 MInt nghbrId = a_reconstructionNeighborId(smallCellId, i);
14122 if(a_bndryId(nghbrId) > -1)
14123 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId > -1)
14124 nghbrId = m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId;
14125 MBool found = false;
14126 for(MInt j = 0; j < a_noReconstructionNeighbors(masterCellId); j++) {
14127 if(nghbrId == a_reconstructionNeighborId(masterCellId, j)) {
14128 found = true;
14129 break;
14130 }
14131 }
14132 if(!found && nghbrId != masterCellId) {
14133 a_reconstructionNeighborId(masterCellId, a_noReconstructionNeighbors(masterCellId)) = nghbrId;
14134 a_noReconstructionNeighbors(masterCellId)++;
14135 }
14136 }
14137 }
14138 }
14139 }
14140
14141 m_fvBndryCnd->rerecorrectCellCoordinates();
14142}
14143
14144
14145// --------------------------------------------------------------------------------------
14146
14147
14151template <MInt nDim_, class SysEqn>
14153 TRACE();
14154
14155 if(m_orderOfReconstruction > 1) mTerm(1, AT_, "Check code here.");
14156
14157 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
14158 const MInt recDim = (m_orderOfReconstruction == 2) ? (IPOW2(nDim) + 1) : nDim;
14159 MFloatScratchSpace tmpA(m_cells.noRecNghbrs(), recDim, AT_, "tmpA");
14160 MFloatScratchSpace tmpC(recDim, m_cells.noRecNghbrs(), AT_, "tmpC");
14161 MFloatScratchSpace weights(m_cells.noRecNghbrs(), AT_, "weights");
14162
14163#ifndef NDEBUG
14164 MFloat counter = F0;
14165 MFloat avg = F0;
14166 MFloat maxc = F0;
14167#endif
14168
14169 m_reconstructionConstants.clear();
14170 m_reconstructionCellIds.clear();
14171 m_reconstructionNghbrIds.clear();
14172
14173 // clear cell-center reconstruction
14174 m_reconstructionDataSize = 0;
14175
14176 // reset isFlux
14177 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14178 a_hasProperty(cellId, SolverCell::IsFlux) = false;
14179 }
14180
14181 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14182 a_reconstructionData(cellId) = m_reconstructionDataSize;
14183
14184 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
14185 // if( !a_hasProperty( cellId , SolverCell::IsFlux) ) continue;
14186 if(a_isBndryGhostCell(cellId)) continue;
14187 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
14188 /*IF_CONSTEXPR(nDim == 3) {
14189 if(a_hasProperty(cellId , SolverCell::IsInvalid)) continue;
14190 }*/
14191 if(a_bndryId(cellId) > -1) {
14192 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_linkedCellId > -1) {
14193 continue;
14194 }
14195 }
14196
14197 a_hasProperty(cellId, SolverCell::IsFlux) = true;
14198
14199 // loop over least-squares cell cluster
14200 const MInt noNghbrIds = a_noReconstructionNeighbors(cellId);
14201 if(noNghbrIds == 0) continue;
14202
14203 for(MInt n = 0; n < noNghbrIds; n++) {
14204 const MInt nghbrId = a_reconstructionNeighborId(cellId, n);
14205 a_hasProperty(nghbrId, SolverCell::IsFlux) = true;
14206 }
14207
14208 MFloat condNum =
14209 computeRecConstSVD(cellId, m_reconstructionDataSize, tmpA, tmpC, weights, recDim, m_reConstSVDWeightMode, -1);
14210
14211 m_reconstructionDataSize += noNghbrIds;
14212
14213#ifndef NDEBUG
14214 avg += condNum;
14215 maxc = mMax(maxc, condNum);
14216 counter += F1;
14217#else
14218 std::ignore = condNum;
14219
14220#endif
14221 }
14222
14223 a_reconstructionData(a_noCells()) = m_reconstructionDataSize;
14224
14225 // copy reconstruction Constants into bndry reconstruction Constants for all bndryCells
14226 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
14227 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
14228 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) continue;
14229 for(MInt nghbr = 0; nghbr < a_noReconstructionNeighbors(cellId); nghbr++) {
14230 for(MInt i = 0; i < nDim; i++) {
14231 m_fvBndryCnd->m_reconstructionConstants[bndryId][nghbr * nDim + i] =
14232 m_reconstructionConstants[nDim * (a_reconstructionData(cellId) + nghbr) + i];
14233 }
14234 }
14235 const MUint noRecNghbrs = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size();
14236 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
14237 // Note: skip the first noSrfcs neighbor ids since they contain dummyIds
14238 for(MUint n = noSrfcs; n < noRecNghbrs; n++) {
14239 a_hasProperty(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], SolverCell::IsFlux) = true;
14240 }
14241 }
14242
14243 m_log << "ok" << endl;
14244
14245#ifndef NDEBUG
14246
14247 MPI_Allreduce(MPI_IN_PLACE, &maxc, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "maxc");
14248 MPI_Allreduce(MPI_IN_PLACE, &avg, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "avg");
14249 MPI_Allreduce(MPI_IN_PLACE, &counter, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "counter");
14250
14251 m_log << " -> Singular value decomposition: maximum/average condition number: " << maxc << "/" << avg / counter
14252 << endl;
14253
14254#endif
14255}
14256
14257
14258// ---------------------------------------------------------------------------
14259
14260
14261template <MInt nDim_, class SysEqn>
14263 TRACE();
14264
14265 m_fvBndryCnd->updateCutOffCellVariables();
14266}
14267
14268
14269template <MInt nDim_, class SysEqn>
14271 TRACE();
14272
14273 m_fvBndryCnd->initCutOffBndryCnds();
14274}
14275
14276// --------------------------------------------------------------------------------------
14277
14278template <MInt nDim_, class SysEqn>
14280 TRACE();
14281
14282 m_fvBndryCnd->applyNonReflectingBCCutOff();
14283}
14284
14285
14286// --------------------------------------------------------------------------------------
14287
14288
14289template <MInt nDim_, class SysEqn>
14291 TRACE();
14292
14293 m_fvBndryCnd->applyNonReflectingBCAfterTreatmentCutOff();
14294}
14295
14296
14297// --------------------------------------------------------------------------------------
14298
14299
14300template <MInt nDim_, class SysEqn>
14302 TRACE();
14303
14304 const MInt noSrfcs = a_noSurfaces();
14305 //---
14306
14307 for(MInt s = 0; s < noSrfcs; s++) {
14308 for(MInt i = 0; i < nDim; i++) {
14309 a_surfaceDeltaX(s, i) = a_surfaceCoordinate(s, i) - a_coordinate(a_surfaceNghbrCellId(s, 0), i);
14310 a_surfaceDeltaX(s, nDim + i) = a_surfaceCoordinate(s, i) - a_coordinate(a_surfaceNghbrCellId(s, 1), i);
14311 }
14312 }
14313}
14314
14315
14316//-----------------------------------------------------------------------------
14317
14318
14319// template <MInt nDim_, class SysEqn>
14320// void FvCartesianSolverXD<nDim,SysEqn>::updateBndryCollector()
14321//{
14322// TRACE();
14323//
14324// MInt noCells = a_noCells();
14325// //---
14326//
14327// for( MInt cellId = 0; cellId < noCells; cellId++)
14328// if( a_bndryId( cellId ) > -1 )
14329// m_fvBndryCnd->m_bndryCells->a[ a_bndryId( cellId ) ].m_cellId = cellId;
14330//}
14331
14332
14333// ----------------------------------------------------------------------------
14334
14335
14340template <MInt nDim_, class SysEqn>
14342 TRACE();
14343
14344 MInt noCellIds = a_noCells();
14345 MInt bndryId;
14346 MInt smallCell;
14347
14348 // ---------- end of initialization ----------------
14349
14350 // copy fluid cell cogs and correct those of boundary cells
14351 for(MInt cellId = 0; cellId < noCellIds; cellId++) {
14352 if(!a_isBndryGhostCell(cellId)) {
14353 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
14354 // copy coordinates of cog
14355 gccCoordinates[cellId * nDim + spaceId] = a_coordinate(cellId, spaceId);
14356
14357 // correct cog of boundary cells
14358 if(a_bndryId(cellId) > -1) {
14359 bndryId = a_bndryId(cellId);
14360
14361 gccCoordinates[cellId * nDim + spaceId] -= m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[spaceId];
14362 }
14363 }
14364 }
14365 }
14366
14367 // correct coordinates of fluid cells which are masters of a small cell
14368 for(MInt smallId = 0; smallId < m_fvBndryCnd->m_smallBndryCells->size(); smallId++) {
14369 smallCell = m_fvBndryCnd->m_smallBndryCells->a[smallId];
14370 if(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId > -1) {
14371 if(a_bndryId(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId) == -1) {
14372 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
14373 gccCoordinates[(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId) * nDim + spaceId] =
14374 m_fvBndryCnd->m_bndryCells->a[smallCell].m_masterCoordinates[spaceId];
14375 }
14376 }
14377 }
14378 }
14379}
14380
14381
14382// ----------------------------------------------------------------------------
14383
14384
14385template <MInt nDim_, class SysEqn>
14387 TRACE();
14388
14389 MInt smallCell;
14390 MInt masterId;
14391 const MInt noCells = a_noCells();
14392 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
14393 //---
14394
14395 for(MInt cellId = 0; cellId < noCells; cellId++) {
14396 a_cellVolume(cellId) = c_cellLengthAtCell(cellId);
14397 for(MInt spaceId = 1; spaceId < nDim; spaceId++) {
14398 a_cellVolume(cellId) *= c_cellLengthAtCell(cellId);
14399 }
14400 }
14401 // correct the volume of boundary cells
14402 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
14403 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
14404 a_cellVolume(cellId) = m_fvBndryCnd->m_bndryCells->a[bndryId].m_volume;
14405 }
14406
14407 // correct the volume of fluid master cells
14408 for(MInt smallId = 0; smallId < m_fvBndryCnd->m_smallBndryCells->size(); smallId++) {
14409 smallCell = m_fvBndryCnd->m_smallBndryCells->a[smallId];
14410 masterId = m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId;
14411 if(a_bndryId(masterId) == -1) {
14412 a_cellVolume(masterId) += m_fvBndryCnd->m_bndryCells->a[smallCell].m_volume;
14413 }
14414 }
14415
14416 // check the volume of all cells that are
14417 // taken into account
14418 for(MInt cellId = 0; cellId < noCells; cellId++) {
14419 if(a_cellVolume(cellId) < 0.0
14420 // || a_cellVolume( cellId ) < pow( 10.0, -12.0 )
14421 ) {
14422 cerr << "!!!Volume is " << a_cellVolume(cellId) << endl;
14423 cerr << "cell Id " << c_globalId(cellId) << " level " << a_level(cellId) << endl;
14424 if(a_bndryId(cellId) > -1) {
14425 cerr << "... is a boundary cell" << endl << endl;
14426 }
14427 cerr << "Coordinates: " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1);
14428 IF_CONSTEXPR(nDim == 3) cerr << " " << a_coordinate(cellId, 2);
14429 cerr << endl;
14430 }
14431 }
14432
14433 // compute the inverse volume
14434 for(MInt cellId = 0; cellId < noCells; cellId++) {
14435 a_FcellVolume(cellId) = F1 / a_cellVolume(cellId);
14436 }
14437}
14438
14439
14440// --------------------------------------------------------------------------------------
14443// --------------------------------------------------------------------------------------
14444
14448template <MInt nDim_, class SysEqn>
14450 TRACE();
14451 // TODO labels:FV compute sponge factor (linear, tanh)
14452 if(m_spongeLayerThickness > F0) {
14453 std::array<MFloat, 6> values{}; // order is: rho1, p1, rho2, p2, rho3, p3; default are rhoInf and pInf
14454 values = computeTargetValues();
14455
14456 for(MInt c = 0; c < m_noCellsInsideSpongeLayer; c++) {
14457 const MInt cellId = m_cellsInsideSpongeLayer[c];
14458 // update rhs RHO_E, RHO, RHO_V, RHO_U, RHO_W, RHO_Y (NOTE: RHO_Y is not computed by computeSpongeDeltas):
14459 updateSpongeLayerRhs(cellId, computeSpongeDeltas(cellId, values));
14460 }
14461 }
14462}
14463
14464template <MInt nDim_, class SysEqn>
14466 using valueA = std::array<MFloat, 6>;
14467 valueA values;
14468 values[0] = m_rhoInfinity;
14469 values[1] = m_PInfinity;
14470 values[2] = m_rhoInfinity;
14471 values[3] = m_PInfinity;
14472 values[4] = m_rhoInfinity;
14473 values[5] = m_PInfinity;
14474
14475 switch(m_spongeLayerType) {
14476 case 5: {
14477 values[0] = m_rhoHg;
14478 values[1] = m_PHg;
14479 values[2] = m_UHg;
14480 values[3] = m_rhoCg;
14481 values[4] = m_PCg;
14482 values[5] = m_UCg;
14483 break;
14484 }
14485 case 6: {
14486 values[0] = m_rhoInfinity;
14487 values[1] = m_PInfinity;
14488 values[2] = m_UInfinity;
14489 values[3] = m_VInfinity;
14490 values[4] = m_WInfinity;
14491 values[5] = m_UInfinity;
14492 break;
14493 }
14494 case 66: {
14495 values[0] = m_rhoInfinity;
14496 values[1] = m_PInfinity;
14497 values[2] = m_UInfinity;
14498 values[3] = m_VInfinity;
14499 values[4] = m_WInfinity;
14500 values[5] = m_UInfinity;
14501 break;
14502 }
14503 case 77: {
14504 values[0] = m_rhoInfinity;
14505 values[1] = m_PInfinity;
14506 values[2] = m_UInfinity;
14507 values[3] = m_VInfinity;
14508 values[4] = m_WInfinity;
14509 values[5] = m_UInfinity;
14510 break;
14511 }
14512
14513 // FAN --> Alexej Pogorelov
14514 case 41: {
14515 IF_CONSTEXPR(nDim == 2) mTerm(-1, "Info: untested in 2D.");
14516
14517 m_deltaP = 1.002083018;
14518 values[1] = m_PInfinity * m_deltaP;
14519 return values;
14520 }
14521
14522 // this sponge was originally located in fvsolver3d.cpp; so if anything is not working as
14523 // it is supposed to work, look in there
14524 case 51: { // ALLGEMEINER SPONGE MIT MITTELUNG
14525 IF_CONSTEXPR(nDim == 2) mTerm(-1, "Info: This sponge layer type only works in 3D.");
14526
14527 static constexpr MInt noRSteps = 20;
14528
14529 if(m_firstUseUpdateSpongeLayerCase51) {
14530 m_hasCellsInSpongeLayer = m_noCellsInsideSpongeLayer;
14531
14532 m_noSpongeZonesIn = 0;
14533
14545 m_noSpongeZonesOut = 0;
14546 m_noSpongeZonesIn = Context::getSolverProperty<MInt>("noSpongeZonesIn", m_solverId, AT_, &m_noSpongeZonesIn);
14547 m_noSpongeZonesOut = Context::getSolverProperty<MInt>("noSpongeZonesOut", m_solverId, AT_, &m_noSpongeZonesOut);
14548 if(m_noSpongeZonesIn > 0) {
14549 for(MInt i = 0; i < m_noSpongeZonesIn; i++) {
14550 m_spongeDirectionsIn[i] = Context::getSolverProperty<MInt>("spongeDirectionsIn", m_solverId, AT_, i);
14551
14559 m_secondSpongeDirectionsIn[i] =
14560 Context::getSolverProperty<MInt>("secondSpongeDirectionsIn", m_solverId, AT_, i);
14561 m_spongeAveragingIn[i] = Context::getSolverProperty<MInt>("spongeAveragingIn", m_solverId, AT_, i);
14562 }
14563 }
14564 if(m_noSpongeZonesOut > 0) {
14565 for(MInt i = 0; i < m_noSpongeZonesOut; i++) {
14575 m_spongeDirectionsOut[i] = Context::getSolverProperty<MInt>("spongeDirectionsOut", m_solverId, AT_, i);
14576
14584 m_secondSpongeDirectionsOut[i] =
14585 Context::getSolverProperty<MInt>("secondSpongeDirectionsOut", m_solverId, AT_, i);
14586
14594 m_spongeAveragingOut[i] = Context::getSolverProperty<MInt>("spongeAveragingOut", m_solverId, AT_, i);
14595 }
14596 }
14597 MIntScratchSpace comm_buff_scratch_processes(1, AT_, "comm_buff_scratch_processes");
14598 MIntScratchSpace comm_buff_result_scratch_processes(noDomains(), AT_, "comm_buff_result_scratch_processes");
14599 MInt* comm_buff_processes = comm_buff_scratch_processes.getPointer();
14600 MInt* comm_buff_result_processes = comm_buff_result_scratch_processes.getPointer();
14601 comm_buff_processes[0] = m_hasCellsInSpongeLayer;
14602
14603 MPI_Allgather(comm_buff_processes, 1, MPI_INT, comm_buff_result_processes, 1, MPI_INT, mpiComm(), AT_,
14604 "comm_buff_processes", "comm_buff_result_processes");
14605
14606 MPI_Group world_group;
14607 MPI_Group group_sponge;
14608 MInt noProcs_sponge = 0;
14609 for(MInt i = 0; i < noDomains(); i++) {
14610 if(comm_buff_result_processes[i] > 0) {
14611 noProcs_sponge++;
14612 }
14613 }
14614 MIntScratchSpace procs_sponge(noProcs_sponge, AT_, "procs_sponge");
14615 MInt count = 0;
14616 for(MInt i = 0; i < noDomains(); i++) {
14617 if(comm_buff_result_processes[i] > 0) {
14618 procs_sponge[count++] = i;
14619 }
14620 }
14621
14622 MPI_Comm_group(mpiComm(), &world_group, AT_, "world_group");
14623 MPI_Group_incl(world_group, noProcs_sponge, procs_sponge.getPointer(), &group_sponge, AT_);
14624
14625 MPI_Comm_create(mpiComm(), group_sponge, &comm_sponge, AT_, "comm_sponge");
14626
14638 m_timeOfMaxPdiff = 0.0;
14639 m_timeOfMaxPdiff = Context::getSolverProperty<MFloat>("timeOfMaxPdiff", m_solverId, AT_, &m_timeOfMaxPdiff);
14640 // Convert from freestream-based to stagnation-based non-dimensionalization
14641 m_timeOfMaxPdiff = m_timeOfMaxPdiff / m_timeRef;
14642
14643 m_firstUseUpdateSpongeLayerCase51 = false;
14644
14645 // allocate sponge specific variables, which need to persist through the whole run
14646 mAlloc(m_coordSpongeIn, m_noSpongeZonesIn, "m_coordSpongeIn", AT_);
14647 mAlloc(m_secondCoordSpongeIn, m_noSpongeZonesIn, "m_secondCoordSpongeIn", AT_);
14648 mAlloc(m_coordSpongeOut, m_noSpongeZonesOut, "m_coordSpongeOut", AT_);
14649 mAlloc(m_secondCoordSpongeOut, m_noSpongeZonesOut, "m_secondCoordSpongeOut", AT_);
14650 mAlloc(m_uNormal_r, noRSteps, "m_uNormal_r", AT_);
14651 }
14652 if(!m_hasCellsInSpongeLayer) {
14653 break; // return;
14654 }
14655 MFloatScratchSpace spongeVolumeIn(m_noSpongeZonesIn, AT_, "spongeVolumeIn");
14656 MFloatScratchSpace spongeVolumeOut(m_noSpongeZonesOut, AT_, "spongeVolumeOut");
14657 MFloatScratchSpace pressureIn(m_noSpongeZonesIn, AT_, "pressureIn");
14658 MFloatScratchSpace pressureOut(m_noSpongeZonesOut, AT_, "pressureOut");
14659 MFloatScratchSpace densityIn(m_noSpongeZonesIn, AT_, "densityIn");
14660 MFloatScratchSpace densityOut(m_noSpongeZonesOut, AT_, "densityOut");
14661 MFloatScratchSpace coordAverageIn(m_noSpongeZonesIn, AT_, "coordAverageIn");
14662 MFloatScratchSpace coordAverageOut(m_noSpongeZonesOut, AT_, "coordAverageOut");
14663 MFloatScratchSpace comm_buff_scratch(2 * m_noSpongeZonesIn + 2 * m_noSpongeZonesOut + 40, AT_,
14664 "comm_buff_scratch");
14665 MFloatScratchSpace comm_buff_result_scratch(2 * m_noSpongeZonesIn + 2 * m_noSpongeZonesOut + 40, AT_,
14666 "comm_buff_result_scratch");
14667 MFloat* comm_buff = comm_buff_scratch.getPointer();
14668 MFloat* comm_buff_result = comm_buff_result_scratch.getPointer();
14669 MFloat bBox[6];
14670 auto* tmp = new MFloat[6];
14671 m_geometry->getBoundingBox(tmp);
14672 bBox[0] = tmp[0];
14673 bBox[1] = tmp[3];
14674 bBox[2] = tmp[1];
14675 bBox[3] = tmp[4];
14676 bBox[4] = tmp[2];
14677 bBox[5] = tmp[5];
14678 constexpr MFloat directionSign[6] = {1.0, -1.0, 1.0, -1.0, 1.0, -1.0};
14679 constexpr MInt directionDim[6] = {0, 0, 1, 1, 2, 2};
14680 constexpr MInt otherDirection[6] = {1, 0, 3, 2, 5, 4};
14681 const MFloat cellLength = c_cellLengthAtLevel(maxRefinementLevel());
14682 const MFloat R = 2.0;
14683 MInt counter_r[noRSteps];
14684 for(MInt i = 0; i < noRSteps; i++) {
14685 m_uNormal_r[i] = F0;
14686 counter_r[i] = 0;
14687 }
14688 const MFloat rDiff = R / noRSteps;
14689
14690 // ---------------------
14691
14692 for(MInt i = 0; i < m_noSpongeZonesIn; i++) {
14693 densityIn[i] = F0;
14694 pressureIn[i] = F0;
14695 spongeVolumeIn[i] = F0;
14696 coordAverageIn[i] = bBox[m_spongeDirectionsIn[i]]
14697 + directionSign[m_spongeDirectionsIn[i]] * m_spongeAveragingIn[i] * cellLength;
14698 m_coordSpongeIn[i] = m_spongeCoord[m_spongeDirectionsIn[i]];
14699 if(m_secondSpongeDirectionsIn[i] > -1) {
14700 m_secondCoordSpongeIn[i] =
14701 F1B2 * (bBox[m_secondSpongeDirectionsIn[i]] + bBox[otherDirection[m_secondSpongeDirectionsIn[i]]]);
14702 } else {
14703 m_secondSpongeDirectionsIn[i] = m_spongeDirectionsIn[i];
14704 m_secondCoordSpongeIn[i] = bBox[otherDirection[m_secondSpongeDirectionsIn[i]]];
14705 }
14706 }
14707 for(MInt i = 0; i < m_noSpongeZonesOut; i++) {
14708 densityOut[i] = F0;
14709 pressureOut[i] = F0;
14710 spongeVolumeOut[i] = F0;
14711 coordAverageOut[i] = bBox[m_spongeDirectionsOut[i]]
14712 + directionSign[m_spongeDirectionsOut[i]] * m_spongeAveragingOut[i] * cellLength;
14713 m_coordSpongeOut[i] = m_spongeCoord[m_spongeDirectionsOut[i]];
14714 if(m_secondSpongeDirectionsOut[i] > -1) {
14715 m_secondCoordSpongeOut[i] =
14716 F1B2 * (bBox[m_secondSpongeDirectionsOut[i]] + bBox[otherDirection[m_secondSpongeDirectionsOut[i]]]);
14717 } else {
14718 m_secondSpongeDirectionsOut[i] = m_spongeDirectionsOut[i];
14719 m_secondCoordSpongeOut[i] = bBox[otherDirection[m_secondSpongeDirectionsOut[i]]];
14720 }
14721 }
14722
14723 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14724 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
14725 continue;
14726 }
14727 if(a_hasProperty(cellId, SolverCell::IsInvalid)) {
14728 continue;
14729 }
14730 if(!a_hasProperty(cellId, SolverCell::IsActive)) {
14731 continue;
14732 }
14733
14734 for(MInt i = 0; i < m_noSpongeZonesIn; i++) {
14735 if(!a_isBndryGhostCell(cellId)
14736 && (a_coordinate(cellId, directionDim[m_spongeDirectionsIn[i]]) - coordAverageIn[i])
14737 * directionSign[m_spongeDirectionsIn[i]]
14738 < F0
14739 && (a_coordinate(cellId, directionDim[m_secondSpongeDirectionsIn[i]]) - m_secondCoordSpongeIn[i])
14740 * directionSign[m_secondSpongeDirectionsIn[i]]
14741 < F0) {
14742 pressureIn[i] += a_pvariable(cellId, PV->P) * a_cellVolume(cellId);
14743 spongeVolumeIn[i] += a_cellVolume(cellId);
14744 if(a_bndryId(cellId) > -1) {
14745 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs; srfc++) {
14746 const MInt ghostCellId =
14747 m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcVariables[srfc]->m_ghostCellId;
14748 pressureIn[i] += a_pvariable(ghostCellId, PV->P) * a_cellVolume(ghostCellId);
14749 spongeVolumeIn[i] += a_cellVolume(ghostCellId);
14750 }
14751 }
14752 }
14753 }
14754 for(MInt i = 0; i < m_noSpongeZonesOut; i++) {
14755 if(!a_isBndryGhostCell(cellId)
14756 && (a_coordinate(cellId, directionDim[m_spongeDirectionsOut[i]]) - coordAverageOut[i])
14757 * directionSign[m_spongeDirectionsOut[i]]
14758 < F0
14759 && (a_coordinate(cellId, directionDim[m_secondSpongeDirectionsOut[i]]) - m_secondCoordSpongeOut[i])
14760 * directionSign[m_secondSpongeDirectionsOut[i]]
14761 < F0) {
14762 densityOut[i] += a_pvariable(cellId, PV->RHO) * a_cellVolume(cellId);
14763 spongeVolumeOut[i] += a_cellVolume(cellId);
14764
14765 const MFloat r = sqrt(POW2(a_coordinate(cellId, 1)) + POW2(a_coordinate(cellId, 2)));
14766 const auto rIndex = (MInt)((R - r) / rDiff);
14767 m_uNormal_r[rIndex] += a_pvariable(cellId, PV->U);
14768 counter_r[rIndex]++;
14769 }
14770 }
14771 }
14772
14773
14774 for(MInt i = 0; i < m_noSpongeZonesIn; i++) {
14775 comm_buff[2 * i] = pressureIn[i];
14776 comm_buff[2 * i + 1] = spongeVolumeIn[i];
14777 }
14778 // FIXME labels:FV The following buffer is not used later, so what is the purpose of densityOut & spongeVolumeOut
14779 for(MInt i = 0; i < m_noSpongeZonesOut; i++) {
14780 comm_buff[2 * m_noSpongeZonesIn + 2 * i] = densityOut[i];
14781 comm_buff[2 * m_noSpongeZonesIn + 2 * i + 1] = spongeVolumeOut[i];
14782 }
14783 for(MInt i = 0; i < 20; i++) {
14784 comm_buff[2 * m_noSpongeZonesIn + 2 * m_noSpongeZonesOut + i] = m_uNormal_r[i];
14785 comm_buff[2 * m_noSpongeZonesIn + 2 * m_noSpongeZonesOut + 20 + i] = counter_r[i];
14786 }
14787
14788 MPI_Allreduce(comm_buff, comm_buff_result, 2 * (m_noSpongeZonesIn + m_noSpongeZonesOut) + 40, MPI_DOUBLE, MPI_SUM,
14789 comm_sponge, AT_, "comm_buff", "comm_buff_result");
14790
14791 for(MInt i = 0; i < m_noSpongeZonesIn; i++) {
14792 pressureIn[i] = comm_buff_result[2 * i] / comm_buff_result[2 * i + 1];
14793 densityIn[i] = sysEqn().density_IR_P(pressureIn[i]);
14794 }
14795 for(MInt i = 0; i < noRSteps; i++) {
14796 m_uNormal_r[i] = comm_buff_result[i + 2 * (m_noSpongeZonesIn + m_noSpongeZonesOut)]
14797 / comm_buff_result[i + 2 * (m_noSpongeZonesIn + m_noSpongeZonesOut) + 20];
14798 if(m_uNormal_r[i] < F0) {
14799 m_uNormal_r[i] = F0;
14800 }
14801 }
14802
14803 // only pressureIn is saved in values, since the other values can be deduced later
14804 if(m_noSpongeZonesIn > 6)
14805 mTerm(1, AT_,
14806 "FvCartesianSolverXD::computeTargetValues(): For noSpongeZonesIn>6 the code needs to be "
14807 "modified.");
14808
14809 for(MInt i = 0; i < m_noSpongeZonesIn; i++)
14810 values[i] = pressureIn[i];
14811
14812 return values;
14813 }
14814
14815 // Sponge for jets from (chevron) nozzle
14816 case 1174: {
14817 const MFloat pressureAmbient = m_PInfinity;
14818 const MFloat densityAmbient = m_rhoInfinity;
14819
14820 const MFloat pressure_i = m_nozzleInletP;
14821 const MFloat density_i = m_nozzleInletRho;
14822
14823 values[0] = density_i;
14824 values[1] = pressure_i;
14825
14826 values[2] = densityAmbient;
14827 values[3] = pressureAmbient;
14828
14829 break;
14830 }
14831
14832 case 47: {
14833 MInt ghostCellId;
14834 MFloatScratchSpace comm_buff_scratch(6, AT_, "comm_buff_scratch");
14835 MFloatScratchSpace comm_buff_result_scratch(6, AT_, "comm_buff_result_scratch");
14836 MFloat* comm_buff = comm_buff_scratch.getPointer();
14837 MFloat* comm_buff_result = comm_buff_result_scratch.getPointer();
14838 MFloat density = F0;
14839 MFloat spongeVolume = F0;
14840 MFloat pressureIn1 = F0;
14841 MFloat spongeVolumeIn1 = F0;
14842 MFloat pressureIn2 = F0;
14843 MFloat spongeVolumeIn2 = F0;
14844 MFloat u_in1 = F0;
14845 MFloat v_in1 = F0;
14846 MFloat w_in1 = F0;
14847 MFloat u_in2 = F0;
14848 MFloat v_in2 = F0;
14849 MFloat w_in2 = F0;
14850 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
14851 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
14852 continue;
14853 }
14854 if(a_hasProperty(cellId, SolverCell::IsInvalid)) {
14855 continue;
14856 }
14857 if(!a_hasProperty(cellId, SolverCell::IsActive)) {
14858 continue;
14859 }
14860 if(a_hasProperty(cellId, SolverCell::IsHalo)) continue;
14861 if(!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 2) < -67.0) {
14862 density += a_pvariable(cellId, PV->RHO) * a_cellVolume(cellId);
14863 spongeVolume += a_cellVolume(cellId);
14864 }
14865 if(!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 0) > 82.0 && a_coordinate(cellId, 1) > 0.0) {
14866 pressureIn1 += a_pvariable(cellId, PV->P) * a_cellVolume(cellId);
14867 u_in1 += a_pvariable(cellId, PV->U) * a_cellVolume(cellId);
14868 v_in1 += a_pvariable(cellId, PV->V) * a_cellVolume(cellId);
14869 w_in1 += a_pvariable(cellId, PV->W) * a_cellVolume(cellId);
14870 spongeVolumeIn1 += a_cellVolume(cellId);
14871 if(a_bndryId(cellId) > -1) {
14872 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs; srfc++) {
14873 ghostCellId = m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcVariables[srfc]->m_ghostCellId;
14874 pressureIn1 += a_pvariable(ghostCellId, PV->P) * a_cellVolume(ghostCellId);
14875 spongeVolumeIn1 += a_cellVolume(ghostCellId);
14876 }
14877 }
14878 }
14879 if(!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 0) > 82.0 && a_coordinate(cellId, 1) < 0.0) {
14880 pressureIn2 += a_pvariable(cellId, PV->P) * a_cellVolume(cellId);
14881 u_in2 += a_pvariable(cellId, PV->U) * a_cellVolume(cellId);
14882 v_in2 += a_pvariable(cellId, PV->V) * a_cellVolume(cellId);
14883 w_in2 += a_pvariable(cellId, PV->W) * a_cellVolume(cellId);
14884 spongeVolumeIn2 += a_cellVolume(cellId);
14885 if(a_bndryId(cellId) > -1) {
14886 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs; srfc++) {
14887 ghostCellId = m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcVariables[srfc]->m_ghostCellId;
14888 pressureIn2 += a_pvariable(ghostCellId, PV->P) * a_cellVolume(ghostCellId);
14889 u_in2 += a_pvariable(ghostCellId, PV->U) * a_cellVolume(ghostCellId);
14890 v_in2 += a_pvariable(ghostCellId, PV->V) * a_cellVolume(ghostCellId);
14891 w_in2 += a_pvariable(ghostCellId, PV->W) * a_cellVolume(ghostCellId);
14892 spongeVolumeIn2 += a_cellVolume(ghostCellId);
14893 }
14894 }
14895 }
14896 }
14897 comm_buff[0] = density;
14898 comm_buff[1] = pressureIn1;
14899 comm_buff[2] = pressureIn2;
14900 comm_buff[3] = spongeVolume;
14901 comm_buff[4] = spongeVolumeIn1;
14902 comm_buff[5] = spongeVolumeIn2;
14903 MPI_Allreduce(comm_buff, comm_buff_result, 6, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "comm_buff",
14904 "comm_buff_result");
14905 density = comm_buff_result[0] / comm_buff_result[3];
14906 MFloat pressure = m_PInfinity - m_deltaPL;
14907 pressureIn1 = comm_buff_result[1] / comm_buff_result[4];
14908 MFloat densityIn1 = sysEqn().density_IR_P(pressureIn1);
14909 pressureIn2 = comm_buff_result[2] / comm_buff_result[5];
14910 MFloat densityIn2 = sysEqn().density_IR_P(pressureIn2);
14911 if(globalTimeStep < 550) {
14912 pressureIn1 = sysEqn().p_Ref();
14913 densityIn1 = 1.0;
14914 pressureIn2 = pressureIn1;
14915 densityIn2 = densityIn1;
14916 }
14917 values[0] = density;
14918 values[1] = pressure;
14919 values[2] = densityIn1;
14920 values[3] = pressureIn1;
14921 values[4] = densityIn2;
14922 values[5] = pressureIn2;
14923 return values;
14924 }
14925
14926
14927 default: {
14928 values[0] = m_rhoInfinity;
14929 values[1] = m_PInfinity;
14930 values[2] = m_rhoInfinity;
14931 values[3] = m_PInfinity;
14932 values[4] = m_rhoInfinity;
14933 values[5] = m_PInfinity;
14934 return values;
14935 }
14936
14937 // forced response velocity profile, forcing via sponge layer
14938 // This sponge has been moved from fvsolver2d.cpp, so evtl. you can have a look there
14939 case 17515: {
14940 IF_CONSTEXPR(nDim == 3) mTerm(-1, "Info: This sponge layer type only works in 2D.");
14941
14942 MFloat pressure;
14943 MFloat maxSpongeFactor1 = -999999, minSpongeFactor1 = 999999;
14944 MFloat maxSpongeFactor2 = -999999, minSpongeFactor2 = 999999;
14945 MFloat maxSpongeFactor3 = -999999, minSpongeFactor3 = 999999;
14946 MFloat spongeEndFactor = -99999;
14947 //---
14948 // save previous mean pressure for weighting
14949 const MFloat backupMeanPressure = m_meanPressure;
14950
14951 m_meanPressure = F0;
14952 // compute the mean pressure for all cells in the sponge zone below the reaction zone
14953 MInt counter = 0;
14954 for(MInt c = 0; c < m_noCellsInsideSpongeLayer; c++) {
14955 const MInt cellId = m_cellsInsideSpongeLayer[c];
14956 if(a_spongeBndryId(cellId, 0) == 176191 || a_spongeBndryId(cellId, 1) == 176191
14957 || a_spongeBndryId(cellId, 0) == 209104 || a_spongeBndryId(cellId, 1) == 209104
14958 || a_spongeBndryId(cellId, 0) == 209101 || a_spongeBndryId(cellId, 1) == 209101
14959 || a_spongeBndryId(cellId, 0) == 17616 || a_spongeBndryId(cellId, 1) == 17616
14960 || a_spongeBndryId(cellId, 0) == 3906 || a_spongeBndryId(cellId, 1) == 3906
14961 || a_spongeBndryId(cellId, 0) == 39060 || a_spongeBndryId(cellId, 1) == 39060
14962 || a_spongeBndryId(cellId, 0) == 209102 || a_spongeBndryId(cellId, 1) == 209102) {
14963 counter++;
14964 m_meanPressure += a_pvariable(cellId, PV->P);
14965 }
14966 }
14967
14968 MPI_Allreduce(MPI_IN_PLACE, &m_meanPressure, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
14969 "m_meanPressure");
14970 MPI_Allreduce(MPI_IN_PLACE, &counter, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "counter");
14971
14972 m_meanPressure /= (MFloat)counter;
14973
14974 if(!m_forcing) {
14975 for(MInt c = 0; c < m_noCellsInsideSpongeLayer; c++) {
14976 const MInt cellId = m_cellsInsideSpongeLayer[c];
14977 // search for time dependent sponge id and set new sigma sponge
14978 if(m_spongeTimeDep) {
14979 for(MInt bcId = 0; bcId < m_noSpongeBndryCndIds; bcId++) {
14980 const MInt bcSpId = m_spongeBndryCndIds[bcId];
14981
14982 if(a_spongeBndryId(cellId, 0) != bcSpId && a_spongeBndryId(cellId, 1) != bcSpId) continue;
14983
14984 // Jerry - Changed double sponge for looking after time dependence before skipping it.
14985 MInt bcId2 = -2;
14986 MInt bcSpId2 = -2;
14987 if(a_spongeBndryId(cellId, 1) != -1) {
14988 if(a_spongeBndryId(cellId, 1) == bcSpId) {
14989 bcSpId2 = a_spongeBndryId(cellId, 0);
14990 } else {
14991 bcSpId2 = a_spongeBndryId(cellId, 1);
14992 }
14993
14994 for(MInt k = 0; k < m_noSpongeBndryCndIds; ++k) {
14995 if(m_spongeBndryCndIds[k] == bcSpId2) {
14996 bcId2 = k;
14997 break;
14998 }
14999 }
15000
15001 // if (m_spongeTimeDependent[bcId2]<1) {
15002 // continue;
15003 // }
15004 }
15005 if(bcId2 != -2) {
15006 if(m_spongeTimeDependent[bcId] < 1 && m_spongeTimeDependent[bcId2] < 1) continue;
15007
15008 } else {
15009 if(m_spongeTimeDependent[bcId] < 1) continue;
15010 }
15011
15012 // if(a_spongeBndryId(cellId, 0) != bcSpId && a_spongeBndryId(cellId, 1) != bcSpId) {
15013 // continue;
15014 // }
15015
15016 // sponge decreasing function from spongeFactorStart down to zero via tanh function / sponge edges treated
15017 // separately
15018 if(m_spongeTimeDependent[bcId] == 1 || m_spongeTimeDependent[bcId2] == 1) {
15019 if(a_spongeBndryId(cellId, 0) == bcSpId && a_spongeBndryId(cellId, 1) == -1) {
15020 if(globalTimeStep >= (MInt)m_spongeStartIteration[bcId]
15021 && globalTimeStep <= (MInt)m_spongeEndIteration[bcId]) {
15022 const MFloat spongeDiff = m_spongeEndIteration[bcId] - m_spongeStartIteration[bcId];
15023 a_spongeFactor(cellId) =
15024 F1B2 * tanh(5.0)
15025 - F1B2
15026 * tanh((F2 * ((MFloat)globalTimeStep - m_spongeStartIteration[bcId]) - spongeDiff) * 5.0
15027 / spongeDiff);
15028 a_spongeFactor(cellId) *= a_spongeFactorStart(cellId);
15029
15030 maxSpongeFactor1 = mMax(a_spongeFactor(cellId), maxSpongeFactor1);
15031 minSpongeFactor1 = mMin(a_spongeFactor(cellId), minSpongeFactor1);
15032
15033 if(approx(a_spongeFactorStart(cellId), -1.0, MFloatEps)) {
15034 cerr << "sponge time dependent error, see code in fvbndrycnd2d.cpp or fvsolver2d.cpp" << endl;
15035 }
15036
15037 } else if(globalTimeStep < (MInt)m_spongeStartIteration[bcId]) {
15038 a_spongeFactor(cellId) = a_spongeFactorStart(cellId);
15039
15040 maxSpongeFactor1 = mMax(a_spongeFactor(cellId), maxSpongeFactor1);
15041 minSpongeFactor1 = mMin(a_spongeFactor(cellId), minSpongeFactor1);
15042
15043 } else if(globalTimeStep > (MInt)m_spongeEndIteration[bcId]) {
15044 a_spongeFactor(cellId) = F0;
15045 maxSpongeFactor1 = F0;
15046 minSpongeFactor1 = F0;
15047 }
15048 } else {
15049 // take dir
15050 MInt s2;
15051 MInt bcIdS;
15052 MInt bcIdT;
15053 if(m_spongeTimeDependent[bcId] == 1) {
15054 bcIdS = bcId2;
15055 bcIdT = bcId;
15056 } else if(m_spongeTimeDependent[bcId2] == 1) {
15057 bcIdS = bcId;
15058 bcIdT = bcId2;
15059
15060 } else {
15061 stringstream errorMessage;
15062 errorMessage << "ERROR: sponge time dependent";
15063 mTerm(1, AT_, errorMessage.str());
15064 }
15065 switch(m_spongeDirections[bcIdS]) {
15066 case 1:
15067 s2 = 0;
15068 break;
15069 case 0:
15070 s2 = 0;
15071 break;
15072 case 3:
15073 s2 = 1;
15074 break;
15075 case 2:
15076 s2 = 1;
15077 break;
15078 case 5:
15079 s2 = 2;
15080 break;
15081 case 4:
15082 s2 = 2;
15083 break;
15084 default: {
15085 mTerm(1, AT_, "wrong sponge direction selected during solver run, how can this happen?!");
15086 }
15087 }
15088 // calculate sponge end factor which depends on distance to the according wall
15089 MFloat spongeEpsilon = c_cellLengthAtLevel(maxLevel()) / 1000.0;
15090 MFloat spongeFactorBcId = m_spongeLayerThickness * abs(m_spongeFactor[bcIdS]);
15091 MFloat spongeDistanceFactor = F1 / (mMax(spongeEpsilon, spongeFactorBcId));
15092 MFloat spongeDistance = abs(a_coordinate(cellId, s2) - m_spongeCoord[bcIdS]) * spongeDistanceFactor;
15093 spongeEndFactor = pow(spongeDistance, m_spongeBeta);
15094 spongeEndFactor *= m_sigmaSpongeBndryId[bcIdS];
15095 if(globalTimeStep <= 1 && bcId2 != -2) {
15096 m_log << "spongeEnd " << spongeEndFactor << endl;
15097 }
15098 if(globalTimeStep >= (MInt)m_spongeStartIteration[bcIdT]
15099 && globalTimeStep <= (MInt)m_spongeEndIteration[bcIdT]) {
15100 const MFloat spongeDiff = m_spongeEndIteration[bcIdT] - m_spongeStartIteration[bcIdT];
15101 // calculate the sponge end factor via sigma sponge ratio in order to keep the factor distance
15102 // dependent
15103 // spongeEndFactor = a_spongeFactorStart( cellId ) /m_sigmaSpongeBndryId[bcIdTT];
15104 // spongeEndFactor *=m_sigmaEndSpongeBndryId[bcIdTT];
15105
15106 // spongeFactorDiff = a_spongeFactorStart( cellId ) - spongeEndFactor;
15107 const MFloat spongeFactorDiff = spongeEndFactor - a_spongeFactorStart(cellId);
15108 a_spongeFactor(cellId) =
15109 a_spongeFactorStart(cellId) + (spongeFactorDiff / spongeDiff) * globalTimeStep;
15110 // a_spongeFactor( cellId ) = spongeFactorDiff * (F1 + F1B2 * tanh(5.0) - F1B2 * tanh((F2 *
15111 //((MFloat)globalTimeStep - m_spongeStartIteration[bcIdT]) - spongeDiff) * 5.0 / spongeDiff));
15112
15113 maxSpongeFactor1 = mMax(a_spongeFactor(cellId), maxSpongeFactor1);
15114 minSpongeFactor1 = mMin(a_spongeFactor(cellId), minSpongeFactor1);
15115
15116 if(approx(a_spongeFactorStart(cellId), -1.0, MFloatEps)) {
15117 cerr << "sponge time dependent error, see code in fvbndrycnd2d.cpp or fvsolver2d.cpp" << endl;
15118 }
15119
15120
15121 } else if(globalTimeStep < (MInt)m_spongeStartIteration[bcIdT]) {
15122 a_spongeFactor(cellId) = a_spongeFactorStart(cellId);
15123
15124 maxSpongeFactor1 = mMax(a_spongeFactor(cellId), maxSpongeFactor1);
15125 minSpongeFactor1 = mMin(a_spongeFactor(cellId), minSpongeFactor1);
15126
15127 } else if(globalTimeStep > (MInt)m_spongeEndIteration[bcIdT]) {
15128 a_spongeFactor(cellId) = spongeEndFactor;
15129 maxSpongeFactor1 = F0;
15130 minSpongeFactor1 = F0;
15131 }
15132 }
15133 break;
15134 // sponge rising function from zero up to spongeFactorStart (calculated dependent on distance to the
15135 // wall, see spongeLayerLayout)
15136 } else if(m_spongeTimeDependent[bcId] == 2) {
15137 if(globalTimeStep >= (MInt)m_spongeStartIteration[bcId]
15138 && globalTimeStep <= (MInt)m_spongeEndIteration[bcId]) {
15139 const MFloat spongeDiff = m_spongeEndIteration[bcId] - m_spongeStartIteration[bcId];
15140 a_spongeFactor(cellId) =
15141 F1 - F1B2 * tanh(5.0)
15142 + F1B2
15143 * tanh((F2 * ((MFloat)globalTimeStep - m_spongeStartIteration[bcId]) - spongeDiff) * 5.0
15144 / spongeDiff);
15145 a_spongeFactor(cellId) *= a_spongeFactorStart(cellId);
15146
15147 maxSpongeFactor2 = mMax(a_spongeFactor(cellId), maxSpongeFactor2);
15148 minSpongeFactor2 = mMin(a_spongeFactor(cellId), minSpongeFactor2);
15149
15150 if(approx(a_spongeFactorStart(cellId), -1.0, MFloatEps)) {
15151 cerr << "sponge time dependent error, see code in fvbndrycnd2d.cpp or fvsolver2d.cpp" << endl;
15152 }
15153
15154 } else if(globalTimeStep < m_spongeStartIteration[bcId]) {
15155 a_spongeFactor(cellId) = F0;
15156 maxSpongeFactor2 = F0;
15157 minSpongeFactor2 = F0;
15158
15159 } else if(globalTimeStep > m_spongeEndIteration[bcId]) {
15160 a_spongeFactor(cellId) = a_spongeFactorStart(cellId);
15161 maxSpongeFactor2 = mMax(a_spongeFactor(cellId), maxSpongeFactor2);
15162 minSpongeFactor2 = mMin(a_spongeFactor(cellId), minSpongeFactor2);
15163 }
15164 break;
15165 // sponge decreasing function from spongeFactor down to spongeEndFactor (calculated dependent on
15166 // distance to the wall, see spongeLayerLayout)
15167 } else if(m_spongeTimeDependent[bcId] == 3) {
15168 if(globalTimeStep >= (MInt)m_spongeStartIteration[bcId]
15169 && globalTimeStep <= (MInt)m_spongeEndIteration[bcId]) {
15170 const MFloat spongeDiff = m_spongeEndIteration[bcId] - m_spongeStartIteration[bcId];
15171 // calculate the sponge end factor via sigma sponge ratio in order to keep the factor distance
15172 // dependent
15173 spongeEndFactor = a_spongeFactorStart(cellId) / m_sigmaSpongeBndryId[bcId];
15174 spongeEndFactor *= m_sigmaEndSpongeBndryId[bcId];
15175
15176 const MFloat spongeFactorDiff = a_spongeFactorStart(cellId) - spongeEndFactor;
15177
15178 a_spongeFactor(cellId) =
15179 spongeFactorDiff
15180 * (F1 + F1B2 * tanh(5.0)
15181 - F1B2
15182 * tanh((F2 * ((MFloat)globalTimeStep - m_spongeStartIteration[bcId]) - spongeDiff) * 5.0
15183 / spongeDiff));
15184
15185 maxSpongeFactor3 = mMax(a_spongeFactor(cellId), maxSpongeFactor3);
15186 minSpongeFactor3 = mMin(a_spongeFactor(cellId), minSpongeFactor3);
15187
15188 if(approx(a_spongeFactorStart(cellId), -1.0, MFloatEps)) {
15189 cerr << "sponge time dependent error, see code in fvbndrycnd2d.cpp or fvsolver2d.cpp" << endl;
15190 }
15191
15192 // before increasing function, set the sponge factor to the initial spongeFactor
15193 } else if(globalTimeStep < m_spongeStartIteration[bcId]) {
15194 a_spongeFactor(cellId) = a_spongeFactorStart(cellId);
15195 maxSpongeFactor3 = mMax(a_spongeFactor(cellId), maxSpongeFactor3);
15196 minSpongeFactor3 = mMin(a_spongeFactor(cellId), minSpongeFactor3);
15197
15198 // calculate the sponge end factor via sigma sponge ratio in order to keep the factor distance
15199 // dependent
15200 } else if(globalTimeStep > m_spongeEndIteration[bcId]) {
15201 spongeEndFactor = a_spongeFactorStart(cellId) / m_sigmaSpongeBndryId[bcId];
15202 spongeEndFactor *= m_sigmaEndSpongeBndryId[bcId];
15203 a_spongeFactor(cellId) = spongeEndFactor;
15204 maxSpongeFactor3 = mMax(spongeEndFactor, maxSpongeFactor3);
15205 minSpongeFactor3 = mMin(spongeEndFactor, minSpongeFactor3);
15206 }
15207 break;
15208 // sponge rising function from desired start factor up to spongeEndFactor (calculated dependent on
15209 // distance to the wall, see spongeLayerLayout)
15210 } else if(m_spongeTimeDependent[bcId] == 4) {
15211 if(globalTimeStep >= (MInt)m_spongeStartIteration[bcId]
15212 && globalTimeStep <= (MInt)m_spongeEndIteration[bcId]) {
15213 const MFloat spongeDiff = m_spongeEndIteration[bcId] - m_spongeStartIteration[bcId];
15214 // calculate the sponge end factor via sigma sponge ratio in order to keep the factor distance
15215 // dependent
15216 spongeEndFactor = a_spongeFactorStart(cellId) / m_sigmaSpongeBndryId[bcId];
15217 spongeEndFactor *= m_sigmaEndSpongeBndryId[bcId];
15218
15219 const MFloat spongeFactorDiff = spongeEndFactor - a_spongeFactorStart(cellId);
15220
15221 a_spongeFactor(cellId) =
15222 a_spongeFactorStart(cellId)
15223 + spongeFactorDiff
15224 * (F1 - F1B2 * tanh(5.0)
15225 + F1B2
15226 * tanh((F2 * ((MFloat)globalTimeStep - m_spongeStartIteration[bcId]) - spongeDiff)
15227 * 5.0 / spongeDiff));
15228
15229 maxSpongeFactor2 = mMax(a_spongeFactor(cellId), maxSpongeFactor2);
15230 minSpongeFactor2 = mMin(a_spongeFactor(cellId), minSpongeFactor2);
15231
15232 if(approx(a_spongeFactorStart(cellId), -1.0, MFloatEps)) {
15233 cerr << "sponge time dependent error, see code in fvbndrycnd2d.cpp or fvsolver2d.cpp" << endl;
15234 }
15235
15236 } else if(globalTimeStep < m_spongeStartIteration[bcId]) {
15237 a_spongeFactor(cellId) = F0;
15238 maxSpongeFactor2 = F0;
15239 minSpongeFactor2 = F0;
15240
15241 } else if(globalTimeStep > m_spongeEndIteration[bcId]) {
15242 a_spongeFactor(cellId) = a_spongeFactorStart(cellId);
15243 maxSpongeFactor2 = mMax(a_spongeFactor(cellId), maxSpongeFactor2);
15244 minSpongeFactor2 = mMin(a_spongeFactor(cellId), minSpongeFactor2);
15245 }
15246 break;
15247 }
15248 } // for(MInt bcId = 0; bcId < m_noSpongeBndryCndIds; bcId++) ends here
15249 } // if(m_spongeTimeDep) ends here
15250 } // for(MInt c = 0; c < m_noCellsInsideSpongeLayer; c++) ends here
15251
15252 if(m_spongeTimeDep) {
15253 if(m_RKStep == m_noRKSteps - 1 && globalTimeStep % 1000) {
15254 if(noDomains() > 1) {
15255 MPI_Allreduce(MPI_IN_PLACE, &maxSpongeFactor1, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
15256 "maxSpongeFactor1");
15257 MPI_Allreduce(MPI_IN_PLACE, &maxSpongeFactor2, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
15258 "maxSpongeFactor2");
15259 MPI_Allreduce(MPI_IN_PLACE, &maxSpongeFactor3, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
15260 "maxSpongeFactor3");
15261 MPI_Allreduce(MPI_IN_PLACE, &minSpongeFactor1, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
15262 "minSpongeFactor1");
15263 MPI_Allreduce(MPI_IN_PLACE, &minSpongeFactor2, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
15264 "minSpongeFactor2");
15265 MPI_Allreduce(MPI_IN_PLACE, &minSpongeFactor3, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE",
15266 "minSpongeFactor3");
15267 }
15268 if(domainId() == 0) {
15269 FILE* datei;
15270 datei = fopen("spongeFactor", "a+");
15271 fprintf(datei, " %d", globalTimeStep);
15272 fprintf(datei, " %f", m_time);
15273 fprintf(datei, " %-10.8f", maxSpongeFactor1);
15274 fprintf(datei, " %-10.8f", minSpongeFactor1);
15275 fprintf(datei, " %-10.8f", maxSpongeFactor2);
15276 fprintf(datei, " %-10.8f", minSpongeFactor2);
15277 fprintf(datei, " %-10.8f", maxSpongeFactor3);
15278 fprintf(datei, " %-10.8f", minSpongeFactor3);
15279 fprintf(datei, "\n");
15280 fclose(datei);
15281 }
15282 }
15283 }
15284
15285 // compute target pressure & density
15286 // later in computeSpongeDeltas the appropriate one is chosen depending on cellId
15287 // --- Case 1 ---
15288 MFloat pressureLoss = F0;
15289 if(m_plenum) {
15290 pressureLoss = m_rhoInfinity * POW2(m_VInfinity) * (m_inletTubeAreaRatio - F1);
15291 }
15292 // pressure loss = pressure Loss (Inlet -> flame tube) + pressure Loss (Flame surface -> Outlet)
15293 if(m_plenumWall) {
15294 pressureLoss += m_rhoFlameTube * m_targetDensityFactor
15295 * (POW2(m_velocityOutlet) - POW2(m_flameSpeed) * m_flameOutletAreaRatio);
15296 }
15297
15298 if(m_plenum) {
15299 pressure =
15300 m_PInfinity + m_rhoInfinity * POW2(m_VInfinity) * (m_burntUnburntTemperatureRatio - F1) + pressureLoss;
15301 } else {
15302 pressure =
15303 m_PInfinity + m_rhoInfinity * POW2(m_flameSpeed) * (m_burntUnburntTemperatureRatio - F1) + pressureLoss;
15304 }
15305
15306 if(m_confinedFlame) {
15307 pressure = backupMeanPressure * (m_spongeWeight - 1) / m_spongeWeight; // m_PInfinity + m_deltaPL;
15308 pressure += m_meanPressure / m_spongeWeight;
15309 /*
15310MFloat tubeLength = 4.01;
15311MFloat outletLength = 15.0;
15312MFloat outletDiameter = 1.006*2;
15313pressure+= F3B2*m_muInfinity*(tubeLength/POW3(2*m_radiusVelFlameTube))*m_VInfinity;
15314pressure+=
15315F3B2*SUTHERLANDLAW(m_burntUnburntTemperatureRatio)*(outletLength/(POW3(outletDiameter)))*m_velocityOutlet;*/
15316 }
15317 // --- Case 1 ends ---
15318
15319 // --- Case 2 ---
15320 MFloat outflowPressure = m_pressureFlameTube;
15321 MFloat outflowDensity = m_rhoFlameTube * m_targetDensityFactor;
15322 if(m_confinedFlame) {
15323 outflowPressure = m_jetPressure;
15324 // outflowDensity = m_jetDensity;
15325 }
15326 // --- Case 2 ends ---
15327
15328 values[0] = m_rhoInfinity;
15329 values[1] = pressure;
15330 values[2] = outflowDensity;
15331 values[3] = outflowPressure;
15332
15333 } else { // if(!forcing) ends here
15334
15335 // compute target pressure & density
15336 // later in computeSpongeDeltas the appropriate one is chosen depending on cellId
15337 // --- Case 1 ---
15338 MFloat pressureLoss = F0;
15339 if(m_plenum) {
15340 pressureLoss = m_rhoInfinity * POW2(m_VInfinity) * (m_inletTubeAreaRatio - F1);
15341 }
15342 // pressure loss = pressure Loss (Inlet -> flame tube) + pressure Loss (Flame surface -> Outlet)
15343 if(m_plenumWall) {
15344 pressureLoss += m_rhoFlameTube * m_targetDensityFactor
15345 * (POW2(m_velocityOutlet) - POW2(m_flameSpeed) * m_flameOutletAreaRatio);
15346 }
15347
15348 if(m_plenum) {
15349 pressure =
15350 m_PInfinity + m_rhoInfinity * POW2(m_VInfinity) * (m_burntUnburntTemperatureRatio - F1) + pressureLoss;
15351 } else {
15352 pressure =
15353 m_PInfinity + m_rhoInfinity * POW2(m_flameSpeed) * (m_burntUnburntTemperatureRatio - F1) + pressureLoss;
15354 }
15355
15356 if(m_confinedFlame) {
15357 pressure = m_PInfinity + m_deltaPL;
15358 /*
15359MFloat tubeLength = 4.01;
15360MFloat outletLength = 15.0;
15361MFloat outletDiameter = 1.006*2;
15362pressure+= F3B2*m_muInfinity*(tubeLength/POW3(2*m_radiusVelFlameTube))*m_VInfinity;
15363pressure+=
15364F3B2*SUTHERLANDLAW(m_burntUnburntTemperatureRatio)*(outletLength/(POW3(outletDiameter)))*m_velocityOutlet;
15365*/
15366 }
15367 // --- Case 1 ends ---
15368 values[0] = m_rhoInfinity;
15369 values[1] = pressure;
15370
15371 // --- Case 2 ---
15372 // rhoFlameTubem, pressureFlameTube is set to infinity values if a plenum isn't used.
15373 values[2] = m_rhoFlameTube * m_targetDensityFactor;
15374 values[3] = m_pressureFlameTube;
15375 // --- Case 2 ends ---
15376 }
15377 break;
15378 }
15379 // maybe keep these comments:
15380 // they might be useful if somebody needs the above kind of sponge for a testcase but encounters some problems...
15381 // the below case numbers were very similar to the above one and weren't used in any testcases but they might
15382 // include solutions to some problems therefore keep this information here so that somebody who encounters a
15383 // problem with the above sponge can have a look at the SVN for the below case numbers
15384 // ---
15385 // case 17513
15386 // case 17516
15387 // case 17517
15388 // forced response velocity profile, forcing via sponge layer, without forcing u velocity to zero, otherwise
15389 // divergence generates pressure jump at the end of the sponge layer
15390 // case 1751500: {
15391 // using mean pressure at the outflow boundary
15392 // case 17515000: {
15393 // forced response velocity profile, forcing via sponge layer
15394 // case 175150: {
15395 // DL time dependent
15396 // case 19900: {
15397
15398 // end of "2D cases"
15399 } // end of switch
15400 return values;
15401}
15402
15403template <MInt nDim_, class SysEqn>
15404std::array<MFloat, nDim_ + 2>
15405FvCartesianSolverXD<nDim_, SysEqn>::computeSpongeDeltas(const MInt cellId, array<MFloat, 6> value) {
15406 TRACE();
15407 using PVars = std::array<MFloat, nDim + 2>;
15408 using VelA = std::array<MFloat, nDim>;
15409
15410 VelA VVInfinity;
15411 VelA noVelocitySponge;
15412 MFloat noDensitySponge = a_pvariable(cellId, PV->RHO);
15413 MFloat noPressureSponge = a_pvariable(cellId, PV->P);
15414 // MFloat noViscositySponge=a_pvariable(cellId, PV->N);
15415
15416 for(MInt d = 0; d < nDim; ++d) {
15417 VVInfinity[d] = m_VVInfinity[d];
15418 }
15419 for(MInt d = 0; d < nDim; ++d) {
15420 noVelocitySponge[d] = a_pvariable(cellId, PV->VV[d]);
15421 }
15422 auto pJet = [&] { return m_jet ? m_jetPressure : m_PInfinity; };
15423 auto rhoJet = [&] { return m_jet ? m_jetDensity : m_rhoInfinity; };
15424 auto from_target = [&](MFloat targetRho, VelA targetU, MFloat targetP) {
15425 PVars dPV;
15426 dPV[PV->RHO] = a_pvariable(cellId, PV->RHO) - targetRho;
15427 for(MInt d = 0; d < nDim; ++d) {
15428 dPV[PV->VV[d]] = (a_pvariable(cellId, PV->VV[d]) - targetU[d]) * targetRho;
15429 }
15430 IF_CONSTEXPR(isDetChem<SysEqn>) {
15431 const MFloat* const pvarsCell = &a_pvariable(cellId, 0);
15432 std::vector<MFloat> targetPV;
15433 targetPV.resize(nDim + 2 + PV->m_noSpecies);
15434 targetPV[PV->RHO] = targetRho;
15435 targetPV[PV->P] = targetP;
15436 for(MInt d = 0; d < nDim; ++d) {
15437 targetPV[PV->VV[d]] = targetU[d];
15438 }
15439 for(MInt s = 0; s < m_noSpecies; ++s) {
15440 targetPV[PV->Y[s]] = pvarsCell[PV->Y[s]];
15441 }
15442 MFloat sensibleEnergy = F0;
15443 sysEqn().evaluateSensibleEnergy(sensibleEnergy, pvarsCell, a_avariable(cellId, AV->W_MEAN));
15444
15445 MFloat targetSensibleEnergy = F0;
15446 sysEqn().evaluateSensibleEnergy(targetSensibleEnergy, &targetPV[0], a_avariable(cellId, AV->W_MEAN));
15447
15448 dPV[PV->P] = (sensibleEnergy - targetSensibleEnergy) * targetRho;
15449 }
15450 else {
15451 dPV[PV->P] = sysEqn().pressureEnergy(a_pvariable(cellId, PV->P) - targetP);
15452 }
15453 return dPV;
15454 };
15455 auto targetVelocityU = [&]() {
15456 MFloat velocityU = a_oldVariable(cellId, CV->RHO_VV[0]) * (m_spongeWeight - 1) / m_spongeWeight;
15457 velocityU /= a_oldVariable(cellId, CV->RHO);
15458 velocityU += a_variable(cellId, CV->RHO_VV[0]) / (a_variable(cellId, CV->RHO) * m_spongeWeight);
15459 return velocityU;
15460 };
15461 auto targetVelocityV = [&]() {
15462 MFloat velocityV = a_oldVariable(cellId, CV->RHO_VV[1]) * (m_spongeWeight - 1) / m_spongeWeight;
15463 velocityV /= a_oldVariable(cellId, CV->RHO);
15464 // why is this not in here as well?
15465 // velocityV += a_variable(cellId, CV->RHO_VV[0]) / (a_variable(cellId, CV->RHO) *
15466 // m_spongeWeight);
15467 return velocityV;
15468 };
15469 auto targetVelocityW = [&]() {
15470 MFloat velocityW = a_oldVariable(cellId, CV->RHO_VV[2]) * (m_spongeWeight - 1) / m_spongeWeight;
15471 velocityW /= a_oldVariable(cellId, CV->RHO);
15472 velocityW += a_variable(cellId, CV->RHO_VV[2]) / (a_variable(cellId, CV->RHO) * m_spongeWeight);
15473 return velocityW;
15474 };
15475
15483
15484 switch(m_spongeLayerType) {
15485 case 0: {
15490 return from_target(m_rhoInfinity, noVelocitySponge, m_PInfinity);
15491 }
15492 case 1: {
15497 PVars dPVtmp;
15498 dPVtmp = from_target(noDensitySponge, noVelocitySponge, m_PInfinity);
15499 dPVtmp[PV->RHO] = a_pvariable(cellId, PV->RHO)
15500 * ((a_pvariable(cellId, PV->P) + dPVtmp[PV->P]) / a_pvariable(cellId, PV->P) - 1);
15501 return dPVtmp;
15502 }
15503 case 3: {
15508 PVars dPVtmp;
15509 dPVtmp = from_target(m_rhoInfinity * m_targetDensityFactor, noVelocitySponge, m_PInfinity);
15510 for(MInt d = 0; d < nDim; ++d) {
15511 dPVtmp[PV->VV[d]] = a_pvariable(cellId, PV->VV[d]);
15512 }
15513 return dPVtmp;
15514 }
15515
15516 case 5: {
15518
15519 PVars dPVtmp;
15520 dPVtmp = from_target(noDensitySponge, noVelocitySponge, value[1]);
15521 return dPVtmp;
15522 }
15523 case 6: {
15528 PVars dPVtmp;
15529 // if ( a_coordinate(cellId, 0) > 1.0 ) {
15530 // dPVtmp=from_target( value[0],
15531 // noVelocitySponge,
15532 // value[1]);
15533 // } else {
15534 dPVtmp = from_target(value[0], noVelocitySponge, value[1]);
15535 // }
15536 return dPVtmp;
15537 }
15538
15539 case 66: {
15540 PVars dPVtmp;
15541 dPVtmp = from_target(noDensitySponge, noVelocitySponge, value[1]);
15542 return dPVtmp;
15543 }
15544
15545 // Sponge layer for STG forcing
15546 case 77: {
15548 PVars dPVtmp;
15549 dPVtmp = from_target(noDensitySponge, noVelocitySponge, noPressureSponge);
15550
15551 if(m_STGSponge) {
15552 MFloat halfCellLength = grid().halfCellLength(cellId);
15553 MBool apply = false;
15554 if(globalTimeStep >= m_stgSpongeTimeStep) {
15555 for(MInt b = 0; b < m_noStgSpongePositions; b++) {
15556 if(abs(a_coordinate(cellId, 0) - m_stgSpongePositions[b]) < 4 * halfCellLength) {
15557 apply = true;
15558 }
15559 }
15560 }
15561
15562 if(apply) {
15563 // Streamwise velocity cannot be negative
15564 if(a_pvariable(cellId, sysEqn().PV->U) > F0) {
15565 MFloat u_delta = m_STGSpongeFactor[0][cellId];
15566 MFloat rho = a_pvariable(cellId, sysEqn().PV->RHO);
15567 MFloat r = m_STGSpongeFactor[nDim + 1][cellId];
15568 dPVtmp[sysEqn().PV->U] = r * u_delta * rho;
15569 }
15570 }
15571 }
15572
15573 // dPVtmp = from_target(noDensitySponge, velocitySponge, noPressureSponge);
15574 return dPVtmp;
15575 }
15576
15577 // FAN --> Alexej Pogorelov
15578 case 41: {
15580 const MFloat phi_mid = 74.9355804414;
15581 // const MFloat targetU = cos(phi_mid / 180.0 * PI) * m_UInfinity * 1.2539184953;
15582 PVars dPVtmp = from_target(m_rhoInfinity, noVelocitySponge,
15583 a_coordinate(cellId, 0) > c_cellLengthAtLevel(2) ? value[1] : m_PInfinity);
15584 if(a_coordinate(cellId, 0) > c_cellLengthAtLevel(2))
15585 dPVtmp[PV->U] = a_pvariable(cellId, PV->RHO) * a_pvariable(cellId, PV->U)
15586 - cos(phi_mid / 180.0 * PI) * m_UInfinity * m_rhoInfinity * 1.2539184953;
15587 return dPVtmp;
15588 }
15589
15590 // TODO labels:FV The sponge implementation in case 47 is hardcoded, but this cannot be removed from the code
15591 // since the testcase FV/3D_engine_SUZI_parallel uses this value. Either the test case needs to be modified
15592 // or the sponge implementation for case 47 needs to be generalized.
15593 case 47: {
15597 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
15598 break;
15599 }
15600 if(a_hasProperty(cellId, SolverCell::IsInvalid)) {
15601 break;
15602 }
15603 if(!a_hasProperty(cellId, SolverCell::IsActive)) {
15604 break;
15605 }
15606 updateSpongeLayerRhs(
15607 cellId,
15608 from_target((!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 2) < -50.0) ? value[0] : noDensitySponge,
15609 noVelocitySponge,
15610 (!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 2) < -50.0) ? value[1] : noPressureSponge));
15611 updateSpongeLayerRhs(
15612 cellId,
15613 from_target((!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 0) > 60.0 && a_coordinate(cellId, 1) > 0.0)
15614 ? value[2]
15615 : noDensitySponge,
15616 noVelocitySponge,
15617 (!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 0) > 60.0 && a_coordinate(cellId, 1) > 0.0)
15618 ? value[3]
15619 : noPressureSponge));
15620 return from_target(
15621 (!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 0) > 60.0 && a_coordinate(cellId, 1) < 0.0)
15622 ? value[4]
15623 : noDensitySponge,
15624 noVelocitySponge,
15625 (!a_isBndryGhostCell(cellId) && a_coordinate(cellId, 0) > 60.0 && a_coordinate(cellId, 1) < 0.0)
15626 ? value[5]
15627 : noPressureSponge);
15628 }
15629
15630 case 446: {
15635 IF_CONSTEXPR(!hasE<SysEqn>)
15636 mTerm(1, AT_, "Not compatible with SysEqn without RHO_E!");
15637 MFloat U2 = 0.0;
15638 PVars dPVtmp;
15639
15640 for(MInt d = 0; d < nDim; ++d) {
15641 U2 += POW2(a_pvariable(cellId, PV->VV[d]));
15642 }
15643 dPVtmp = from_target(noDensitySponge, noVelocitySponge, noPressureSponge);
15644 dPVtmp[PV->P] =
15645 a_variable(cellId, CV->RHO_E) - sysEqn().internalEnergy(m_PInfinity, a_variable(cellId, CV->RHO), U2);
15646 return dPVtmp;
15647 }
15648
15649 // (dimensional)
15650 case 11212: {
15655 return from_target(noDensitySponge, noVelocitySponge, m_PInfinity);
15656 }
15657
15658 // (dimensional)
15659 case 11213: {
15661 const MInt oneDGridSize = m_oneDimFlame->m_grid.size();
15662 VelA forcedVelocity;
15663 MInt mainAxis = 0;
15664 for(MInt dim = 0; dim < nDim; dim++)
15665 forcedVelocity[dim] = (dim == mainAxis) ? m_oneDimFlame->m_profile.velocity[oneDGridSize - 1] : F0;
15666
15667 return from_target(noDensitySponge, forcedVelocity, m_PInfinity);
15668 }
15669
15670 // (dimensional)
15671 case 11214: {
15673 const MInt oneDGridSize = m_oneDimFlame->m_grid.size();
15674
15675 MFloat FmeanMolarMassBurnt = F0;
15676 for(MUint s = 0; s < PV->m_noSpecies; ++s) {
15677 FmeanMolarMassBurnt +=
15678 m_oneDimFlame->m_profile.massFractions[m_noSpecies * (oneDGridSize - 1) + s] * m_fMolarMass[s];
15679 }
15680
15681 const MFloat temperatureInfinityBurnt = m_oneDimFlame->m_profile.temperature[oneDGridSize - 1];
15682 const MFloat meanMolarMassBurnt = F1 / FmeanMolarMassBurnt;
15683
15684 const MFloat rhoInfinityBurnt = m_PInfinity * meanMolarMassBurnt / (temperatureInfinityBurnt * m_gasConstant);
15685
15686 const MFloat spongeRho = a_coordinate(cellId, 1) < 0 ? m_rhoInfinity : rhoInfinityBurnt;
15687
15688 VelA targetV;
15689 targetV[0] = F0;
15690 targetV[1] = m_VInfinity;
15691 IF_CONSTEXPR(nDim == 3) targetV[1] = F0;
15692 if(a_coordinate(cellId, 1) < 0) {
15693 return from_target(spongeRho, targetV, noPressureSponge);
15694 } else {
15695 return from_target(noDensitySponge, noVelocitySponge, m_PInfinity);
15696 }
15697 }
15698
15699 case 51: {
15701
15702 // ALLGEMEINER SPONGE MIT MITTELUNG
15703 IF_CONSTEXPR(nDim == 2) mTerm(-1, "Info: This sponge layer type only works in 3D.");
15704
15705 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) break;
15706 if(a_hasProperty(cellId, SolverCell::IsInvalid)) break;
15707 if(!a_hasProperty(cellId, SolverCell::IsActive)) break;
15708 if(a_isBndryGhostCell(cellId)) break;
15709
15710 constexpr MFloat directionSign[6] = {1.0, -1.0, 1.0, -1.0, 1.0, -1.0};
15711 constexpr MInt directionDim[6] = {0, 0, 1, 1, 2, 2};
15712 const MFloat Pdiff = m_deltaPL;
15713 MFloat fac = 1.0;
15714 if(m_time < m_timeOfMaxPdiff) fac = (m_time / m_timeOfMaxPdiff);
15715 const MFloat finalPressure = m_PInfinity - Pdiff;
15716 const MFloat initialPressure = sysEqn().p_Ref() - Pdiff;
15717 const MFloat deltaPressure = finalPressure - initialPressure;
15718 static constexpr MInt noRSteps = 20;
15719 const MFloat R = 2.0;
15720 const MFloat rDiff = R / noRSteps;
15721 PVars dPVtmp;
15722 dPVtmp[PV->P] = noPressureSponge;
15723 dPVtmp[PV->RHO] = noDensitySponge;
15724 std::copy_n(&dPVtmp[0], nDim, &noVelocitySponge[0]);
15725
15726 for(MInt i = 0; i < m_noSpongeZonesIn; i++) {
15727 if((a_coordinate(cellId, directionDim[m_spongeDirectionsIn[i]]) - m_coordSpongeIn[i])
15728 * directionSign[m_spongeDirectionsIn[i]]
15729 < F0
15730 && (a_coordinate(cellId, directionDim[m_secondSpongeDirectionsIn[i]]) - m_secondCoordSpongeIn[i])
15731 * directionSign[m_secondSpongeDirectionsIn[i]]
15732 < F0) {
15733 // suboptimal to recompute for each cell again, but that is how it is now
15734 const MFloat pressureIn = value[i];
15735 const MFloat densityIn = sysEqn().density_IR_P(pressureIn);
15736 dPVtmp[PV->P] += sysEqn().pressureEnergy(a_pvariable(cellId, PV->P) - pressureIn);
15737 dPVtmp[PV->RHO] += a_pvariable(cellId, PV->RHO) - densityIn;
15738 }
15739 }
15740 for(MInt i = 0; i < m_noSpongeZonesOut; i++) {
15741 if((a_coordinate(cellId, directionDim[m_spongeDirectionsOut[i]]) - m_coordSpongeOut[i])
15742 * directionSign[m_spongeDirectionsOut[i]]
15743 < F0
15744 && (a_coordinate(cellId, directionDim[m_secondSpongeDirectionsOut[i]]) - m_secondCoordSpongeOut[i])
15745 * directionSign[m_secondSpongeDirectionsOut[i]]
15746 < F0) {
15747 // suboptimal to recompute for each cell again, but that is how it is now
15748 const MFloat pressureOut = (initialPressure + fac * deltaPressure);
15749 const MFloat densityOut = sysEqn().density_IR_P(pressureOut);
15750
15751 dPVtmp[PV->P] += sysEqn().pressureEnergy(a_pvariable(cellId, PV->P) - pressureOut);
15752 dPVtmp[PV->RHO] += a_pvariable(cellId, PV->RHO) - densityOut;
15753
15754 for(MInt dimId = 0; dimId < nDim; dimId++)
15755 dPVtmp[PV->VV[dimId]] += a_pvariable(cellId, PV->VV[dimId]);
15756
15757 const MFloat r = sqrt(POW2(a_coordinate(cellId, 1)) + POW2(a_coordinate(cellId, 2)));
15758 const MInt rIndex = (MInt)((R - r) / rDiff);
15759 dPVtmp[PV->VV[0]] -= m_uNormal_r[rIndex];
15760 }
15761 }
15762 return dPVtmp;
15763 }
15764
15765 case 100: {
15767 VelA VV;
15768 MFloat spongeDistanceFactor = F1;
15769 PVars tmpVars;
15770 if(m_velocitySponge) {
15771 VV[0] = targetVelocityU();
15772 VV[1] = targetVelocityV();
15773 VV[2] = targetVelocityW();
15774 if(a_variable(cellId, CV->RHO_VV[1]) < 0) {
15775 spongeDistanceFactor = F2;
15776 VV[1] += m_VInfinity / m_spongeWeight;
15777 } else {
15778 VV[1] += a_variable(cellId, CV->RHO_VV[1]) / (a_variable(cellId, CV->RHO) * m_spongeWeight);
15779 }
15780 } else {
15781 VV = noVelocitySponge;
15782 }
15783 tmpVars = from_target(rhoJet(),
15784 VV,
15785 (a_coordinate(cellId, 1) < m_yOffsetFlameTube - 0.5) ? rhoJet()
15786 : rhoJet() * m_targetDensityFactor);
15787 tmpVars[PV->VV[0]] *= spongeDistanceFactor;
15788 return tmpVars;
15789 }
15790
15791 case 333: {
15796 return from_target(noDensitySponge, VVInfinity, noPressureSponge);
15797 }
15798 case 2014: {
15803 return from_target(m_rhoInfinity, VVInfinity, m_PInfinity);
15804 }
15805 case 91900: {
15807 VelA VV;
15808 if(m_velocitySponge) {
15809 VV[0] = targetVelocityU();
15810 VV[1] = targetVelocityV();
15811 VV[2] = targetVelocityW();
15812 } else {
15813 VV = noVelocitySponge;
15814 }
15815 return from_target(
15816 (a_coordinate(cellId, 1) < m_yOffsetFlameTube - 0.5 && abs(a_coordinate(cellId, 2)) < m_jetHalfLength + 0.1)
15817 ? rhoJet()
15818 : rhoJet() * m_targetDensityFactor,
15819 VV,
15820 pJet());
15821 }
15822 case 919001: {
15826 VelA VV;
15827 if(m_velocitySponge) {
15828 VV[0] = targetVelocityU();
15829 VV[1] = targetVelocityV();
15830 VV[2] = targetVelocityW();
15831 } else {
15832 VV = noVelocitySponge;
15833 }
15834 return from_target(
15835 (a_coordinate(cellId, 1) < m_yOffsetFlameTube - 0.5 && abs(a_coordinate(cellId, 2)) < m_jetHalfLength + 0.1)
15836 ? F0
15837 : rhoJet() * m_targetDensityFactor,
15838 VV,
15839 pJet());
15840 }
15841 case 919002: {
15845 VelA VV;
15846 PVars tmpVars;
15847 if(m_velocitySponge) {
15848 VV[0] = targetVelocityU();
15849 VV[1] = targetVelocityV();
15850 VV[2] = targetVelocityW();
15851 } else {
15852 VV = noVelocitySponge;
15853 }
15854 tmpVars = from_target(
15855 (a_coordinate(cellId, 1) < m_yOffsetFlameTube - 0.5 && abs(a_coordinate(cellId, 2)) < m_jetHalfLength + 0.1)
15856 ? rhoJet()
15857 : rhoJet() * m_targetDensityFactor,
15858 VV,
15859 pJet());
15860 if(a_coordinate(cellId, 1) < m_yOffsetFlameTube - 0.5 && abs(a_coordinate(cellId, 2)) < m_jetHalfLength + 0.1) {
15861 tmpVars[PV->RHO] *= m_sigmaSpongeInflow / m_sigmaSponge;
15862 tmpVars[PV->P] *= m_sigmaSpongeInflow / m_sigmaSponge;
15863 }
15864 return tmpVars;
15865 }
15866 case 40: {
15872 return from_target(m_rhoInfinity * m_targetDensityFactor,
15873 noVelocitySponge,
15874 m_PInfinity + m_deltaP * (m_domainBoundaries[3] - a_coordinate(cellId, 1)));
15875 }
15876
15877 // Sponge for jet exiting (chevron) nozzle
15878 case 1174: {
15880 ASSERT(!a_hasProperty(cellId, SolverCell::IsInvalid), "sponge cell invalid");
15881 ASSERT(!a_isBndryGhostCell(cellId), "sponge cell is bndry ghost cell");
15882 // ASSERT(a_hasProperty(cellId, SolverCell::IsActive), "sponge cell inactive");
15883 // ASSERT(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel), "sponge cell not on current mg level");
15884 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) break;
15885 if(!a_hasProperty(cellId, SolverCell::IsActive)) break;
15886
15887 VelA velSponge(noVelocitySponge);
15888 MFloat targetRho, targetP;
15889
15890 // TODO labels:FV variable nozzle position needs to be specified in other places as well (eg for IC, BC)
15891 const MFloat centerY = 0.0;
15892 const MFloat centerZ = 0.0;
15893 const MFloat radius = sqrt(POW2(a_coordinate(cellId, 1) - centerY) + POW2(a_coordinate(cellId, 2) - centerZ));
15894 const MFloat xpos = a_coordinate(cellId, 0);
15895 const MFloat maxInletPosX = 3.0; // TODO labels:FVMB @ansgar FIXME hard-coded position
15896 const MFloat minOutletPosX = 50.0; // TODO labels:FVMB @ansgar FIXME hard-coded position
15897
15898 if(xpos <= maxInletPosX && radius <= m_inletRadius) {
15899 const MFloat deltaMomentum = m_momentumThickness * m_inletRadius;
15900 const MFloat jet = tanh((m_inletRadius - radius) / (2.0 * deltaMomentum));
15901
15902 const MFloat density_i = value[0];
15903 targetRho = density_i / sysEqn().CroccoBusemann(m_maNozzleInlet, jet);
15904 targetP = value[1];
15905 } else {
15906 // Ambient values
15907 targetRho = value[2];
15908 targetP = value[3];
15909
15910 // Add velocity sponge for outlet bc to prevent backflow
15911 if(xpos >= minOutletPosX && a_pvariable(cellId, PV->U) < 0) {
15912 velSponge[0] = 0.0;
15913 }
15914 }
15915
15916 return from_target(targetRho, velSponge, targetP);
15917 }
15918
15919 // sponges originally from 2D solver:
15920
15921 // vortex-pair cylinder (quiescent flow prescribed)
15922 case 2: {
15927 PVars dPVtmp;
15928 dPVtmp = from_target(noDensitySponge, noVelocitySponge, m_PInfinity);
15929 dPVtmp[PV->RHO] = a_pvariable(cellId, PV->RHO)
15930 * ((a_pvariable(cellId, PV->P) + dPVtmp[PV->P]) / a_pvariable(cellId, PV->P) - 1);
15931 for(MInt d = 0; d < nDim; ++d) {
15932 dPVtmp[PV->VV[d]] = dPVtmp[PV->RHO] * a_pvariable(cellId, PV->VV[d]);
15933 }
15934 return dPVtmp;
15935 }
15936 // quiescent flow
15937 case 4: {
15942 PVars dPVtmp;
15943 dPVtmp = from_target(noDensitySponge, noVelocitySponge, noPressureSponge);
15944 dPVtmp[PV->P] = sysEqn().pressureEnergy(a_pvariable(cellId, PV->P) - sysEqn().p_Ref());
15945 dPVtmp[PV->RHO] = a_pvariable(cellId, PV->RHO) - 1.0;
15946 return dPVtmp;
15947 }
15948
15949 case 7: {
15951 PVars dPVtmp;
15952 const MFloat T2 = sysEqn().temperature_ES(m_postShockPV[PV->RHO], m_postShockPV[PV->P]);
15953 MFloat velSq = 0.0;
15954 for(MInt d = 0; d < nDim; ++d) {
15955 velSq += POW2(m_postShockPV[PV->VV[d]]);
15956 }
15957 velSq *= F1B2;
15958
15959 dPVtmp = from_target(noDensitySponge, noVelocitySponge, m_postShockPV[PV->P]);
15960 dPVtmp[PV->RHO] = (a_pvariable(cellId, PV->P) - m_postShockPV[PV->P]) / T2;
15961 dPVtmp[PV->P] = (dPVtmp[PV->P] + dPVtmp[PV->RHO] * velSq);
15962 return dPVtmp;
15963 }
15964 // backward-facing step combustor
15965 case 1930: {
15967 return from_target((a_coordinate(cellId, 0) < 0) ? m_rhoInfinity : m_rhoInfinity * m_targetDensityFactor,
15968 noVelocitySponge,
15969 m_PInfinity);
15970 }
15971 // case 1940 already exists from 3D.. but it is different from the 2D one
15972
15973 // forced response
15974 case 17511:
15976
15977 // DL instability
15978 case 1990: {
15980 MFloat pressure;
15981 pressure = m_PInfinity + m_rhoInfinity * POW2(m_flameSpeed) * (m_burntUnburntTemperatureRatio - F1);
15982 return from_target((a_coordinate(cellId, 1) < 0.0) ? m_rhoInfinity : m_rhoInfinity * m_targetDensityFactor,
15983 noVelocitySponge,
15984 (a_coordinate(cellId, 1) < 0.0) ? pressure : m_PInfinity);
15985 }
15986 case 17512:
15988
15989 case 17514: {
15991 return from_target((a_coordinate(cellId, 1) < 0.0) ? m_rhoInfinity : m_rhoInfinity * m_targetDensityFactor,
15992 noVelocitySponge,
15993 (a_coordinate(cellId, 1) < 0.0) ? value[1] : m_PInfinity);
15994 }
15995
15996 // forced response velocity profile, forcing via sponge layer
15997 case 17515: {
15999 MFloat velocity;
16000 MFloat ampl = m_forcingAmplitude;
16001 MFloat xPlus, xNegative;
16002 MFloat St = m_flameStrouhal;
16003 // MFloat neg2=-F2;
16004 // MFloat integrateFactor = m_velocityMagnitudeFactor;
16005 //---
16006
16007 PVars dPVtmp;
16008 if(!m_forcing) {
16009 // compute the forcing terms
16010 MFloat deltaV = F0;
16011 MFloat deltaU = F0;
16012 MFloat velocityU = F0;
16013
16014 if(a_spongeBndryId(cellId, 0) == 176191 || a_spongeBndryId(cellId, 1) == 176191
16015 || a_spongeBndryId(cellId, 0) == 209104 || a_spongeBndryId(cellId, 1) == 209104
16016 || a_spongeBndryId(cellId, 0) == 209101 || a_spongeBndryId(cellId, 1) == 209101
16017 || a_spongeBndryId(cellId, 0) == 17616 || a_spongeBndryId(cellId, 1) == 17616
16018 || a_spongeBndryId(cellId, 0) == 3906 || a_spongeBndryId(cellId, 1) == 3906
16019 || a_spongeBndryId(cellId, 0) == 39060 || a_spongeBndryId(cellId, 1) == 39060
16020 || a_spongeBndryId(cellId, 0) == 209102
16021 || a_spongeBndryId(cellId, 1) == 209102) { // a_coordinate( cellId , 1 ) < m_yOffsetFlameTube ) {
16022
16023 const MFloat density = value[0];
16024 const MFloat pressure = value[1];
16025
16026 dPVtmp[PV->RHO] = a_pvariable(cellId, PV->RHO) - density;
16027 dPVtmp[PV->P] = sysEqn().pressureEnergy(a_pvariable(cellId, PV->P) - pressure);
16028
16029 xPlus = a_coordinate(cellId, 0) + m_radiusVelFlameTube;
16030 xNegative = a_coordinate(cellId, 0) - m_radiusVelFlameTube;
16031
16032 velocity =
16033 m_VInfinity
16034 * (F1B2 * (F1 + tanh(xPlus * m_shearLayerStrength)) * (F1 - tanh(xNegative * m_shearLayerStrength)) - F1);
16035
16036 // velocity = m_VInfinity*(tanh(5.0)-F1B2*tanh(5.0) + F1B2*tanh((neg2*xNegative -
16037 // 0.05)*5.0/0.05))*(tanh(5.0)-F1B2*tanh(5.0) + F1B2*tanh((F2*xPlus - 0.05)*5.0/0.05)); velocity =
16038 // F1B4*(1+tanh(xPlus*100.0))*(1-tanh(xNegative*100.0))*m_VInfinity;//*integrateFactor;
16039
16040 if(!m_specialSpongeTreatment) {
16041 deltaV = (a_pvariable(cellId, PV->VV[1]) - velocity) * m_rhoInfinity;
16042 deltaU = (a_pvariable(cellId, PV->VV[0]) - velocityU) * m_rhoInfinity;
16043 } else {
16044 a_variable(cellId, CV->RHO_V) = velocity * m_rhoInfinity;
16045 a_variable(cellId, CV->RHO_U) = F0;
16046 }
16047
16048 // outflow sponge layer
16049 } else {
16050 const MFloat outflowDensity = value[2];
16051 const MFloat outflowPressure = value[3];
16052
16053 dPVtmp[PV->RHO] = a_pvariable(cellId, PV->RHO) - outflowDensity;
16054 dPVtmp[PV->P] = sysEqn().pressureEnergy(a_pvariable(cellId, PV->P) - outflowPressure);
16055 deltaU = 0;
16056 deltaV = 0;
16057
16058 if(m_velocitySponge && (a_spongeBndryId(cellId, 0) == 1763 || a_spongeBndryId(cellId, 1) == 1763)) {
16059 velocity = a_oldVariable(cellId, CV->RHO_VV[1]) * (m_spongeWeight - 1) / m_spongeWeight;
16060 velocity /= a_oldVariable(cellId, CV->RHO);
16061 velocity += a_variable(cellId, CV->RHO_VV[1]) / (a_variable(cellId, CV->RHO) * m_spongeWeight);
16062
16063 velocityU = a_oldVariable(cellId, CV->RHO_VV[0]) * (m_spongeWeight - 1) / m_spongeWeight;
16064 velocityU /= a_oldVariable(cellId, CV->RHO);
16065 velocityU += a_variable(cellId, CV->RHO_VV[0]) / (a_variable(cellId, CV->RHO) * m_spongeWeight);
16066
16067 deltaV = (a_pvariable(cellId, PV->VV[1]) - velocity) * m_rhoInfinity;
16068 deltaU = (a_pvariable(cellId, PV->VV[0]) - velocityU) * m_rhoInfinity;
16069 }
16070 }
16071
16072 dPVtmp[PV->U] = deltaU * (m_velocitySponge + (!m_specialSpongeTreatment) * m_spongeReductionFactor);
16073 dPVtmp[PV->V] = deltaV * (m_velocitySponge + (!m_specialSpongeTreatment) * m_spongeReductionFactor);
16074
16075 } else { // if(!forcing) ends here
16076
16077 // compute the forcing terms
16078 // ...for the pressure
16079 // ...for the density
16080 MFloat deltaV = F0;
16081 MFloat deltaU = F0;
16082 MFloat velocityU = F0;
16083
16084 if((a_spongeBndryId(cellId, 0) == 17616 || a_spongeBndryId(cellId, 1) == 17616)
16085 || (a_spongeBndryId(cellId, 0) == 176191 || a_spongeBndryId(cellId, 1) == 176191)
16086 || (a_spongeBndryId(cellId, 0) == 209102 || a_spongeBndryId(cellId, 1) == 209102)
16087 || (a_spongeBndryId(cellId, 0) == 209101 || a_spongeBndryId(cellId, 1) == 209101)
16088 || (a_spongeBndryId(cellId, 0) == 209104
16089 || a_spongeBndryId(cellId, 1) == 209104)) { // a_coordinate( cellId , 1 ) < m_yOffsetFlameTube ) {
16090
16091 const MFloat density = value[0];
16092 const MFloat pressure = value[1];
16093
16094 dPVtmp[PV->RHO] = a_pvariable(cellId, PV->RHO) - density;
16095 dPVtmp[PV->P] = sysEqn().pressureEnergy(a_pvariable(cellId, PV->P) - pressure);
16096
16097 xPlus = a_coordinate(cellId, 0) + m_radiusVelFlameTube;
16098 xNegative = a_coordinate(cellId, 0) - m_radiusVelFlameTube;
16099
16100 velocity =
16101 m_VInfinity
16102 * (F1B2 * (F1 + tanh(xPlus * m_shearLayerStrength)) * (F1 - tanh(xNegative * m_shearLayerStrength)) - F1);
16103
16104 velocity *= (F1 + ampl * sin(St * m_time));
16105
16106 // velocity = m_VInfinity*(tanh(5.0)-F1B2*tanh(5.0) + F1B2*tanh((neg2*xNegative -
16107 // 0.05)*5.0/0.05))*(tanh(5.0)-F1B2*tanh(5.0) + F1B2*tanh((F2*xPlus - 0.05)*5.0/0.05));
16108
16109 // velocity = F1B4*(1+tanh(xPlus*100.0))*(1-tanh(xNegative*100.0))*m_VInfinity*( F1 + ampl * sin( St * m_time
16110 // ));//*integrateFactor;
16111
16112 if(!m_specialSpongeTreatment) {
16113 deltaV = (a_pvariable(cellId, PV->VV[1]) - velocity) * m_rhoInfinity;
16114 deltaU = (a_pvariable(cellId, PV->VV[0]) - velocityU) * m_rhoInfinity;
16115 } else {
16116 a_variable(cellId, CV->RHO_V) = velocity * m_rhoInfinity;
16117 a_variable(cellId, CV->RHO_U) = F0;
16118 }
16119
16120 // outflow sponge layer
16121 } else {
16122 const MFloat outflowDensity = value[2];
16123 const MFloat outflowPressure = value[3];
16124
16125 dPVtmp[PV->RHO] = a_pvariable(cellId, PV->RHO) - outflowDensity;
16126 dPVtmp[PV->P] = sysEqn().pressureEnergy(a_pvariable(cellId, PV->P) - outflowPressure);
16127 deltaV = F0;
16128 deltaU = F0;
16129 if(m_velocitySponge && (a_spongeBndryId(cellId, 0) == 1763 || a_spongeBndryId(cellId, 1) == 1763)) {
16130 velocity = a_oldVariable(cellId, CV->RHO_VV[1]) * (m_spongeWeight - 1) / m_spongeWeight;
16131 velocity /= a_oldVariable(cellId, CV->RHO);
16132 velocity += a_variable(cellId, CV->RHO_VV[1]) / (a_variable(cellId, CV->RHO) * m_spongeWeight);
16133
16134 velocityU = a_oldVariable(cellId, CV->RHO_VV[0]) * (m_spongeWeight - 1) / m_spongeWeight;
16135 velocityU /= a_oldVariable(cellId, CV->RHO);
16136 velocityU += a_variable(cellId, CV->RHO_VV[0]) / (a_variable(cellId, CV->RHO) * m_spongeWeight);
16137
16138 deltaV = (a_pvariable(cellId, PV->VV[1]) - velocity) * m_rhoInfinity;
16139 deltaU = (a_pvariable(cellId, PV->VV[0]) - velocityU) * m_rhoInfinity;
16140 }
16141 }
16142
16143 dPVtmp[PV->U] = deltaU * (m_velocitySponge + (!m_specialSpongeTreatment) * m_spongeReductionFactor);
16144 dPVtmp[PV->V] = deltaV * (m_velocitySponge + (!m_specialSpongeTreatment) * m_spongeReductionFactor);
16145 }
16146 return dPVtmp;
16147 }
16148 // end of "2D sponges"
16149
16150
16151 default: {
16152 mTerm(1, AT_,
16153 "FvCartesianSolverXD::computeSpongeDeltas() switch variable 'm_spongeLayerType' not matching any "
16154 "case");
16155 }
16156 } // end of switch
16157 return from_target(noDensitySponge, noVelocitySponge, noPressureSponge);
16158}
16159
16160
16161template <MInt nDim_, class SysEqn>
16162void FvCartesianSolverXD<nDim_, SysEqn>::updateSpongeLayerRhs(const MInt cellId, array<MFloat, nDim_ + 2> dPV) {
16163 TRACE();
16164
16165 // update rhs RHO_E, RHO, RHO_V, RHO_U, RHO_W, RHO_Y
16166 IF_CONSTEXPR(hasE<SysEqn>)
16167 a_rightHandSide(cellId, CV->RHO_E) += a_spongeFactor(cellId) * dPV[PV->P] * a_cellVolume(cellId);
16168 a_rightHandSide(cellId, CV->RHO) += a_spongeFactor(cellId) * dPV[PV->RHO] * a_cellVolume(cellId);
16169 for(MInt d = 0; d < nDim; ++d) {
16170 a_rightHandSide(cellId, CV->RHO_VV[d]) += a_spongeFactor(cellId) * dPV[PV->VV[d]] * a_cellVolume(cellId);
16171 }
16172
16173 // IF_CONSTEXPR(SysEqn::m_noRansEquations > 0){
16174 // for(MInt r = 0; r < m_noRansEquations; ++r) {
16175 // a_rightHandSide(cellId, CV->RHO_NN[r]) +=
16176 // a_spongeFactor(cellId)*dPV[PV->RHO]*a_cellVolume(cellId);
16177 // }
16178 // }
16179
16180 // species
16181 for(MInt s = 0; s < m_noSpecies; s++) {
16182 a_rightHandSide(cellId, CV->RHO_Y[s]) +=
16183 a_spongeFactor(cellId) * dPV[PV->RHO] * a_cellVolume(cellId) * a_pvariable(cellId, PV->Y[s]);
16184 }
16185}
16186
16187
16188// --------------------------------------------------------------------------------------
16189
16190
16193template <MInt nDim_, class SysEqn>
16195 TRACE();
16196
16197 MInt noDirs = 2 * nDim;
16198 MFloat halfCellWidth;
16199 MFloat epsilon = c_cellLengthAtLevel(maxRefinementLevel()) / 1000.0;
16200 MFloatScratchSpace tmp(nDim, AT_, "tmp");
16201 MFloatScratchSpace tmp2(nDim, AT_, "tmp2");
16202 //---
16203
16204 // compute domain dimensions
16205 halfCellWidth = F1B2 * c_cellLengthAtCell(0);
16206 for(MInt i = 0; i < nDim; i++) {
16207 m_domainBoundaries[2 * i] = a_coordinate(0, i) - halfCellWidth;
16208 m_domainBoundaries[2 * i + 1] = a_coordinate(0, i) + halfCellWidth;
16209 }
16210 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
16211 if(c_noChildren(cellId) > 0) continue;
16212 halfCellWidth = F1B2 * c_cellLengthAtCell(cellId);
16213 for(MInt i = 0; i < nDim; i++) {
16214 m_domainBoundaries[2 * i] = mMin(m_domainBoundaries[2 * i], a_coordinate(cellId, i) - halfCellWidth);
16215 m_domainBoundaries[2 * i + 1] = mMax(m_domainBoundaries[2 * i + 1], a_coordinate(cellId, i) + halfCellWidth);
16216 }
16217 }
16218 // exchange domain boundaries
16219 // maximum dimensions
16220 for(MInt i = 0; i < nDim; i++)
16221 tmp.p[i] = m_domainBoundaries[2 * i + 1];
16222 MPI_Reduce(tmp.getPointer(), tmp2.getPointer(), nDim, MPI_DOUBLE, MPI_MAX, 0, mpiComm(), AT_, "tmp.getPointer()",
16223 "tmp2.getPointer()");
16224 MPI_Bcast(tmp2.getPointer(), nDim, MPI_DOUBLE, 0, mpiComm(), AT_, "tmp2.getPointer()");
16225 for(MInt i = 0; i < nDim; i++)
16226 m_domainBoundaries[2 * i + 1] = tmp2.p[i];
16227 // minimum dimensions
16228 for(MInt i = 0; i < nDim; i++)
16229 tmp.p[i] = m_domainBoundaries[2 * i];
16230 MPI_Reduce(tmp.getPointer(), tmp2.getPointer(), nDim, MPI_DOUBLE, MPI_MIN, 0, mpiComm(), AT_, "tmp.getPointer()",
16231 "tmp2.getPointer()");
16232 MPI_Bcast(tmp2.getPointer(), nDim, MPI_DOUBLE, 0, mpiComm(), AT_, "tmp2.getPointer()");
16233 for(MInt i = 0; i < nDim; i++)
16234 m_domainBoundaries[2 * i] = tmp2.p[i];
16235
16236 // compute the mean coordinate ([2] is set for the 2D-version)
16237 m_meanCoord[2] = F0;
16238 m_fvBndryCnd->m_meanCoord[2] = m_meanCoord[2];
16239 for(MInt i = 0; i < nDim; i++) {
16240 m_meanCoord[i] = F1B2 * (m_domainBoundaries[2 * i] + m_domainBoundaries[2 * i + 1]);
16241 m_fvBndryCnd->m_meanCoord[i] = m_meanCoord[i];
16242 }
16243
16244 if(m_spongeLayerThickness > F0) {
16245 if(!m_createSpongeBoundary) {
16246 // compute sponge zone dimensions
16247 for(MInt i = 0; i < nDim; i++) {
16248 m_spongeCoord[2 * i] = m_domainBoundaries[2 * i] + m_spongeLayerThickness * m_spongeFactor[2 * i];
16249 m_spongeCoord[noDirs + 2 * i] = F1 / mMax(epsilon, m_spongeLayerThickness * m_spongeFactor[2 * i]);
16250 m_spongeCoord[2 * i + 1] = m_domainBoundaries[2 * i + 1] - m_spongeLayerThickness * m_spongeFactor[2 * i + 1];
16251 m_spongeCoord[noDirs + 2 * i + 1] = F1 / (mMax(epsilon, m_spongeLayerThickness * m_spongeFactor[2 * i + 1]));
16252 }
16253 }
16254 }
16255
16256 m_log << "*** boundaries of the computational domain " << endl;
16257 m_log << " direction " << endl;
16258 for(MInt i = 0; i < nDim; i++) {
16259 m_log << "min " << i << " " << m_domainBoundaries[2 * i] << endl;
16260 m_log << "max " << i << " " << m_domainBoundaries[2 * i + 1] << endl;
16261 m_log << "mean " << i << " " << m_meanCoord[i] << endl;
16262 }
16263}
16264
16265
16266// ----------------------------------------------------------------------------
16267
16268
16269// ----------------------------------------------------------------------------
16270// ****************** Small cells *********************************************
16271// ----------------------------------------------------------------------------
16272
16273
16280template <MInt nDim_, class SysEqn>
16282 TRACE();
16283
16284 const MInt noSmallCells = m_fvBndryCnd->m_smallBndryCells->size();
16285 const MInt noVarIds = FV->noVariables;
16286 //---
16287
16288#ifdef _OPENMP
16289#pragma omp parallel for collapse(2)
16290#endif
16291 for(MInt s = 0; s < noSmallCells; s++) {
16292 for(MInt varId = 0; varId < noVarIds; varId++) {
16293 a_rightHandSide(m_masterCellIds[s], varId) += a_rightHandSide(m_smallCellIds[s], varId);
16294 a_rightHandSide(m_smallCellIds[s], varId) = F0;
16295 }
16296 }
16297}
16298
16299
16300// ----------------------------------------------------------------------------
16301// ****************** Output / restart ****************************************
16302// ----------------------------------------------------------------------------
16303
16304
16316template <MInt nDim_, class SysEqn>
16317void FvCartesianSolverXD<nDim_, SysEqn>::saveSolverSolution(const MBool forceOutput, const MBool finalTimeStep) {
16318 TRACE();
16319 std::ignore = finalTimeStep;
16320 // the following preprocessor statement triggers a more detailed output
16321 // might lead to memory issues as a new array is allocated.
16322 // better only use for debug reasons (\author: Claudia)
16323 //#define _DET_OUT
16324 // Return if this is not the primary solver in a multilevel computation
16325 if(isMultilevel() && !isMultilevelPrimary()) {
16326 return;
16327 }
16328
16329 MInt offset = m_solutionOffset;
16330 MInt rank = domainId();
16331 stringstream gridFileName;
16332#ifdef _DET_OUT
16333 MIntScratchSpace MS_Ids(m_fvBndryCnd->m_bndryCells->size(), AT_, "MS_Ids");
16334 cerr << "detailed Output!" << endl;
16335#endif
16336
16337 //---
16338
16339
16341 /* minimum and maximum wall vorticity */
16343 if(m_recordWallVorticity) {
16344 FILE* datei;
16345 MInt cellId, bndryId, ghostCellId;
16346 MFloat vorticity;
16347 MFloat minimumWallVorticity = 10000.;
16348 MFloat maximumWallVorticity = -10000.;
16349
16350 datei = fopen("wallVorticity", "a+");
16351 fprintf(datei, "%d", globalTimeStep);
16352 fprintf(datei, " %f", m_physicalTime);
16353 fprintf(datei, " %f", m_time);
16354
16355 for(MInt bcId = 0; bcId < m_fvBndryCnd->m_noBndryCndIds; bcId++) {
16356 if(m_fvBndryCnd->m_bndryCndIds[bcId] != 3006) continue;
16357 for(MInt id = m_fvBndryCnd->m_bndryCndCells[bcId]; id < m_fvBndryCnd->m_bndryCndCells[bcId + 1]; id++) {
16358 bndryId = m_fvBndryCnd->m_sortedBndryCells->a[id];
16359 cellId = m_bndryCells->a[bndryId].m_cellId;
16360 if(m_bndryCells->a[bndryId].m_linkedCellId > -1)
16361 if(a_bndryId(m_bndryCells->a[bndryId].m_linkedCellId) == -1) cellId = m_bndryCells->a[bndryId].m_linkedCellId;
16362 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
16363 ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[0]->m_ghostCellId;
16364
16365 vorticity = F1B4
16366 * (a_slope(cellId, PV->V, 0) + a_slope(ghostCellId, PV->V, 0) - a_slope(cellId, PV->U, 1)
16367 - a_slope(ghostCellId, PV->U, 1));
16368 vorticity /= m_UInfinity; // normalize
16369 minimumWallVorticity = mMin(minimumWallVorticity, vorticity);
16370 maximumWallVorticity = mMax(maximumWallVorticity, vorticity);
16371 }
16372 }
16373 fprintf(datei, " %f", minimumWallVorticity);
16374 fprintf(datei, " %f", maximumWallVorticity);
16375
16376 fprintf(datei, "\n");
16377 fclose(datei);
16378 }
16379
16381 /* conserved quantities L and A */
16383 if(m_recordLandA) {
16384 TERMM_IF_COND(m_reConstSVDWeightMode == 3 || m_reConstSVDWeightMode == 4, "Not yet implemented!");
16385 // this is 2D code!!!
16386 // compute the total vorticity
16387 FILE* datei;
16388 MInt noSrfcs = a_noSurfaces();
16389 MFloat vorticity = F0;
16390 MFloat totalVorticity = F0;
16391 MFloat totalVorticityPrimary = F0;
16392 MFloat totalVorticitySecondary = F0;
16393 MFloat totalSecondaryVorticity = F0;
16394 MFloat kineticEnergy = F0;
16395 MFloat enstrophy = F0;
16396 MFloat L1X = F0;
16397 MFloat L1Y = F0;
16398 MFloat L2X = F0;
16399 MFloat L2Y = F0;
16400 MFloat AZ1 = F0;
16401 MFloat AZ2 = F0;
16402 MFloat AZ3 = F0;
16403 MFloat LtopX = F0;
16404 MFloat LtopY = F0;
16405 MFloat AZtop = F0;
16406 MFloat tvtop = F0;
16407 MFloat tvtoprect = F0;
16408 MFloat LtopXrect = F0;
16409 MFloat LtopYrect = F0;
16410 MFloat LXprimary = F0;
16411 MFloat LXsecondary = F0;
16412 MFloat xmax = F0;
16413 MFloat xmin = F0;
16414 MFloat ymax = F0;
16415
16416 // changed by claudia in order to make this code applicable when m_movingGrid is false
16417 MFloat gridVelocity[3] = {F0, F0, F0};
16418 MFloat gridVelocityDt1[3] = {F0, F0, F0};
16419 MFloat gridCenter[3] = {F0, F0, F0};
16420
16421 // define rectangular computing area
16432 MInt refinementPatches = 0;
16433 refinementPatches = Context::getSolverProperty<MInt>("refinementPatches", m_solverId, AT_, &refinementPatches);
16434 switch(refinementPatches) {
16435 case 1211: {
16436 xmax = 10.0;
16437 xmin = -6.0;
16438 ymax = 10.0;
16439 break;
16440 }
16441 case 1212: {
16442 xmax = 10.0;
16443 xmin = -20.0;
16444 ymax = 10.0;
16445 break;
16446 }
16447 default: {
16448 // do nothing, create new case for matching refinement patch if needed
16449 }
16450 }
16451
16452 // compute L and A
16453 for(MInt cell = m_noActiveCells - 1; cell >= 0; --cell) {
16454 MInt cellId = m_activeCellIds[cell];
16455 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
16456 if(a_isBndryGhostCell(cellId)) continue;
16457 if(a_coordinate(cellId, 0) > xmax) continue;
16458 if(a_coordinate(cellId, 0) < xmin) continue;
16459 if(ABS(a_coordinate(cellId, 1)) > ymax) continue;
16460 vorticity = F1B2 * (a_slope(cellId, PV->V, 0) - a_slope(cellId, PV->U, 1));
16461 kineticEnergy +=
16462 F1B2 * a_cellVolume(cellId) * (POW2(a_pvariable(cellId, PV->U)) + POW2(a_pvariable(cellId, PV->V)));
16463 enstrophy += F1B2 * a_cellVolume(cellId) * POW2(vorticity);
16464 totalVorticity += ABS(vorticity) * a_cellVolume(cellId);
16465 if(vorticity * a_coordinate(cellId, 1) > F0) totalSecondaryVorticity += ABS(vorticity) * a_cellVolume(cellId);
16466 L2X += a_cellVolume(cellId) * vorticity * (a_coordinate(cellId, 1)); //- gridCenter[ 1 ] );
16467 L2Y -= a_cellVolume(cellId) * vorticity * (a_coordinate(cellId, 0)); //- gridCenter[ 0 ] );
16468 AZ1 -= a_cellVolume(cellId) * vorticity * F1B2
16469 * (POW2(a_coordinate(cellId, 0)) + //- gridCenter[ 0 ] ) +
16470 POW2(a_coordinate(cellId, 1))); //- gridCenter[ 1 ] ) );
16471 AZ3 -= a_cellVolume(cellId) * vorticity
16472 * ((a_coordinate(cellId, 0)) * gridCenter[0] + (a_coordinate(cellId, 1)) * gridCenter[1]);
16473 // top domain half
16474 if(a_coordinate(cellId, 1) > F0) {
16475 tvtop += vorticity * a_cellVolume(cellId);
16476 LtopX += a_cellVolume(cellId) * vorticity * (a_coordinate(cellId, 1));
16477 LtopY -= a_cellVolume(cellId) * vorticity * (a_coordinate(cellId, 0));
16478 AZtop -= a_cellVolume(cellId) * vorticity
16479 * ((a_coordinate(cellId, 0)) * gridCenter[0] + (a_coordinate(cellId, 1)) * gridCenter[1]);
16480 LtopXrect += a_cellVolume(cellId) * vorticity * (a_coordinate(cellId, 1));
16481 LtopYrect -= a_cellVolume(cellId) * vorticity * (a_coordinate(cellId, 0));
16482 tvtoprect += vorticity * a_cellVolume(cellId);
16483 }
16484 // only the primary vorticity contribution
16485 if(vorticity * (a_coordinate(cellId, 1)) > F0) {
16486 LXprimary += a_cellVolume(cellId) * vorticity * (a_coordinate(cellId, 1));
16487 totalVorticityPrimary += ABS(vorticity) * a_cellVolume(cellId);
16488 } else {
16489 LXsecondary += a_cellVolume(cellId) * vorticity * (a_coordinate(cellId, 1));
16490 totalVorticitySecondary += ABS(vorticity) * a_cellVolume(cellId);
16491 }
16492 }
16493 L1X = totalVorticity * gridCenter[1];
16494 L1Y = -totalVorticity * gridCenter[0];
16495 AZ2 = -m_angularBodyVelocity;
16496 LtopX += tvtop * gridCenter[1];
16497 LtopY -= tvtop * gridCenter[0];
16498 AZtop -= F1B2 * tvtop * (POW2(gridCenter[0]) + POW2(gridCenter[1]));
16499 LtopXrect += tvtoprect * gridCenter[1];
16500 LtopYrect -= tvtoprect * gridCenter[0];
16501 // LXprimary += totalVorticityPrimary * gridCenter[ 1 ];
16502 // LXsecondary += totalVorticitySecondary * gridCenter[ 1 ];
16503
16504 // normalize
16505 L1X /= m_UInfinity;
16506 L1Y /= m_UInfinity;
16507 L2X /= m_UInfinity;
16508 L2Y /= m_UInfinity;
16509 AZ1 /= m_UInfinity;
16510 AZ2 /= m_UInfinity;
16511 AZ3 /= m_UInfinity;
16512 LtopX /= m_UInfinity;
16513 LtopY /= m_UInfinity;
16514 AZtop /= m_UInfinity;
16515 LtopXrect /= m_UInfinity;
16516 LtopYrect /= m_UInfinity;
16517 LXprimary /= m_UInfinity;
16518 LXsecondary /= m_UInfinity;
16519
16520 // compute the integral int l x nabla^2 omega dV
16521 // /////////////////////////////////////////////
16522
16523 // compute the vorticity gradient
16524 for(MInt i = 0; i < a_noCells(); i++)
16525 for(MInt d = 0; d < nDim; d++)
16526 a_rightHandSide(i, d) = F0;
16527
16528 for(MUint k = 0; k < m_reconstructionDataSize; k++) {
16529 MFloat vorticityDifference =
16530 (F1B2
16531 * ((a_slope(m_reconstructionNghbrIds[k], 1, 0) - a_slope(m_reconstructionNghbrIds[k], 0, 1))
16532 - (a_slope(m_reconstructionCellIds[k], 1, 0) - a_slope(m_reconstructionCellIds[k], 0, 1))));
16533 a_rightHandSide(m_reconstructionCellIds[k], 0) += m_reconstructionConstants[nDim * k] * vorticityDifference;
16534 a_rightHandSide(m_reconstructionCellIds[k], 1) += m_reconstructionConstants[nDim * k + 1] * vorticityDifference;
16535 }
16536
16537 copyRHSIntoGhostCells();
16538
16539 // compute the integral int l x nabla^2 omega dV
16540 MFloat laplaceVorticityIntegral = F0;
16541 MFloat* area = &a_surfaceArea(0);
16542 for(MInt srfcId = 0; srfcId < noSrfcs; srfcId++) {
16543 // compute the surface vorticity * area
16544 a_surfaceFlux(srfcId, 0) =
16545 area[srfcId]
16546 * (a_surfaceFactor(srfcId, 0) * a_rightHandSide(a_surfaceNghbrCellId(srfcId, 0), a_surfaceOrientation(srfcId))
16547 + (a_surfaceFactor(srfcId, 1)
16548 * a_rightHandSide(a_surfaceNghbrCellId(srfcId, 1), a_surfaceOrientation(srfcId))));
16549 }
16550 for(MInt cell = m_noActiveCells - 1; cell >= 0; --cell) {
16551 MInt cellId = m_activeCellIds[cell];
16552 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
16553 a_rightHandSide(cellId, 0) = F0;
16554 }
16555 for(MInt srfcId = 0; srfcId < noSrfcs; srfcId++) {
16556 a_rightHandSide(a_surfaceNghbrCellId(srfcId, 0), 0) += a_surfaceFlux(srfcId, 0);
16557 a_rightHandSide(a_surfaceNghbrCellId(srfcId, 1), 0) -= a_surfaceFlux(srfcId, 0);
16558 }
16559 for(MInt cell = m_noActiveCells - 1; cell >= 0; --cell) {
16560 MInt cellId = m_activeCellIds[cell];
16561 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
16562 if(a_isBndryGhostCell(cellId)) continue;
16563 if(a_coordinate(cellId, 0) > xmax) continue;
16564 if(a_coordinate(cellId, 0) < xmin) continue;
16565 if(ABS(a_coordinate(cellId, 1)) > ymax) continue;
16566 laplaceVorticityIntegral += a_rightHandSide(cellId, 0) * (a_coordinate(cellId, 1) - gridCenter[1]);
16567 }
16568
16569 datei = fopen("conservedQuantities", "a+");
16570 fprintf(datei, "%d", globalTimeStep);
16571 fprintf(datei, " %f", m_physicalTime);
16572 fprintf(datei, " %f", m_time);
16573 fprintf(datei, " %f", L1X);
16574 fprintf(datei, " %f", L1Y);
16575 fprintf(datei, " %f", L2X);
16576 fprintf(datei, " %f", L2Y);
16577 fprintf(datei, " %f", AZ1);
16578 fprintf(datei, " %f", AZ2);
16579 fprintf(datei, " %f", AZ3);
16580 fprintf(datei, " %f", LtopX);
16581 fprintf(datei, " %f", LtopY);
16582 fprintf(datei, " %f", AZtop);
16583 fprintf(datei, " %f", LtopXrect);
16584 fprintf(datei, " %f", LtopYrect);
16585 fprintf(datei, " %f", LXprimary);
16586 fprintf(datei, " %f", LXsecondary);
16587 fprintf(datei, "\n");
16588 fclose(datei);
16589
16590 datei = fopen("flowFieldQuantities", "a+");
16591 fprintf(datei, "%d", globalTimeStep);
16592 fprintf(datei, " %f", m_physicalTime);
16593 fprintf(datei, " %f", m_time);
16594 fprintf(datei, " %f", totalVorticity);
16595 fprintf(datei, " %f", kineticEnergy);
16596 fprintf(datei, " %f", enstrophy);
16597 fprintf(datei, " %f", totalSecondaryVorticity);
16598 fprintf(datei, " %f", laplaceVorticityIntegral);
16599 fprintf(datei, "\n");
16600 fclose(datei);
16601
16602 // compute body force components
16603 //-------------------------------
16604 MFloat momentOfVorticity = F0;
16605 MFloat positiveMomentOfVorticity = F0;
16606 MFloat negativeMomentOfVorticity = F0;
16607 for(MInt cell = m_noActiveCells - 1; cell >= 0; --cell) {
16608 MInt cellId = m_activeCellIds[cell];
16609 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
16610 if(a_isBndryGhostCell(cellId)) continue;
16611 if(a_coordinate(cellId, 0) > xmax) continue;
16612 if(a_coordinate(cellId, 0) < xmin) continue;
16613 if(ABS(a_coordinate(cellId, 1)) > ymax) continue;
16614 vorticity = F1B2 * (a_slope(cellId, PV->V, 0) - a_slope(cellId, PV->U, 1));
16615 momentOfVorticity += a_cellVolume(cellId) * vorticity * a_coordinate(cellId, 1);
16616 if(vorticity * a_coordinate(cellId, 1) > F0)
16617 positiveMomentOfVorticity += a_cellVolume(cellId) * vorticity * a_coordinate(cellId, 1);
16618 else
16619 negativeMomentOfVorticity += a_cellVolume(cellId) * vorticity * a_coordinate(cellId, 1);
16620 }
16621 // time derivatives
16622 MFloat timeDerivativeMOV = (momentOfVorticity - m_oldMomentOfVorticity) / timeStep();
16623 MFloat timeDerivativeNMOV = (negativeMomentOfVorticity - m_oldNegativeMomentOfVorticity) / timeStep();
16624 MFloat timeDerivativePMOV = (positiveMomentOfVorticity - m_oldPositiveMomentOfVorticity) / timeStep();
16625 if(globalTimeStep < 2) {
16626 timeDerivativeMOV = F0;
16627 timeDerivativeNMOV = F0;
16628 timeDerivativePMOV = F0;
16629 }
16630 MFloat dUxdt = (gridVelocityDt1[0] - gridVelocity[0]) / timeStep();
16631 MFloat Ustar = m_Re / m_UInfinity * gridVelocity[0];
16632 // set old values
16633 m_oldMomentOfVorticity = momentOfVorticity;
16634 m_oldNegativeMomentOfVorticity = negativeMomentOfVorticity;
16635 m_oldPositiveMomentOfVorticity = positiveMomentOfVorticity;
16636
16637 datei = fopen("bodyForceBalance", "a+");
16638 fprintf(datei, "%d", globalTimeStep);
16639 fprintf(datei, " %f", m_physicalTime);
16640 fprintf(datei, " %f", m_time);
16641 fprintf(datei, " %f", momentOfVorticity);
16642 fprintf(datei, " %f", timeDerivativeMOV);
16643 fprintf(datei, " %f", negativeMomentOfVorticity);
16644 fprintf(datei, " %f", timeDerivativeNMOV);
16645 fprintf(datei, " %f", positiveMomentOfVorticity);
16646 fprintf(datei, " %f", timeDerivativePMOV);
16647 fprintf(datei, " %f", Ustar);
16648 fprintf(datei, " %f", dUxdt);
16649 fprintf(datei, "\n");
16650 fclose(datei);
16651 }
16652
16653 if(m_integratedHeatReleaseOutput) {
16654 if(m_integratedHeatReleaseOutputInterval != 0
16655 && (((globalTimeStep - offset) % m_integratedHeatReleaseOutputInterval) == 0)) {
16656 calculateHeatRelease();
16657
16658 MFloat accumulatedHeatRelease = F0;
16659 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
16660 accumulatedHeatRelease += m_heatRelease[cellId] * a_cellVolume(cellId);
16661 }
16662
16663 MPI_Allreduce(MPI_IN_PLACE, &accumulatedHeatRelease, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
16664 "accumulatedHeatRelease");
16665
16666 if(rank == 0) {
16667 FILE* datei;
16668 datei = fopen("integratedHeatRelease", "a+");
16669 fprintf(datei, "%d", globalTimeStep);
16670 fprintf(datei, " %-10.10f", m_physicalTime);
16671 fprintf(datei, " %-10.10f", m_time);
16672 fprintf(datei, " %-10.10f", accumulatedHeatRelease);
16673 fprintf(datei, "\n");
16674 fclose(datei);
16675 }
16676 }
16677 }
16678
16679 if(!m_combustion) {
16680 // force coefficients
16681 if(m_dragOutputInterval != 0
16682 && (((globalTimeStep - offset) % m_dragOutputInterval) == 0 && globalTimeStep >= offset)) {
16683 MFloatScratchSpace forceCoefficientVector(nDim, AT_, "forceCoefficientVector");
16684 computeForceCoefficients(&forceCoefficientVector.p[0]);
16685
16686 MFloat m_ub_utau = 1.0 / sqrt(forceCoefficientVector.p[0] / 2.0);
16687 MFloat Re_tau = m_Re / m_ub_utau;
16688
16689 if(rank == 0) {
16690 FILE* datei;
16691 datei = fopen("forceCoef", "a+");
16692 fprintf(datei, "%d", globalTimeStep);
16693 fprintf(datei, " %f", m_physicalTime);
16694 fprintf(datei, " %f", m_time);
16695 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
16696 fprintf(datei, " %f", forceCoefficientVector.p[spaceId]);
16697 }
16698 IF_CONSTEXPR(nDim == 2) {
16699 fprintf(datei, " %f",
16700 forceCoefficientVector.p[0] * cos(m_angle[0]) + forceCoefficientVector.p[1] * sin(m_angle[0]));
16701 fprintf(datei, " %f",
16702 -forceCoefficientVector.p[0] * sin(m_angle[0]) + forceCoefficientVector.p[1] * cos(m_angle[0]));
16703 }
16704 if(m_periodicCells == 3) { // azimuthal periodicity concept
16705 fprintf(datei, " %f", m_ub_utau);
16706 fprintf(datei, " %f", Re_tau);
16707 }
16708 fprintf(datei, "\n");
16709 fclose(datei);
16710 }
16711 }
16712 }
16713
16714 if(m_wmSurfaceProbeInterval > 0) {
16715 if(((globalTimeStep - offset) % m_wmSurfaceProbeInterval) == 0 && globalTimeStep >= offset) {
16716 writeWMSurfaceProbes();
16717 }
16718 }
16719
16720 if(m_wallNormalOutput && m_normalOutputInterval > 0) {
16721 if(((globalTimeStep - offset) % m_normalOutputInterval) == 0 && globalTimeStep >= offset) {
16722 getWallNormalPointVars();
16723 }
16724 }
16725
16726 if(m_saSrfcProbeInterval > 0) {
16727 if(globalTimeStep >= m_saSrfcProbeStart) {
16728 if(((globalTimeStep - offset) % m_saSrfcProbeInterval) == 0 && globalTimeStep >= offset) {
16729 writeSpanAvgSrfcProbes();
16730 }
16731 }
16732 }
16733
16734 {
16735 // solution output
16736 // ---------------
16737 if((((globalTimeStep - offset) % m_solutionInterval) == 0 && globalTimeStep >= offset) || forceOutput
16738 || (m_solutionTimeSteps.count(globalTimeStep) > 0)) {
16739 if(m_outputPhysicalTime) {
16740 if(domainId() == 0)
16741 cerr << "solverId: " << m_solverId << ", Writing " << m_outputFormat << " output at time step "
16742 << globalTimeStep << ", physical time " << m_physicalTime << " ... ";
16743 m_log << "Writing " << m_outputFormat << " output at time step " << globalTimeStep << ", physical time "
16744 << m_physicalTime << " ... ";
16745 } else {
16746 if(domainId() == 0)
16747 cerr << "solverId: " << m_solverId << ", Writing " << m_outputFormat << " output at time step "
16748 << globalTimeStep << ", time " << m_time << " ... ";
16749 m_log << "Writing " << m_outputFormat << " output at time step " << globalTimeStep << ", time " << m_time
16750 << " ... ";
16751 }
16752
16753
16754 MInt noLevelSetFieldData = 0;
16755
16756 if(m_levelSet) {
16757 if(m_combustion) {
16758 noLevelSetFieldData = 0; // a_noLevelSetFieldData();
16759 // noLevelSetFieldData = combustion().noLevelSetFieldData();
16760 } else if(m_levelSetMb) {
16761 noLevelSetFieldData = 0;
16762 } else {
16763 noLevelSetFieldData = a_noLevelSetFieldData();
16764 }
16765 }
16766
16767 MBool writeSpongeInfo = false;
16768 writeSpongeInfo = Context::getSolverProperty<MBool>("writeSpongeInfo", solverId(), AT_, &writeSpongeInfo);
16769
16770 if(m_spongeTimeDep) writeSpongeInfo = true;
16771
16772 MBool writeLimInfo = false;
16773 if(string2enum(m_surfaceValueReconstruction) == HOCD_LIMITED_SLOPES_MAN) writeLimInfo = true;
16774
16775 MFloatScratchSpace dbVariables(a_noCells()
16776 * (PV->noVariables + (MInt)m_levelSet * noLevelSetFieldData
16777 + m_vorticitySize + (MInt)m_qCriterionOutput + (MInt)writeSpongeInfo
16778 + (MInt)writeLimInfo + (5 + PV->noVariables) * (MInt)m_wmOutput
16779 + (MInt)m_useSandpaperTrip)
16780 + (MInt)isDetChem<SysEqn>,
16781 AT_, "dbVariables");
16782 MIntScratchSpace idVariables(a_noCells() * 2, AT_,
16783 "idVariables"); // MIntScratchSpace idVariables(a_noCells()*2, AT_, "idVariables");
16784 MFloatScratchSpace dbParameters(4, AT_, "dbParameters");
16785 MIntScratchSpace idParameters(2, AT_, "idParameters");
16786 vector<MString> dbVariablesName;
16787 vector<MString> idVariablesName;
16788 vector<MString> dbParametersName;
16789 vector<MString> idParametersName;
16790 vector<MString> name;
16791
16792 stringstream fileName;
16793 if(m_multipleFvSolver) {
16794 fileName << m_solutionOutput << "QOUT" << getIdentifier(true, "_") << globalTimeStep;
16795 } else {
16796 fileName << m_solutionOutput << "QOUT_" << globalTimeStep;
16797 }
16798
16799 for(MInt v = 0; v < PV->noVariables; v++) {
16800 name.push_back(m_variablesName[v]);
16801 }
16802
16803 this->collectVariables(&a_pvariable(0, 0), dbVariables, name, dbVariablesName, PV->noVariables, a_noCells());
16804 if(writeLimInfo) {
16805 name.clear();
16806 name.push_back("limPhi");
16807 this->collectVariables(m_limPhi, dbVariables, name, dbVariablesName, 1, a_noCells());
16808 }
16809
16810 if(m_vorticityOutput) {
16811 MFloatScratchSpace vorticity(a_noCells() * m_vorticitySize, AT_, "vorticity");
16812 getVorticity(&vorticity[0]);
16813 name.clear();
16814 for(MInt i = 0; i < m_vorticitySize; i++) {
16815 name.push_back(m_vorticityName[i]);
16816 }
16817 this->collectVariables(vorticity.begin(), dbVariables, name, dbVariablesName, m_vorticitySize, a_noCells(),
16818 true);
16819 }
16820
16821 if(m_qCriterionOutput) {
16822 MFloatScratchSpace qCriterion(a_noCells(), AT_, "qCriterion");
16823 computeQCriterion(qCriterion);
16824 name.clear();
16825 name.push_back("qCriterion");
16826 this->collectVariables(qCriterion.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16827 }
16828
16829
16830 if(m_wmOutput) {
16831 MFloatScratchSpace tmp(a_noCells(), AT_, "tmp");
16832
16833 for(MInt cell = 0; cell < a_noCells(); cell++) {
16834 tmp[cell] = 0.0;
16835 }
16836 for(MUint wmSrfcId = 0; wmSrfcId < m_wmSurfaces.size(); wmSrfcId++) {
16837 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
16838 const MInt cell = m_bndryCells->a[bndryCellId].m_cellId;
16839 tmp[cell] = (MFloat)m_wmSurfaces[wmSrfcId].m_wmHasImgCell;
16840 }
16841 name.clear();
16842 name.push_back("hasImgCell");
16843 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16844
16845 for(MInt cell = 0; cell < a_noCells(); cell++) {
16846 tmp[cell] = 0.0;
16847 }
16848 for(MUint wmSrfcId = 0; wmSrfcId < m_wmSurfaces.size(); wmSrfcId++) {
16849 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
16850 const MInt cell = m_bndryCells->a[bndryCellId].m_cellId;
16851 tmp[cell] = (MFloat)m_wmSurfaces[wmSrfcId].m_wmUII;
16852 }
16853 name.clear();
16854 name.push_back("u_II");
16855 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16856
16857 for(MInt cell = 0; cell < a_noCells(); cell++) {
16858 tmp[cell] = 0.0;
16859 }
16860 for(MUint wmSrfcId = 0; wmSrfcId < m_wmSurfaces.size(); wmSrfcId++) {
16861 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
16862 const MInt cell = m_bndryCells->a[bndryCellId].m_cellId;
16863 tmp[cell] = (MFloat)m_wmSurfaces[wmSrfcId].m_wmTauW;
16864 }
16865 name.clear();
16866 name.push_back("tau_w_spalding");
16867 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16868
16869 for(MInt cell = 0; cell < a_noCells(); cell++) {
16870 tmp[cell] = 0.0;
16871 }
16872 for(MUint wmSrfcId = 0; wmSrfcId < m_wmSurfaces.size(); wmSrfcId++) {
16873 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
16874 const MInt cell = m_bndryCells->a[bndryCellId].m_cellId;
16875 tmp[cell] = (MFloat)m_wmSurfaces[wmSrfcId].m_wmMUEWM;
16876 }
16877 name.clear();
16878 name.push_back("mue_wm");
16879 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16880
16881 for(MInt cell = 0; cell < a_noCells(); cell++) {
16882 tmp[cell] = (MFloat)a_isWMImgCell(cell);
16883 }
16884 name.clear();
16885 name.push_back("isWMImgCell");
16886 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16887
16888 const MChar* imgVarNames[5] = {"UImg", "VImg", "WImg", "RHOImg", "PImg"};
16889 for(MInt v = 0; v < PV->noVariables; v++) {
16890 for(MInt cell = 0; cell < a_noCells(); cell++) {
16891 tmp[cell] = 0.0;
16892 }
16893 for(MUint wmSrfcId = 0; wmSrfcId < m_wmSurfaces.size(); wmSrfcId++) {
16894 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
16895 const MInt cell = m_bndryCells->a[bndryCellId].m_cellId;
16896 tmp[cell] = (MFloat)m_wmSurfaces[wmSrfcId].m_wmImgVars[v];
16897 }
16898 name.clear();
16899 name.push_back(v <= 4 ? imgVarNames[v] : "YImg" + std::to_string(v));
16900 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16901 }
16902 }
16903
16904 if(m_useSandpaperTrip) {
16905 MFloatScratchSpace tmp(a_noCells(), AT_, "tmp");
16906 for(MInt cell = 0; cell < a_noCells(); cell++) {
16907 tmp[cell] = (MFloat)a_isSandpaperTripCell(cell);
16908 }
16909 name.clear();
16910 name.push_back("isSandpaperTripCell");
16911 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16912 }
16913
16914 if(m_levelSet) {
16915 MInt noSets = 0;
16916 if(m_combustion) {
16917 noSets = a_noSets();
16918 } else if(!m_levelSetMb) {
16919 noSets = a_noSets();
16920 }
16921 for(MInt set = 0; set < noSets; set++) {
16922 MFloatScratchSpace levelSetFunction(a_noCells(), AT_, "levelSetFunction");
16923 MFloatScratchSpace curvature(a_noCells(), AT_, "curvature");
16924
16925 for(MInt cell = 0; cell < c_noCells(); cell++) {
16926 if(m_combustion) {
16927 levelSetFunction[cell] = a_levelSetFunction(cell, 0);
16928 curvature[cell] = a_curvatureG(cell, 0);
16929 } else if(m_levelSetMb) {
16930 continue;
16931 } else {
16932 levelSetFunction[cell] = a_levelSetFunction(cell, 0);
16933 curvature[cell] = a_curvatureG(cell, 0);
16934 }
16935 }
16936 stringstream gName;
16937 stringstream gCurv;
16938 gName << "G_" << set << endl;
16939 gCurv << "curvature_" << set << endl;
16940 name.clear();
16941 name.push_back(gName.str());
16942 this->collectVariables(levelSetFunction.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16943 name.clear();
16944 name.push_back(gCurv.str());
16945 this->collectVariables(curvature.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16946 }
16947 }
16948
16949 this->collectParameters(m_noSamples, idParameters, "noSamples", idParametersName);
16950 this->collectParameters(globalTimeStep, idParameters, "globalTimeStep", idParametersName);
16951 if(m_outputPhysicalTime) {
16952 this->collectParameters(m_physicalTime, dbParameters, "time", dbParametersName);
16953 this->collectParameters(m_time, dbParameters, "internalTime", dbParametersName);
16954 } else {
16955 this->collectParameters(m_time, dbParameters, "time", dbParametersName);
16956 this->collectParameters(m_physicalTime, dbParameters, "physicalTime", dbParametersName);
16957 }
16958
16959 MIntScratchSpace domainIdCheck(a_noCells(), AT_, "domainIdCheck");
16960 MIntScratchSpace windowCheck(a_noCells(), AT_, "windowCheck");
16961 for(MInt cell = 0; cell < a_noCells(); cell++) {
16962 domainIdCheck.p[cell] = domainId();
16963 if(a_isBndryGhostCell(cell)) continue;
16964 if(a_isWindow(cell)) {
16965 windowCheck.p[cell] = domainId();
16966 } else
16967 windowCheck.p[cell] = -1;
16968 }
16969
16970 // writing out sponge info
16971 if(writeSpongeInfo) {
16972 MFloatScratchSpace spongeFactor(a_noCells(), AT_, "spongeFactor");
16973 for(MInt cell = 0; cell < a_noCells(); cell++) {
16974 spongeFactor[cell] = a_spongeFactor(cell);
16975 }
16976 name.clear();
16977 name.push_back("sigmaSponge");
16978 this->collectVariables(spongeFactor.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
16979 }
16980
16981 // --------------------------------------------
16982
16983 switch(string2enum(m_outputFormat)) {
16984 case NETCDF: {
16985 fileName << ParallelIo::fileExt();
16986 // TODO labels:FV,IO currently not working for adaptation, check save restartFile
16987 // and get solver recalcIds!
16988 //
16989 saveGridFlowVarsPar((fileName.str()).c_str(), a_noCells(), noInternalCells(), dbVariables, dbVariablesName, 0,
16990 idVariables, idVariablesName, 0, dbParameters, dbParametersName, idParameters,
16991 idParametersName, m_recalcIds);
16992 break;
16993 }
16994 case VTK:
16995 case VTU:
16996 case VTP: {
16997 m_fvBndryCnd->recorrectCellCoordinates();
16998 // grid().extractPointIdsFromGrid(false);
16999 extractPointIdsFromGrid(m_extractedCells, m_gridPoints, false, m_splitChildToSplitCell, m_vtuLevelThreshold,
17000 m_vtuCoordinatesThreshold);
17001 reduceVariables();
17002 fileName << "_D" << domainId() << ".vtu";
17003
17005
17006 VtkIo.writeVtkXmlOutput((fileName.str()).c_str());
17007 if(m_extractedCells) {
17008 delete m_extractedCells;
17009 m_extractedCells = nullptr;
17010 }
17011 if(m_gridPoints) {
17012 delete m_gridPoints;
17013 m_gridPoints = nullptr;
17014 }
17015 m_fvBndryCnd->rerecorrectCellCoordinates();
17016 break;
17017 }
17018 default: {
17019 stringstream errorMessage;
17020 errorMessage << "FvCartesianSolverXD::saveOutputFv(): switch variable 'm_outputFormat' with value "
17021 << m_outputFormat << " not matching any case." << endl;
17022 mTerm(1, AT_, errorMessage.str());
17023 }
17024 }
17025
17026 if(domainId() == 0) cerr << "ok" << endl;
17027 }
17028 }
17029}
17030
17031
17032//------------------------------------------------------------------------------------------------------
17033
17034template <MInt nDim_, class SysEqn>
17035void FvCartesianSolverXD<nDim_, SysEqn>::writeRestartFile(const MBool writeRestart, const MBool writeBackup,
17036 const MString gridFileName, MInt* recalcIdTree) {
17037 TRACE();
17038
17039 m_currentGridFileName = gridFileName;
17040
17041 if(m_recalcIds != nullptr) {
17042 for(MInt cellId = 0; cellId < maxNoGridCells(); cellId++) {
17043 m_recalcIds[cellId] = recalcIdTree[cellId];
17044 }
17045 }
17046
17047 if(writeRestart) {
17048 saveRestartFile(writeBackup);
17049 }
17050
17051 if(m_useSandpaperTrip) {
17052 saveSandpaperTripVars();
17053 }
17054
17055 if(m_wmLES) {
17056 writeWMTimersASCII();
17057 }
17058
17059 saveSampleFiles();
17060}
17061
17062//------------------------------------------------------------------------------------------------------
17063
17064template <MInt nDim_, class SysEqn>
17066 TRACE();
17067
17068 writeGridRestart = false;
17069
17070 // write intermediate restart file
17071 if(m_restartInterval == -1 && !writeRestart) {
17072 writeRestart = false;
17073 }
17074
17075 MInt relativeTimeStep = globalTimeStep - m_restartOffset;
17076 MInt relativeRestartTimeStep = m_restartTimeStep - m_restartOffset;
17077
17078 if(((relativeTimeStep % m_restartInterval) == 0 && relativeTimeStep > relativeRestartTimeStep) || writeRestart) {
17079 writeRestart = true;
17080
17081 if(m_forceRestartGrid) {
17082 m_adaptationSinceLastRestart = true;
17083 writeGridRestart = true;
17084 if(m_recalcIds == nullptr && isActive()) mAlloc(m_recalcIds, maxNoGridCells(), "m_recalcIds", -1, AT_);
17085 }
17086
17087 if(m_adaptationSinceLastRestartBackup || m_adaptationSinceLastRestart) {
17088 writeGridRestart = true;
17089 }
17090 }
17091
17092 if(isActive() && m_levelSetMb && writeRestart) {
17093 if(maxLevel() > minLevel()) {
17094 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
17095 if(a_isBndryGhostCell(cellId)) continue;
17096 if(a_isHalo(cellId)) continue;
17097 if(a_level(cellId) != minLevel()) continue;
17098 reduceData(cellId, &a_pvariable(0, 0), PV->noVariables);
17099 }
17100 }
17101 }
17102
17103 return writeRestart;
17104}
17105
17106template <MInt nDim_, class SysEqn>
17108 TRACE();
17109
17110 if(doneRestart) {
17111 m_adaptationSinceLastRestart = false;
17112 m_adaptationSinceLastRestartBackup = false;
17113 }
17114}
17115
17116
17117//------------------------------------------------------------------------------------------------------
17118
17119template <MInt nDim_, class SysEqn>
17121 TRACE();
17122
17123 if(m_time < m_samplingTimeBegin) {
17124 return;
17125 }
17126 if(m_time > m_samplingTimeEnd) {
17127 return;
17128 }
17129 if(globalTimeStep % samplingInterval() != 0) {
17130 return;
17131 }
17132
17133 const MInt oldSize = a_noCells();
17134 m_cells.size(m_bndryGhostCellsOffset);
17135
17136 MInt ghostcellbackup = m_totalnoghostcells;
17137 MInt splitchildbackup = m_totalnosplitchilds;
17138 m_totalnoghostcells = 0;
17139 m_totalnosplitchilds = 0;
17140
17141 stringstream varFileName;
17142
17143 {
17144 varFileName << outputDir() << "Q_" << m_noSamples << ParallelIo::fileExt();
17145
17146 MFloatScratchSpace dbVariables(
17147 a_noCells() * (PV->noVariables + (MInt)m_levelSet + m_vorticitySize + (MInt)m_qCriterionOutput), AT_,
17148 "dbVariables");
17149 MIntScratchSpace idVariables(0, AT_, "idVariables");
17150 MFloatScratchSpace dbParameters(6, AT_, "dbParameters");
17151 MIntScratchSpace idParameters(4, AT_, "idParameters");
17152 vector<MString> dbVariablesName;
17153 vector<MString> idVariablesName;
17154 vector<MString> dbParametersName;
17155 vector<MString> idParametersName;
17156 vector<MString> name;
17157
17158 for(MInt v = 0; v < PV->noVariables; v++) {
17159 name.push_back(m_variablesName[v]);
17160 }
17161
17162 this->collectVariables(&a_pvariable(0, 0), dbVariables, name, dbVariablesName, PV->noVariables, a_noCells());
17163
17164 if(m_vorticityOutput) {
17165 MFloatScratchSpace vorticity(a_noCells() * m_vorticitySize, AT_, "vorticity");
17166 getVorticity(&vorticity[0]);
17167 name.clear();
17168 for(MInt i = 0; i < m_vorticitySize; i++) {
17169 name.push_back(m_vorticityName[i]);
17170 }
17171 this->collectVariables(vorticity.begin(), dbVariables, name, dbVariablesName, m_vorticitySize, a_noCells(), true);
17172 }
17173
17174 if(m_qCriterionOutput) {
17175 MFloatScratchSpace qCriterion(a_noCells(), AT_, "qCriterion");
17176 computeQCriterion(qCriterion);
17177 name.clear();
17178 name.push_back("qCriterion");
17179 this->collectVariables(qCriterion.begin(), dbVariables, name, dbVariablesName, 1, a_noCells());
17180 }
17181 setRestartFileOutputTimeStep();
17182 this->collectParameters(m_noSamples, idParameters, "noSamples", idParametersName);
17183 this->collectParameters(globalTimeStep, idParameters, "globalTimeStep", idParametersName);
17184 if(m_outputPhysicalTime) {
17185 this->collectParameters(m_physicalTime, dbParameters, "time", dbParametersName);
17186 } else {
17187 this->collectParameters(m_time, dbParameters, "time", dbParametersName);
17188 }
17189 this->collectParameters(m_restartFileOutputTimeStep, dbParameters, "timeStep", dbParametersName);
17190 this->collectParameters(m_noTimeStepsBetweenSamples, idParameters, "noTimeStepsBetweenSamples", idParametersName);
17191 this->collectParameters(m_physicalTime, dbParameters, "physicalTime", dbParametersName);
17192 this->collectParameters((MInt)m_forcing, idParameters, "forcing", idParametersName);
17193 this->collectParameters(m_meanPressure, dbParameters, "meanPressure", dbParametersName);
17194
17195 // TODO labels:FV,IO currently not working for adaptation, check save restartFile
17196 // and get solver recalcIds!
17197 //
17198 saveGridFlowVarsPar((varFileName.str()).c_str(), a_noCells(), noInternalCells(), dbVariables, dbVariablesName, 0,
17199 idVariables, idVariablesName, 0, dbParameters, dbParametersName, idParameters, idParametersName,
17200 m_recalcIds);
17201 }
17202
17203 m_noSamples++;
17204
17205
17206 m_cells.size(oldSize);
17207 m_totalnoghostcells = ghostcellbackup;
17208 m_totalnosplitchilds = splitchildbackup;
17209}
17210
17211
17212template <MInt nDim_, class SysEqn>
17214 TRACE();
17215 // const MInt maxNoEmbeddedBodies = 10;
17216 // ofstream ofl2[maxNoEmbeddedBodies];
17217 MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
17218 MInt cellId, ghostCellId;
17219 MFloat rhoSurface, pSurface;
17220 MFloat T, mue, dAoverRe, rhoU2;
17221 MFloat dist;
17222 const MFloat eps = c_cellLengthAtLevel(maxRefinementLevel()) * 0.0001;
17223 MFloat angle, cp, ma;
17224 MFloat pressure[nDim];
17225 MFloat tau[nDim];
17226 MFloat shear[nDim];
17227 MFloat globalForceCoefficients[nDim];
17228 MInt localNoSurfacePoints = 0;
17229 MFloat ypmin = 999999.99;
17230 MFloat ypmax = F0;
17231 MFloat ypavg = F0;
17232 MFloat yprms = F0;
17233 MFloat ypcnt = F0;
17234
17235 for(MInt i = 0; i < nDim; i++) {
17236 tau[i] = numeric_limits<MFloat>::max(); // gcc 4.8.2 maybe uninitialized
17237 }
17238
17239 // prepare parallel writing
17240 if(m_surfDistParallel) {
17241 for(MInt bndryCellId = 0; bndryCellId < noBndryCells; bndryCellId++) {
17242 cellId = m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_cellId;
17243 // if( cellId >= noInternalCells() )
17244 // continue;
17245 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17246 if(a_isHalo(cellId)) continue;
17247 if(a_isPeriodic(cellId)) continue;
17248 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_noSrfcs; srfc++) {
17249 if(m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_bndryCndId < 3000
17250 || m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_bndryCndId >= 4000)
17251 continue;
17252 localNoSurfacePoints++;
17253 }
17254 }
17255 }
17256 const MInt surfaceValuesSize = 4 + nDim;
17257 MFloatScratchSpace surfaceValues(localNoSurfacePoints * surfaceValuesSize, AT_, "surfaceValues");
17258 //---
17259
17260
17261 // reset
17262 for(MInt i = 0; i < nDim; i++) {
17263 shear[i] = F0;
17264 pressure[i] = F0;
17265 }
17266
17267 rhoU2 = F0;
17268 for(MInt i = 0; i < nDim; i++) {
17269 rhoU2 += POW2(m_VVInfinity[i]);
17270 }
17271 rhoU2 *= m_rhoInfinity;
17272
17273 MBool found_ = false;
17274 MFloat localRetau[1];
17275 MFloat globalRetau[1];
17276 localRetau[0] = 0.0;
17277 globalRetau[0] = 0.0;
17278 MFloat Re_tau_ = 0.0;
17279 MFloat localArea1[1];
17280 MFloat globalArea1[1];
17281 localArea1[0] = 0.0;
17282 globalArea1[0] = 0.0;
17283
17284
17285 MInt counter = 0;
17286 for(MInt bndryCellId = 0; bndryCellId < noBndryCells; bndryCellId++) {
17287 // only take (non-ghost) non-slave cells with solid-wall bc into account
17288 cellId = m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_cellId;
17289 if(cellId >= noInternalCells() && (!m_surfDistParallel)) continue;
17290 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
17291 if(a_isHalo(cellId)) continue;
17292 if(a_isPeriodic(cellId)) continue;
17293
17294 MFloatScratchSpace dummyPvariables(m_bndryCells->a[bndryCellId].m_noSrfcs, PV->noVariables, AT_, "dummyPvariables");
17295
17296 if(!m_surfDistParallel)
17297 if(m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_linkedCellId > -1)
17298 if(a_bndryId(m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_linkedCellId) > -1) continue;
17299 if(!m_fvBndryCnd->m_cellMerging) {
17300 for(MInt s = 0; s < mMin((signed)m_fvBndryCnd->m_bndryCell[bndryCellId].m_recNghbrIds.size(),
17301 m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_noSrfcs);
17302 s++) {
17303 dummyPvariables(s, PV->P) = m_fvBndryCnd->m_bndryCell[bndryCellId].m_srfcVariables[s]->m_primVars[PV->P];
17304 dummyPvariables(s, PV->RHO) = m_fvBndryCnd->m_bndryCell[bndryCellId].m_srfcVariables[s]->m_primVars[PV->RHO];
17305 }
17306 }
17307 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_noSrfcs; srfc++) {
17308 if(m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_bndryCndId < 3000
17309 || m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_bndryCndId >= 4000)
17310 continue;
17311 // find corresponding ghostId
17312 ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcVariables[srfc]->m_ghostCellId;
17313
17314 // density and pressure on surface
17315 rhoSurface = F1B2 * (a_pvariable(cellId, PV->RHO) + a_pvariable(ghostCellId, PV->RHO));
17316 pSurface = F1B2 * (a_pvariable(cellId, PV->P) + a_pvariable(ghostCellId, PV->P));
17317
17318 // temperature
17319 T = sysEqn().temperature_ES(rhoSurface, pSurface);
17320
17321 // calculate the viscosity with the sutherland law mue = T^3/2 * (1+S/T_0)(T + S/T_0)
17322 mue = SUTHERLANDLAW(T);
17323
17324 // A_s / Re
17325 dAoverRe =
17326 m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_area / (m_referenceLength * sysEqn().m_Re0);
17327
17328 // distanceVector: connection vector of boundary surface center and cell center
17329 dist = F0;
17330 for(MInt i = 0; i < nDim; i++) {
17331 dist +=
17332 fabs((a_coordinate(cellId, i) - m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_coordinates[i])
17333 * m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_normalVector[i]);
17334 }
17335
17336 // determine tau (all dimensions)
17337 if(m_fvBndryCnd->m_cellMerging) {
17338 for(MInt orientation = 0; orientation < nDim; orientation++) {
17339 if(fabs(dist) > eps)
17340 tau[orientation] =
17341 mue * F1B2 * (a_pvariable(cellId, PV->VV[orientation]) - a_pvariable(ghostCellId, PV->VV[orientation]))
17342 / dist;
17343 else
17344 tau[orientation] = F0;
17345 }
17346 } else {
17347 rhoSurface = F0;
17348 pSurface = F0;
17349 for(MInt n = 0; n < (signed)m_fvBndryCnd->m_bndryCell[bndryCellId].m_recNghbrIds.size(); n++) {
17350 const MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryCellId].m_recNghbrIds[n];
17351 const MFloat nghbrPvariableP = (n < m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_noSrfcs)
17352 ? dummyPvariables(n, PV->P)
17353 : a_pvariable(nghbrId, PV->P);
17354 const MFloat nghbrPvariableRho = (n < m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_noSrfcs)
17355 ? dummyPvariables(n, PV->RHO)
17356 : a_pvariable(nghbrId, PV->RHO);
17357 rhoSurface +=
17358 m_fvBndryCnd->m_bndryCell[bndryCellId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariableRho;
17359 pSurface +=
17360 m_fvBndryCnd->m_bndryCell[bndryCellId].m_srfcVariables[srfc]->m_imagePointRecConst[n] * nghbrPvariableP;
17361 }
17362 T = sysEqn().temperature_ES(rhoSurface, pSurface);
17363 mue = SUTHERLANDLAW(T);
17364 for(MInt k = 0; k < nDim; k++) {
17365 tau[k] = mue * m_fvBndryCnd->m_bndryCell[bndryCellId].m_srfcVariables[srfc]->m_normalDeriv[PV->VV[k]];
17366 }
17367 }
17368
17369 // shear-stress and pressure
17370 for(MInt orientation = 0; orientation < nDim; orientation++) {
17371 pressure[orientation] +=
17372 (-F1) * pSurface * m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_area
17373 * m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_normalVector[orientation];
17374 shear[orientation] += tau[orientation] * dAoverRe;
17375 }
17376
17377
17378 if(m_periodicCells == 3) { // azimuthal periodicity concept
17379
17380
17381 MFloat Length_2 = c_cellLengthAtCell(cellId);
17382 if(a_coordinate(cellId, 2) < 200.0 && a_coordinate(cellId, 1) > 200.0
17383 && a_coordinate(cellId, 1) < (200.0 + Length_2) && a_coordinate(cellId, 0) >= 2.5
17384 && a_coordinate(cellId, 0) < 2.5 + Length_2) {
17385 found_ = true;
17386 Re_tau_ = sqrt(tau[0] / sysEqn().m_Re0 / rhoSurface / (m_Ma * sqrt(m_TInfinity)) / (m_Ma * sqrt(m_TInfinity)))
17387 * m_Re;
17388 }
17389
17390 if(a_coordinate(cellId, 0) >= 2.5 && a_coordinate(cellId, 0) < 2.5 + Length_2) {
17391 // MFloat re_test= sqrt(fabs(tau[ 0 ])/m_Re0/rhoSurface/(m_Ma * sqrt( m_TInfinity ))/(m_Ma * sqrt(
17392 // m_TInfinity )))*m_Re;
17393 localArea1[0] += m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[0]->m_area;
17394 localRetau[0] +=
17395 sqrt(fabs(tau[0]) / sysEqn().m_Re0 / rhoSurface / (m_Ma * sqrt(m_TInfinity)) / (m_Ma * sqrt(m_TInfinity)))
17396 * m_Re * m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[0]->m_area;
17397 }
17398 }
17399
17400
17401 MFloat yplus;
17402 MFloat magTau = F0;
17403 for(MInt dim = 0; dim < nDim; dim++) {
17404 magTau += POW2(tau[dim]);
17405 }
17406 yplus = sqrt(sysEqn().m_Re0 * sqrt(magTau) * rhoSurface) * c_cellLengthAtCell(cellId) / mue;
17407
17408 ypmin = mMin(ypmin, yplus);
17409 ypmax = mMax(ypmax, yplus);
17410 ypavg += yplus;
17411 yprms += POW2(yplus);
17412 ypcnt += F1;
17413
17414 // save surface values to scratch space:
17415 if(m_surfDistParallel) {
17416 MFloat radToDeg = 360.0 / (2.0 * PI);
17417 MFloat xOffset = 0.0;
17418 MFloat yOffset = 0.0;
17419 if(m_levelSetMb) {
17420 MInt body = m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_bodyId[0];
17421 ASSERT(body > -1, "wrong body Id for boundary surface...");
17422 xOffset = m_bodyCenter[body * nDim + 0];
17423 yOffset = m_bodyCenter[body * nDim + 1];
17424 }
17425 MFloat dx = m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_coordinates[0] - xOffset;
17426 MFloat dy = m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_coordinates[1] - yOffset;
17427 angle = 180.0 - (radToDeg * atan2(dy, dx));
17428 ma = F0;
17429 for(MInt i = 0; i < nDim; i++)
17430 ma += POW2(m_fvBndryCnd->m_bndryCell[bndryCellId].m_srfcVariables[srfc]->m_primVars[PV->VV[i]]);
17431 ma = sqrt(ma);
17432 ma /= sysEqn().speedOfSound(rhoSurface, pSurface);
17433 cp = (pSurface - m_PInfinity) / (F1B2 * rhoU2);
17434 MFloat cf = (m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_normalVector[1] * tau[0]
17435 - m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_normalVector[0] * tau[1])
17436 / (F1B2 * rhoU2 * sysEqn().m_Re0);
17437 MInt idcnt = counter * surfaceValuesSize;
17438 surfaceValues(idcnt++) = angle;
17439 for(MInt i = 0; i < nDim; i++) {
17440 surfaceValues(idcnt++) = m_fvBndryCnd->m_bndryCells->a[bndryCellId].m_srfcs[srfc]->m_coordinates[i];
17441 }
17442 surfaceValues(idcnt++) = cp;
17443 surfaceValues(idcnt++) = cf;
17444 surfaceValues(idcnt) = ma;
17445 counter++;
17446 }
17447 }
17448 }
17449
17450
17451 // parallel surface-value output using MPI I/O
17452 if(m_surfDistParallel) {
17453 const MString fileName = "surfaceDistribution";
17454 const MInt dataSolver = surfaceValuesSize;
17455 const MInt floatWidth = 9;
17456 const MInt noChars = floatWidth + 2;
17457 MInt dataSize = dataSolver * noChars * counter;
17458 ScratchSpace<char> data(dataSize, AT_, "data");
17459 MInt cnt = 0;
17460 for(MInt c = 0; c < counter; c++) {
17461 for(MInt i = 0; i < dataSolver; i++) {
17462 stringstream s;
17463 s.clear();
17464 s << fixed << setprecision(floatWidth) << surfaceValues[c * dataSolver + i];
17465 s.str().copy(&data[cnt], floatWidth);
17466 cnt += floatWidth;
17467 if(i < (dataSolver - 1))
17468 sprintf(&data[cnt], ", ");
17469 else
17470 sprintf(&data[cnt], " \n");
17471 cnt += 2;
17472 }
17473 }
17474 ASSERT(dataSize == cnt, "");
17475 ScratchSpace<MInt> dataPerDomain(noDomains(), AT_, "dataPerDomain");
17476 MPI_Allgather(&dataSize, 1, MPI_INT, &dataPerDomain[0], 1, MPI_INT, mpiComm(), AT_, "dataSize", "dataPerDomain[0]");
17477 MInt globalDataOffset = 0;
17478 for(MInt d = 0; d < domainId(); d++)
17479 globalDataOffset += dataPerDomain[d];
17480 MPI_File file = nullptr;
17481 MInt rcode = MPI_File_open(mpiComm(), const_cast<MChar*>(fileName.c_str()), MPI_MODE_CREATE | MPI_MODE_WRONLY,
17482 MPI_INFO_NULL, &file, AT_);
17483 if(rcode != MPI_SUCCESS) mTerm(1, AT_, "Error opening file " + fileName);
17484 MPI_Status status;
17485 // MPI_File_seek(file, globalDataOffset, MPI_SEEK_SET, AT_ );
17486 MPI_File_seek(file, globalDataOffset, MPI_SEEK_CUR, AT_);
17487 rcode = (counter > 0) ? MPI_File_write(file, &data[0], dataSize, MPI_CHAR, &status) : MPI_SUCCESS;
17488 if(rcode != MPI_SUCCESS) mTerm(1, AT_, "Error (1) writing to file " + fileName);
17489 MPI_File_close(&file, AT_);
17490 }
17491
17492 if(m_euler) {
17493 for(MInt i = 0; i < nDim; i++)
17494 forceCoefficients[i] = (pressure[i]) / (F1B2 * rhoU2);
17495 } else {
17496 for(MInt i = 0; i < nDim; i++) {
17497 forceCoefficients[i] = (shear[i] + pressure[i]) / (F1B2 * rhoU2);
17498 }
17499 if(m_periodicCells == 3) { // azimuthal periodicity concept
17500 for(MInt i = 0; i < nDim; i++)
17501 forceCoefficients[i] = (shear[i]) / (F1B2 * rhoU2) / (5.0) / (2.0 * PI * 0.5);
17502 }
17503 }
17504
17505 // exchange and sum up the local force coefficients
17506 if(m_periodicCells == 3) {
17507 MPI_Allreduce(localRetau, globalRetau, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localRetau", "globalRetau");
17508 MPI_Allreduce(localArea1, globalArea1, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "localArea1", "globalArea1");
17509
17510 globalRetau[0] =
17511 globalRetau[0] / globalArea1[0]; //( m_domainBoundaries[ 1 ]- m_domainBoundaries[ 0 ])/(2.0*PI*0.5);
17512 }
17513
17514 MPI_Reduce(forceCoefficients, globalForceCoefficients, nDim, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_,
17515 "forceCoefficients", "globalForceCoefficients");
17516 MPI_Bcast(globalForceCoefficients, nDim, MPI_DOUBLE, 0, mpiComm(), AT_, "globalForceCoefficients");
17517
17518 for(MInt i = 0; i < nDim; i++) {
17519 forceCoefficients[i] = globalForceCoefficients[i];
17520 }
17521
17522 MPI_Allreduce(MPI_IN_PLACE, &ypmin, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "ypmin");
17523 MPI_Allreduce(MPI_IN_PLACE, &ypmax, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "ypmax");
17524 MPI_Allreduce(MPI_IN_PLACE, &ypavg, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "ypavg");
17525 MPI_Allreduce(MPI_IN_PLACE, &yprms, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "yprms");
17526 MPI_Allreduce(MPI_IN_PLACE, &ypcnt, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "ypcnt");
17527
17528
17529 if(found_ && m_periodicCells == 3) // azimuthal periodicity concept
17530 {
17531 FILE* datei;
17532 datei = fopen("reTau_loc", "a+");
17533 fprintf(datei, "%d", globalTimeStep);
17534 fprintf(datei, " %f", Re_tau_);
17535 fprintf(datei, "\n");
17536 fclose(datei);
17537 }
17538
17539 if(domainId() == 0 && m_periodicCells == 3) { // azimuthal periodicity concept
17540 FILE* datei;
17541 datei = fopen("reTau", "a+");
17542 fprintf(datei, "%d", globalTimeStep);
17543 fprintf(datei, " %f", globalRetau[0]);
17544 fprintf(datei, "\n");
17545 fclose(datei);
17546 }
17547 // if ( domainId() == 0 && globalTimeStep%10 == 0 ) cerr << "yplus: min=" << ypmin << ", avg=" << ypavg/ypcnt << ",
17548 // rms=" << sqrt(yprms/ypcnt) << ", max=" << ypmax << "." << endl; if ( globalTimeStep % m_restartInterval == 0 )
17549 m_log << "yplus: min=" << ypmin << ", avg=" << ypavg / ypcnt << ", rms=" << sqrt(yprms / ypcnt) << ", max=" << ypmax
17550 << "." << endl;
17551}
17552
17553
17554//-----------------------------------------------------------------------------
17555
17556
17561template <MInt nDim_, class SysEqn>
17563 const MInt noPVars = PV->noVariables;
17564 if(m_extractedCells == nullptr) {
17565 cerr << "Extracted cells not allocated." << endl;
17566 return;
17567 }
17568 for(MInt c = 0; c < m_extractedCells->size(); c++) {
17569 MInt cellId = m_extractedCells->a[c].m_cellId;
17570 for(MInt dir = 0; dir < nDim; dir++) {
17571 MInt n0 = (a_hasNeighbor(cellId, 2 * dir) > 0) ? c_neighborId(cellId, 2 * dir) : cellId;
17572 MInt n1 = (a_hasNeighbor(cellId, 2 * dir + 1) > 0) ? c_neighborId(cellId, 2 * dir + 1) : cellId;
17573 for(MInt var = 0; var < noPVars; var++) {
17574 a_slope(cellId, var, dir) =
17575 (a_pvariable(n1, var) - a_pvariable(n0, var)) / mMax(1e-10, a_coordinate(n1, dir) - a_coordinate(n0, dir));
17576 }
17577 }
17578 }
17579}
17580
17581
17582//-----------------------------------------------------------------------------
17583
17584
17589template <MInt nDim_, class SysEqn>
17591 TRACE();
17592
17593 const MInt noPVars = PV->noVariables;
17594 const MBool needSlopes =
17595 (m_vtuQCriterionOutput || m_vtuVorticityOutput || m_vtuVelocityGradientOutput || m_vtuLambda2Output);
17596 if(m_extractedCells == nullptr) {
17597 cerr << "Extracted cells not allocated." << endl;
17598 return;
17599 }
17600
17601 if(m_vtuLevelThreshold < maxRefinementLevel()) {
17602 if(needSlopes && m_vtuLevelThreshold > maxUniformRefinementLevel()) {
17603 LSReconstructCellCenter();
17604 }
17605 for(MInt c = 0; c < m_extractedCells->size(); c++) {
17606 MInt cellId = m_extractedCells->a[c].m_cellId;
17607 if(c_noChildren(cellId) > 0 && a_level(cellId) == m_vtuLevelThreshold) {
17608 reduceData(cellId, &a_pvariable(0, 0), noPVars);
17609 }
17610 }
17611 if(needSlopes && m_vtuLevelThreshold <= maxUniformRefinementLevel()) {
17612 exchangeDataFV(&a_pvariable(0, 0), noPVars, false, m_rotIndVarsPV);
17613 computeSlopesByCentralDifferences();
17614 } else if(m_vtuWritePointData) {
17615 exchangeDataFV(&a_pvariable(0, 0), noPVars, false, m_rotIndVarsPV);
17616 }
17617 if(needSlopes) {
17618 for(MInt c = 0; c < m_extractedCells->size(); c++) {
17619 MInt cellId = m_extractedCells->a[c].m_cellId;
17620 if(c_noChildren(cellId) > 0 && a_level(cellId) == m_vtuLevelThreshold) {
17621 reduceData(cellId, &a_slope(0, 0, 0), noPVars * nDim);
17622 }
17623 }
17624 }
17625 }
17626 if(m_vtuWritePointData) {
17627 if(needSlopes) {
17628 // Rotation of slopes for azimuthal periodicity is not yet handled
17629 exchangeDataFV(&a_slope(0, 0, 0), noPVars * nDim, false);
17630 }
17631 }
17632}
17633
17634
17635//-----------------------------------------------------------------------------
17636
17637
17644template <MInt nDim_, class SysEqn>
17646 TRACE();
17647
17648 MBool debugOutput = m_domainIdOutput;
17649#ifdef _MB_DEBUG_
17650 debugOutput = true;
17651#endif
17652
17653 MBool jet = false;
17654 if(m_jet || m_confinedFlame) jet = true;
17655 m_levelSetOutput = m_levelSetOutput || (m_levelSet && !m_combustion && !m_levelSetMb);
17656
17657 MInt noCells;
17658 MInt noInternalCellIds;
17659 std::vector<MInt> recalcIdsSolver(0);
17660 std::vector<MInt> reOrderedCells(0);
17661 // << TODO labels:FVMB Without this IMHO memory-leaking but backward-compatible
17662 // move FVMB test case fails (LS/3D_minLevelIncrease)
17663 if(grid().newMinLevel() > 0) {
17664 m_recalcIds = nullptr;
17665 }
17666 // >>
17667 this->calcRecalcCellIdsSolver(m_recalcIds, noCells, noInternalCellIds, recalcIdsSolver, reOrderedCells);
17668 // a_noCells(), however pVariables need to be written in a different way then!
17669 noCells = (grid().newMinLevel() < 0) ? a_noCells() : reOrderedCells.size();
17670
17671 stringstream varFileName;
17672 stringstream backupFileName;
17673 const MInt noDbVariables =
17674 noCells
17675 * (PV->noVariables // primitive variables
17676 + (MInt)debugOutput * 2 // visualise window/halo-Cells and cellId
17677 + (MInt)m_levelSetRans + ((MInt)m_acousticAnalysis) * 3 // acoustics analysis variables
17678 + ((m_averageVorticity && m_movingAvgInterval == 0) || m_saveVorticityToRestart)
17679 * m_vorticitySize // vorticity variables
17680 + (MInt)m_restartOldVariables * CV->noVariables // dpdt
17681 + (MInt)m_localTS + (MInt)m_bodyIdOutput + (MInt)m_levelSetOutput
17682 + ((MInt)(isDetChem<SysEqn> && m_detChemExtendedOutput)) * 3
17683 + ((MInt)(isDetChem<SysEqn> && m_detChemExtendedOutput && m_acousticAnalysis)) * 4 + (MInt)m_wmLES * 2);
17684
17685 MBool addVarOut = m_localTS || m_bodyIdOutput || m_levelSetOutput;
17686 MFloatScratchSpace dbVariables(noDbVariables, AT_, "dbVariables");
17687 MFloatScratchSpace tmp(noCells * ((MInt)addVarOut), AT_, "tmp");
17688 MFloatScratchSpace tmpW(noCells * ((MInt)debugOutput), AT_, "tmpW");
17689 MFloatScratchSpace tmpDetChem(noCells * ((MInt)isDetChem<SysEqn>), AT_, "tmpDetChem");
17690
17691 const MInt noIdVariables = (MInt)m_isActiveOutput;
17692 MIntScratchSpace idVariables(noIdVariables, AT_, "idVariables");
17693 MIntScratchSpace tmpId(noCells * noIdVariables, AT_, "idVariables");
17694
17695 MInt writeRestartTimeBc2800 = 0;
17696 if(Context::propertyExists("modeType", m_solverId)) writeRestartTimeBc2800 = 1;
17697 MFloatScratchSpace dbParameters(writeRestartTimeBc2800 + 5 + 3 * (MInt)jet, AT_, "dbParameters");
17698 MIntScratchSpace idParameters(4, AT_, "idParameters");
17699 vector<MString> dbVariablesName;
17700 vector<MString> idVariablesName;
17701 vector<MString> dbParametersName;
17702 vector<MString> idParametersName;
17703 vector<MString> name;
17704
17705 for(MInt v = 0; v < PV->noVariables; v++) {
17706 name.push_back(m_variablesName[v]);
17707 }
17708
17709 if(grid().newMinLevel() < 0) {
17710 this->collectVariables(&a_pvariable(0, 0), dbVariables, name, dbVariablesName, PV->noVariables, a_noCells());
17711 } else {
17712 MFloat** variables = nullptr;
17713 const MInt noPVars = PV->noVariables;
17714 mAlloc(variables, noCells, noPVars, "variables", 0.0, AT_);
17715
17716 for(MInt cell = 0; cell < noCells; cell++) {
17717 for(MInt var = 0; var < noPVars; var++)
17718 variables[cell][var] = a_pvariable(reOrderedCells[cell], var);
17719 }
17720
17721 this->collectVariables(variables, dbVariables, name, dbVariablesName, noPVars, noCells);
17722 variables = nullptr;
17723 mDeallocate(variables);
17724 }
17725
17726 IF_CONSTEXPR(isDetChem<SysEqn>) {
17727 if(m_detChemExtendedOutput) {
17728 name.clear();
17729 name.push_back("RHO_E");
17730 if(grid().newMinLevel() < 0) {
17731 for(MInt cellId = 0; cellId < noCells; cellId++) {
17732 tmpDetChem[cellId] = a_variable(cellId, CV->RHO_E);
17733 }
17734 } else {
17735 for(MInt cellId = 0; cellId < noCells; cellId++) {
17736 tmpDetChem[cellId] = a_variable(reOrderedCells[cellId], CV->RHO_E);
17737 }
17738 }
17739 this->collectVariables(tmpDetChem.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17740
17741 name.clear();
17742 name.push_back("T");
17743 if(grid().newMinLevel() < 0) {
17744 for(MInt cellId = 0; cellId < noCells; cellId++) {
17745 tmpDetChem[cellId] = a_pvariable(cellId, PV->P) / m_gasConstant * a_avariable(cellId, AV->W_MEAN)
17746 / a_pvariable(cellId, PV->RHO);
17747 }
17748 } else {
17749 for(MInt cellId = 0; cellId < noCells; cellId++) {
17750 tmpDetChem[cellId] = a_pvariable(reOrderedCells[cellId], PV->P) / m_gasConstant
17751 * a_avariable(reOrderedCells[cellId], AV->W_MEAN)
17752 / a_pvariable(reOrderedCells[cellId], PV->RHO);
17753 }
17754 }
17755 this->collectVariables(tmpDetChem.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17756
17757 name.clear();
17758 name.push_back("HeatRelease");
17759 if(grid().newMinLevel() < 0) {
17760 for(MInt cellId = 0; cellId < noCells; cellId++) {
17761 if(a_isBndryGhostCell(cellId)) continue;
17762 const MFloat dampeningFactor = m_heatReleaseDamp ? m_dampFactor[cellId] : F1;
17763 tmpDetChem[cellId] = 0;
17764 for(MUint s = 0; s < PV->m_noSpecies; ++s) {
17765 tmpDetChem[cellId] -= dampeningFactor * a_speciesReactionRate(cellId, s) * m_standardHeatFormation[s];
17766 }
17767 }
17768 } else {
17769 for(MInt cellId = 0; cellId < noCells; cellId++) {
17770 if(a_isBndryGhostCell(cellId)) continue;
17771 const MFloat dampeningFactor = m_heatReleaseDamp ? m_dampFactor[cellId] : F1;
17772 tmpDetChem[cellId] = 0;
17773 for(MUint s = 0; s < PV->m_noSpecies; ++s) {
17774 tmpDetChem[cellId] -=
17775 dampeningFactor * a_speciesReactionRate(reOrderedCells[cellId], s) * m_standardHeatFormation[s];
17776 }
17777 }
17778 }
17779 this->collectVariables(tmpDetChem.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17780
17781 if(m_acousticAnalysis) {
17782 MFloatScratchSpace QeI(a_noCells(), AT_, "QeI");
17783 MFloatScratchSpace QeIII(a_noCells(), AT_, "QeIII");
17784 MFloatScratchSpace cSquared(a_noCells(), AT_, "cSquared");
17785 MFloatScratchSpace drhodt(a_noCells(), AT_, "drhodt");
17786
17787 computeAcousticSourceTermQe(QeI, QeIII, cSquared, drhodt);
17788
17789 name.clear();
17790 name.push_back("QeI");
17791 this->collectVariables(QeI.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17792
17793 name.clear();
17794 name.push_back("QeIII");
17795 this->collectVariables(QeIII.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17796
17797 name.clear();
17798 name.push_back("cSquared");
17799 this->collectVariables(cSquared.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17800
17801 name.clear();
17802 name.push_back("drhodt");
17803 this->collectVariables(drhodt.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17804 }
17805 }
17806 }
17807
17808 if(m_wmLES) {
17809 MFloat** wmVariables = nullptr;
17810 const MInt noWMVars = 2;
17811 mAlloc(wmVariables, noCells, noWMVars, "wmVariables", 0.0, AT_);
17812 name.clear();
17813 name.emplace_back("utau");
17814 name.emplace_back("u_II");
17815 for(MUint wmSrfcId = 0; wmSrfcId < m_wmSurfaces.size(); wmSrfcId++) {
17816 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
17817 const MInt cell = m_bndryCells->a[bndryCellId].m_cellId;
17818 wmVariables[cell][0] = m_wmSurfaces[wmSrfcId].m_wmUTAU;
17819 wmVariables[cell][1] = m_wmSurfaces[wmSrfcId].m_wmUII;
17820 }
17821 this->collectVariables(wmVariables, dbVariables, name, dbVariablesName, noWMVars, noCells);
17822 wmVariables = nullptr;
17823 mDeallocate(wmVariables);
17824 }
17825
17826 if(debugOutput) {
17827 name.clear();
17828 name.push_back("domainId");
17829 for(MInt i = 0; i < c_noCells(); i++) {
17830 if(a_isWindow(i)) {
17831 tmpW[i] = -domainId();
17832 } else {
17833 tmpW[i] = domainId();
17834 }
17835 }
17836 this->collectVariables(tmpW.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17837
17838 name.clear();
17839 name.push_back("globalId");
17840 for(MInt i = 0; i < c_noCells(); i++) {
17841 assertValidGridCellId(i);
17842 tmpW[i] = c_globalId(i);
17843 }
17844 for(MInt i = c_noCells(); i < noCells; i++) {
17845 tmpW[i] = -1;
17846 }
17847 this->collectVariables(tmpW.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17848 }
17849
17850 if(m_levelSetOutput) {
17851 name.clear();
17852 name.push_back("G");
17853 if(m_levelSetMb) {
17854 if(grid().newMinLevel() < 0) {
17855 for(MInt cellId = 0; cellId < noCells; cellId++) {
17856 tmp[cellId] = a_levelSetValuesMb(cellId, 0);
17857 }
17858 } else {
17859 for(MInt cellId = 0; cellId < noCells; cellId++) {
17860 tmp[cellId] = a_levelSetValuesMb(reOrderedCells[cellId], 0);
17861 }
17862 }
17863 } else {
17864 for(MInt i = 0; i < noCells; i++) {
17865 tmp[i] = a_levelSetFunction(i, 0);
17866 }
17867 }
17868 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17869 }
17870
17871 if(m_localTS) {
17872 name.clear();
17873 name.push_back("localTS");
17874 for(MInt cellId = 0; cellId < noCells; cellId++) {
17875 tmp[cellId] = a_localTimeStep(cellId);
17876 }
17877 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17878 }
17879
17880 if(m_levelSetRans) {
17881 name.clear();
17882 name.push_back("d");
17883 for(MInt cellId = 0; cellId < noCells; cellId++) {
17884 tmp[cellId] = a_levelSetFunction(cellId, 0);
17885 }
17886 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17887 }
17888
17889 if(m_bodyIdOutput) {
17890 ASSERT(m_levelSetMb, "");
17891 if(grid().newMinLevel() < 0) {
17892 for(MInt cellId = 0; cellId < noCells; cellId++) {
17893 tmp[cellId] = a_associatedBodyIds(cellId, 0);
17894 }
17895 } else {
17896 for(MInt cellId = 0; cellId < noCells; cellId++) {
17897 tmp[cellId] = a_associatedBodyIds(reOrderedCells[cellId], 0);
17898 }
17899 }
17900 name.clear();
17901 name.push_back("BodyId");
17902 this->collectVariables(tmp.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17903 }
17904
17905 if(m_isActiveOutput) {
17906 if(grid().newMinLevel() < 0) {
17907 for(MInt cellId = 0; cellId < noCells; cellId++) {
17908 tmpId[cellId] = (MInt)(!a_hasProperty(cellId, SolverCell::IsInactive));
17909 }
17910 } else {
17911 for(MInt cellId = 0; cellId < noCells; cellId++) {
17912 tmpId[cellId] = (MInt)(!a_hasProperty(reOrderedCells[cellId], SolverCell::IsInactive));
17913 }
17914 }
17915 name.clear();
17916 name.push_back("IsActive");
17917 this->collectVariables(tmpId.begin(), idVariables, name, idVariablesName, 1, noCells);
17918 }
17919
17920 if(m_combustion && m_acousticAnalysis) {
17921 IF_CONSTEXPR(!hasE<SysEqn>)
17922 mTerm(1, AT_, "Not compatible with SysEqn without RHO_E!");
17923 const MFloat gammaMinusOne = m_gamma - F1;
17924 const MFloat FgammaMinusOne = F1 / gammaMinusOne;
17925 MFloat reactionEnthalpy = (m_burntUnburntTemperatureRatio - F1) * FgammaMinusOne;
17926 MFloat FtimeStep = 1 / timeStep();
17927
17928 MFloatScratchSpace dPdT(noCells, AT_, "dPdT");
17929 MFloatScratchSpace dHdT(noCells, AT_, "dHdT");
17930 MFloatScratchSpace h(noCells, AT_, "h");
17931
17932 for(MInt cell = 0; cell < noCells; cell++) {
17933 dPdT[cell] = F0;
17934 dHdT[cell] = F0;
17935 h[cell] = F0;
17936
17937 if(!a_hasProperty(cell, SolverCell::IsOnCurrentMGLevel)) continue;
17938
17939 // compute the velocities
17940 MFloat velPOW2 = F0;
17941 for(MInt i = 0; i < nDim; i++) {
17942 velPOW2 += POW2(a_oldVariable(cell, CV->RHO_VV[i]));
17943 }
17944
17945 dPdT[cell] = a_pvariable(cell, 3);
17946 // compute primitive old pressure from conservative variables
17947 const MFloat pold = sysEqn().pressure(a_oldVariable(cell, CV->RHO), velPOW2, a_oldVariable(cell, CV->RHO_E));
17948
17949 dPdT[cell] -= pold;
17950 dPdT[cell] *= FtimeStep;
17951
17952 h[cell] = a_reactionRate(cell, 0);
17953 h[cell] *= a_cellVolume(cell) * reactionEnthalpy;
17954 dHdT[cell] = a_reactionRate(cell, 0);
17955 dHdT[cell] -= a_reactionRateBackup(cell, 0);
17956 dHdT[cell] *= a_cellVolume(cell) * reactionEnthalpy;
17957 dHdT[cell] *= FtimeStep;
17958 }
17959
17960 stringstream dPdTname;
17961 stringstream dHdTname;
17962 stringstream hName;
17963 dPdTname << "dPdT";
17964 dHdTname << "dHdT";
17965 hName << "h";
17966 name.clear();
17967 name.push_back(dPdTname.str());
17968 this->collectVariables(dPdT.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17969 name.clear();
17970 name.push_back(dHdTname.str());
17971 this->collectVariables(dHdT.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17972 name.clear();
17973 name.push_back(hName.str());
17974 this->collectVariables(h.begin(), dbVariables, name, dbVariablesName, 1, noCells);
17975 }
17976
17977 setRestartFileOutputTimeStep();
17978
17979 this->collectParameters(m_noSamples, idParameters, "noSamples", idParametersName);
17980 this->collectParameters(globalTimeStep, idParameters, "globalTimeStep", idParametersName);
17981 if(m_outputPhysicalTime) {
17982 this->collectParameters(m_physicalTime, dbParameters, "time", dbParametersName);
17983 } else {
17984 this->collectParameters(m_time, dbParameters, "time", dbParametersName);
17985 }
17986 this->collectParameters(m_restartFileOutputTimeStep, dbParameters, "timeStep", dbParametersName);
17987 this->collectParameters(m_noTimeStepsBetweenSamples, idParameters, "noTimeStepsBetweenSamples", idParametersName);
17988 this->collectParameters(m_physicalTime, dbParameters, "physicalTime", dbParametersName);
17989 this->collectParameters((MInt)m_forcing, idParameters, "forcing", idParametersName);
17990 if(writeRestartTimeBc2800 != 0) {
17991 this->collectParameters(m_restartTimeBc2800, dbParameters, "restartTimeBc2800", dbParametersName);
17992 }
17993
17994 if(m_jet || m_confinedFlame) {
17995 this->collectParameters(m_jetDensity, dbParameters, "jetDensity", dbParametersName);
17996 this->collectParameters(m_jetPressure, dbParameters, "jetPressure", dbParametersName);
17997 this->collectParameters(m_jetTemperature, dbParameters, "jetTemperature", dbParametersName);
17998 }
17999
18000 // Add vorticity to restart file
18001 if((m_averageVorticity && m_movingAvgInterval == 0) || m_saveVorticityToRestart) {
18002 MFloatScratchSpace vorticity(noCells * m_vorticitySize, AT_, "vorticity");
18003 getVorticity(&vorticity[0]);
18004 name.clear();
18005 for(MInt i = 0; i < m_vorticitySize; i++) {
18006 name.push_back(m_vorticityName[i]);
18007 }
18008 this->collectVariables(vorticity.begin(), dbVariables, name, dbVariablesName, m_vorticitySize, noCells, true);
18009 }
18010
18011 // Store oldVariables in restart file if requested in property file
18012 if(m_restartOldVariables) {
18013 // Prepare buffers
18014 MFloatScratchSpace oldRhoE(noCells, AT_, "oldRhoE");
18015 MFloatScratchSpace oldRhoU(noCells, AT_, "oldRhoU");
18016 MFloatScratchSpace oldRhoV(noCells, AT_, "oldRhoV");
18017 MFloatScratchSpace oldRhoW(nDim == 3 ? noCells : 1, AT_, "oldRhoW");
18018 MFloatScratchSpace oldRho(noCells, AT_, "oldRho");
18019
18020 // Copy data to buffers
18021 IF_CONSTEXPR(nDim == 3) {
18022 // 3D version
18023 for(MInt c = 0; c < noCells; c++) {
18024 IF_CONSTEXPR(hasE<SysEqn>)
18025 oldRhoE[c] = a_oldVariable(c, CV->RHO_E);
18026 oldRhoU[c] = a_oldVariable(c, CV->RHO_VV[0]);
18027 oldRhoV[c] = a_oldVariable(c, CV->RHO_VV[1]);
18028 oldRhoW[c] = a_oldVariable(c, CV->RHO_VV[2]);
18029 oldRho[c] = a_oldVariable(c, CV->RHO);
18030 }
18031 }
18032 else {
18033 // 2D version
18034 for(MInt c = 0; c < noCells; c++) {
18035 IF_CONSTEXPR(hasE<SysEqn>)
18036 oldRhoE[c] = a_oldVariable(c, CV->RHO_E);
18037 oldRhoU[c] = a_oldVariable(c, CV->RHO_VV[0]);
18038 oldRhoV[c] = a_oldVariable(c, CV->RHO_VV[1]);
18039 oldRho[c] = a_oldVariable(c, CV->RHO);
18040 }
18041 }
18042
18043 // Collect data
18044 name.clear();
18045 name.push_back("oldRhoE");
18046 this->collectVariables(oldRhoE.begin(), dbVariables, name, dbVariablesName, 1, noCells);
18047 name.clear();
18048 name.push_back("oldRhoU");
18049 this->collectVariables(oldRhoU.begin(), dbVariables, name, dbVariablesName, 1, noCells);
18050 name.clear();
18051 name.push_back("oldRhoV");
18052 this->collectVariables(oldRhoV.begin(), dbVariables, name, dbVariablesName, 1, noCells);
18053 IF_CONSTEXPR(nDim == 3) {
18054 name.clear();
18055 name.push_back("oldRhoW");
18056 this->collectVariables(oldRhoW.begin(), dbVariables, name, dbVariablesName, 1, noCells);
18057 }
18058 name.clear();
18059 name.push_back("oldRho");
18060 this->collectVariables(oldRho.begin(), dbVariables, name, dbVariablesName, 1, noCells);
18061 }
18062
18063 MInt* pointerRecalcIds = (m_recalcIds == nullptr) ? nullptr : recalcIdsSolver.data();
18064
18065 if(m_useNonSpecifiedRestartFile) {
18066 if(writeBackup) {
18067 // write a backup restart file
18068 backupFileName << outputDir() << "restartVariablesBackup_" << globalTimeStep << ParallelIo::fileExt();
18069
18070 cerr0 << "writing flow variables (backup) for the fv-solver... ";
18071
18072 saveGridFlowVarsPar((backupFileName.str()).c_str(), noCells, noInternalCellIds, dbVariables, dbVariablesName, 0,
18073 idVariables, idVariablesName, 0, dbParameters, dbParametersName, idParameters,
18074 idParametersName, pointerRecalcIds);
18075
18076 cerr0 << "ok" << endl;
18077 }
18078 varFileName << outputDir() << "restartVariables" << ParallelIo::fileExt();
18079 struct stat buffer {};
18080 if(stat((varFileName.str()).c_str(), &buffer) == 0) {
18081 // restart already exists rename to current timestep backup
18082 std::rename(varFileName.str().c_str(), (varFileName.str() + to_string(globalTimeStep) + "backup").c_str());
18083 }
18084 } else {
18085 if(!isMultilevel()) {
18086 varFileName << outputDir() << "restartVariables" << getIdentifier(m_multipleFvSolver, "", "") << "_"
18087 << globalTimeStep << ParallelIo::fileExt();
18088 } else {
18089 // For multilevel, use solver-specific file name for restart files
18090 const MInt maxLength = 256;
18091 array<MChar, maxLength> buffer{};
18092 snprintf(buffer.data(), maxLength, "restart_b%02d_t%08d", solverId(), globalTimeStep);
18093 varFileName << outputDir() << MString(buffer.data()) << ParallelIo::fileExt();
18094 }
18095 }
18096
18097 saveGridFlowVarsPar((varFileName.str()).c_str(), noCells, noInternalCellIds, dbVariables, dbVariablesName, 0,
18098 idVariables, idVariablesName, 0, dbParameters, dbParametersName, idParameters, idParametersName,
18099 pointerRecalcIds);
18100
18101 if(domainId() == 0) cerr << "ok" << endl;
18102}
18103
18104//-----------------------------------------------------------------------------
18105
18112template <MInt nDim_, class SysEqn>
18114 stringstream gridFile;
18115 stringstream gridFilePath;
18116 gridFile << "grid_" << globalTimeStep << ".Netcdf";
18117 gridFilePath << outputDir() << "grid_" << globalTimeStep << ".Netcdf";
18118 MIntScratchSpace recalcIds(grid().raw().treeb().size(), AT_, "recalcIds");
18119
18120 grid().raw().saveGrid((gridFilePath.str()).c_str(), recalcIds.begin());
18121
18122 writeRestartFile(true, false, (gridFile.str()).c_str(), recalcIds.begin());
18123}
18124
18131template <MInt nDim_, class SysEqn>
18133 TRACE();
18134
18135 {
18136 stringstream varFileName; // gridFileName
18137 //---
18138
18139 if(m_useNonSpecifiedRestartFile) {
18140 // gridFileName << restartDir() << "restartGrid_" << domainId() << ParallelIo::fileExt();
18141 if(m_multipleFvSolver) {
18142 varFileName << restartDir() << "restartVariables" << m_solverId << ParallelIo::fileExt();
18143 } else {
18144 varFileName << restartDir() << "restartVariables" << ParallelIo::fileExt();
18145 }
18146 } else {
18147 // TODO labels:FV,toremove remove this, globalTimeStep should not be changed by any solver!
18148 globalTimeStep = m_restartTimeStep;
18149
18150 // gridFileName << restartDir() << "restartGrid_" << globalTimeStep << "_" << domainId() <<
18151 // ParallelIo::fileExt();
18152 if(!isMultilevel()) {
18153 if(m_multipleFvSolver) {
18154 varFileName << restartDir() << "restartVariables" << m_solverId << "_" << globalTimeStep
18155 << ParallelIo::fileExt();
18156 } else {
18157 varFileName << restartDir() << "restartVariables_" << globalTimeStep << ParallelIo::fileExt();
18158 }
18159 } else {
18160 // For multilevel, use solver-specific file name for restart files
18161 const MInt maxLength = 256;
18162 array<MChar, maxLength> buffer{};
18163 snprintf(buffer.data(), maxLength, "restart_b%02d_t%08d", solverId(), globalTimeStep);
18164 varFileName << restartDir() << MString(buffer.data()) << ParallelIo::fileExt();
18165 }
18166 }
18167
18168 m_log << "loading primitive variables ... ";
18169 loadGridFlowVarsPar((varFileName.str()).c_str());
18170
18171 // Load oldVariable data
18172 if(m_restartOldVariables && !m_restartOldVariablesReset) {
18173 m_log << "loading old variables..." << endl;
18174 loadOldVariables(varFileName.str());
18175 }
18176
18177 if(!m_resetInitialCondition) {
18178 if(!m_useNonSpecifiedRestartFile) {
18179 if(globalTimeStep != m_restartTimeStep) {
18180 stringstream errorMessage;
18181 m_log << "globalTimeStep unequal m_restartTimeStep!" << endl;
18182 m_log << "globalTimeStep = " << globalTimeStep << " and m_restartTimeStep = " << m_restartTimeStep << endl;
18183 m_log << "abort!" << endl;
18184 errorMessage << "globalTimeStep unequal m_restartTimeStep!" << endl;
18185 errorMessage << "globalTimeStep = " << globalTimeStep << " and m_restartTimeStep = " << m_restartTimeStep
18186 << endl;
18187 errorMessage << "abort!" << endl;
18188 // mTerm(1,AT_,errorMessage.str());
18189 }
18190 } else {
18191 m_restartTimeStep = globalTimeStep;
18192 // stringstream backupFileName;
18193 // backupFileName << "cp " << varFileName.str() << " " << restartDir() << "restartVariables_" << globalTimeStep
18194 // << ParallelIo::fileExt(); system( (backupFileName.str()).c_str() );
18195 }
18196 }
18197 m_log << "ok" << endl;
18198
18199 exchangeAll();
18200
18201 if(m_changeMa) {
18202 m_log << "convert primitive restart variables ( " << m_previousMa << " ) to the Mach number " << m_Ma << "..."
18203 << endl;
18204 convertPrimitiveRestartVariables();
18205 m_log << "ok" << endl;
18206 }
18207 if(m_combustion) { // needed when level set grid is not matching the flow grid at the boundaries
18208 computePrimitiveVariablesCoarseGrid(noInternalCells());
18209 // needed if you use more than two layers
18210 exchangeAll();
18211 computePrimitiveVariablesCoarseGrid();
18212 }
18213
18214 m_log << "computing conservative variables (only on internal cells)... "; // will be updated on all active cells
18215 // (halo cells included) in the
18216 // RungeKutta constructor
18217 computeConservativeVariables();
18218 m_log << "ok" << endl;
18219
18220 if(m_restartOldVariables && m_restartOldVariablesReset) {
18221 m_log << "Resetting old variables..." << endl;
18222 if(domainId() == 0) std::cout << "FVSolver: Resetting old variables..." << endl;
18223
18224 std::copy_n(&a_variable(0, 0), a_noCells() * CV->noVariables, &a_oldVariable(0, 0));
18225 }
18226
18227 if(m_outputPhysicalTime) {
18228 m_log << "restart at time step: " << globalTimeStep << " - solution physical time: " << m_physicalTime << endl;
18229 } else {
18230 m_log << "restart at time step: " << globalTimeStep << " - solution time: " << m_time << endl;
18231 }
18232 m_log << m_noSamples << " samples read" << endl;
18233
18235 }
18236}
18237
18238
18245template <MInt nDim_, class SysEqn>
18247 TRACE();
18248
18249 IF_CONSTEXPR(nDim != 2 && nDim != 3) {
18250 cerr << " In global function loadGridFlowVarsPar: wrong number of "
18251 "dimensions !"
18252 << endl;
18253 mTerm(1, AT_);
18254 return;
18255 }
18256
18257 // File loading.
18258 stringstream variables;
18259
18260 using namespace maia;
18261 using namespace parallel_io;
18262 ParallelIo parallelIo(fileName, maia::parallel_io::PIO_READ, mpiComm());
18263
18264 // This should be the same for all the variables
18265 ParallelIo::size_type dimLen = noInternalCells();
18266 ParallelIo::size_type start = domainOffset(domainId()) - grid().bitOffset();
18267
18268 // set offset for all read operations
18269 parallelIo.setOffset(dimLen, start);
18270
18271 // load variable names
18272 static constexpr MInt maxVariables = 128;
18273 array<MString, maxVariables> varNames;
18274
18275 for(MInt vId = 0; vId < maxVariables; vId++) {
18276 MString varName = "variables" + to_string(vId);
18277
18278 if(!parallelIo.hasDataset(varName)) {
18279 break;
18280 }
18281
18282 MString tmp;
18283 parallelIo.getAttribute(&tmp, "name", varName);
18284 varNames[vId] = tmp;
18285 }
18286
18287 auto varPosition = [&](const MString& _varName) {
18288 auto it = find(varNames.begin(), varNames.end(), _varName);
18289 if(it == varNames.end()) {
18290 mTerm(-1, "Couldn't find variable with name " + _varName + " for solver " + to_string(m_solverId));
18291 }
18292 return "variables" + to_string(distance(varNames.begin(), it));
18293 };
18294
18295 auto hasVar = [&](const MString& _varName) {
18296 auto it = find(varNames.begin(), varNames.end(), _varName);
18297 return !(it == varNames.end());
18298 };
18299
18300 // Load our variables
18301 MFloatScratchSpace tmpVar((MInt)dimLen, AT_, "tmpVar");
18302
18303 // Velocity u
18304 parallelIo.readArray(tmpVar.getPointer(), varPosition("u"));
18305 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18306 a_pvariable(i, PV->U) = tmpVar.p[i];
18307 }
18308
18309 // Velocity v
18310 parallelIo.readArray(tmpVar.getPointer(), varPosition("v"));
18311 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18312 a_pvariable(i, PV->V) = tmpVar.p[i];
18313 }
18314
18315 // Density rho
18316 parallelIo.readArray(tmpVar.getPointer(), varPosition("rho"));
18317 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18318 a_pvariable(i, PV->RHO) = tmpVar.p[i];
18319 }
18320
18321 // pressure p
18322 parallelIo.readArray(tmpVar.getPointer(), varPosition("p"));
18323 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18324 a_pvariable(i, PV->P) = tmpVar.p[i];
18325 }
18326
18327 // RANS
18328 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18329 for(MInt r = 0; r < m_noRansEquations; r++) {
18330 parallelIo.readArray(tmpVar.getPointer(), varPosition(m_variablesName[nDim + 2 + r]));
18331 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18332 a_pvariable(i, PV->NN[r]) = tmpVar.p[i];
18333 }
18334 }
18335 }
18336
18337 if(m_combustion) {
18338 if(m_noSpecies > 1) {
18339 mTerm(-1, "code is incorrect!");
18340 }
18341
18342 // species
18343 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
18344 if(m_noSpecies == 1) {
18345 parallelIo.readArray(tmpVar.getPointer(), varPosition("c"));
18346 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18347 a_pvariable(i, PV->C) = tmpVar.p[i];
18348 }
18349 }
18350 if(m_statisticCombustionAnalysis) {
18351 // heat release rate
18352 parallelIo.readArray(tmpVar.getPointer(), varPosition("h"));
18353 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18354 m_heatRelease[i] = tmpVar.p[i];
18355 }
18356 }
18357 } else {
18358 if(m_localTS && hasVar("localTS")) {
18359 parallelIo.readArray(tmpVar.getPointer(), varPosition("localTS"));
18360 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18361 a_localTimeStep(i) = tmpVar.p[i];
18362 }
18363 }
18364 if(m_noSpecies == 1 && hasVar("Y")) {
18365 parallelIo.readArray(tmpVar.getPointer(), varPosition("Y"));
18366 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18367 a_pvariable(i, PV->Y[0]) = tmpVar.p[i];
18368 }
18369 } else {
18370 for(MInt s = 0; s < m_noSpecies; s++) {
18371 MString tmpString = "Y" + m_speciesName[s];
18372 if(hasVar(tmpString)) {
18373 parallelIo.readArray(tmpVar.getPointer(), varPosition(tmpString));
18374 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18375 a_pvariable(i, PV->Y[s]) = tmpVar.p[i];
18376 }
18377 }
18378 }
18379 }
18380 }
18381
18382 IF_CONSTEXPR(nDim == 3) {
18383 // Velocity w
18384 parallelIo.readArray(tmpVar.getPointer(), varPosition("w"));
18385 for(MInt i = 0; i < (MInt)dimLen; ++i) {
18386 a_pvariable(i, PV->W) = tmpVar.p[i];
18387 }
18388
18389 // Load vorticity data if used for averaging (but not for moving average)
18390 if(m_loadSampleVariables && m_averageVorticity && m_movingAvgInterval == 0) {
18391 mTerm(-666, "fix calls see above");
18392
18393 parallelIo.readArray(&m_vorticity[0][0], "variables5", 3);
18394 parallelIo.readArray(&m_vorticity[0][1], "variables6", 3);
18395 parallelIo.readArray(&m_vorticity[0][2], "variables7", 3);
18396 }
18397 }
18398 else {
18399 // Load vorticity data if used for averaging (but not for moving average)
18400 if(m_loadSampleVariables && m_averageVorticity && m_movingAvgInterval == 0) {
18401 mTerm(-666, "fix calls see above");
18402 parallelIo.readArray(&m_vorticity[0][0], "variables4");
18403 }
18404 }
18405
18406 // Getting solution parameters.
18407 parallelIo.getAttribute(&m_noSamples, "noSamples");
18408
18409 if(!m_resetInitialCondition) {
18410 parallelIo.getAttribute(&globalTimeStep, "globalTimeStep");
18411 if(m_outputPhysicalTime) {
18412 parallelIo.getAttribute(&m_physicalTime, "time");
18413 } else {
18414 parallelIo.getAttribute(&m_time, "time");
18415 }
18416 parallelIo.getAttribute(&m_timeStep, "timeStep");
18417 parallelIo.getAttribute(&m_physicalTime, "physicalTime");
18418 }
18419
18420 if(useTimeStepFromRestartFile() && approx(timeStep(), -1., m_eps)) {
18421 mTerm(1, AT_,
18422 "the time-step from the restart file will be used but its equal to -1. That might not do what you think "
18423 "it "
18424 "does...");
18425 }
18426
18427 if(m_restartBc2800) {
18428 parallelIo.getAttribute(&m_restartTimeBc2800, "restartTimeBc2800");
18429 }
18430
18431 parallelIo.getAttribute(&m_noTimeStepsBetweenSamples, "noTimeStepsBetweenSamples");
18432
18433 // ncmpi_inq_varid(ncId, "forcing", &varId);
18434 // ncmpi_get_vara_int_all(ncId, varId, &start, &cnt, &m_forcing);
18435
18436 if(parallelIo.hasAttribute("meanPressure")) {
18437 parallelIo.getAttribute(&m_meanPressure, "meanPressure");
18438 m_log << "meanPressure is" << m_meanPressure << endl;
18439 }
18440
18441 if(m_jet || m_confinedFlame) {
18442 parallelIo.getAttribute(&m_jetDensity, "jetDensity");
18443 m_log << "jetDensity is" << m_jetDensity << endl;
18444
18445 parallelIo.getAttribute(&m_jetPressure, "jetPressure");
18446 m_log << "jetPressure is" << m_jetPressure << endl;
18447
18448 parallelIo.getAttribute(&m_jetTemperature, "jetTemperature");
18449 m_log << "jetTemperature is" << m_jetTemperature << endl;
18450 }
18451
18452 if(parallelIo.hasAttribute("Re", "")) {
18453 parallelIo.getAttribute(&m_Re, "Re");
18454 parallelIo.getAttribute(&sysEqn().m_Re0, "Re0");
18455 parallelIo.getAttribute(&m_randomDeviceSeed, "randomDeviceSeed");
18456 if(domainId() == 0) m_log << "Read Reynolds number: " << m_Re << " (" << sysEqn().m_Re0 << ")." << endl;
18457 }
18458
18460}
18461
18462
18465template <MInt nDim_, class SysEqn>
18467 TRACE();
18468 IF_CONSTEXPR(!hasE<SysEqn>)
18469 mTerm(1, AT_, "Not compatible with SysEqn without RHO_E!");
18470
18471 ParallelIo parallelIo(fileName, maia::parallel_io::PIO_READ, mpiComm());
18472 parallelIo.setOffset(noInternalCells(), domainOffset(domainId()));
18473
18474 MFloatScratchSpace buffer(noInternalCells(), AT_, "buffer");
18475 IF_CONSTEXPR(nDim == 2) {
18476 // rho*e
18477 parallelIo.readArray(&buffer[0], "variables7");
18478 for(MInt i = 0; i < noInternalCells(); i++) {
18479 a_oldVariable(i, CV->RHO_E) = buffer[i];
18480 }
18481 // rho*u
18482 parallelIo.readArray(&buffer[0], "variables8");
18483 for(MInt i = 0; i < noInternalCells(); i++) {
18484 a_oldVariable(i, CV->RHO_VV[0]) = buffer[i];
18485 }
18486 // rho*v
18487 parallelIo.readArray(&buffer[0], "variables9");
18488 for(MInt i = 0; i < noInternalCells(); i++) {
18489 a_oldVariable(i, CV->RHO_VV[1]) = buffer[i];
18490 }
18491 // rho
18492 parallelIo.readArray(&buffer[0], "variables10");
18493 for(MInt i = 0; i < noInternalCells(); i++) {
18494 a_oldVariable(i, CV->RHO) = buffer[i];
18495 }
18496
18497 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18498 for(MInt rans = 1; rans < (m_noRansEquations + 1); rans++) {
18499 MString varname = "variables" + to_string(10 + rans);
18500 parallelIo.readArray(&buffer[0], varname);
18501 for(MInt i = 0; i < noInternalCells(); i++) {
18502 a_oldVariable(i, CV->RHO_NN[rans]) = buffer[i];
18503 }
18504 }
18505 }
18506 }
18507 else IF_CONSTEXPR(nDim == 3) {
18508 // rho*e
18509 parallelIo.readArray(&buffer[0], "variables8");
18510 for(MInt i = 0; i < noInternalCells(); i++) {
18511 a_oldVariable(i, CV->RHO_E) = buffer[i];
18512 }
18513 // rho*u
18514 parallelIo.readArray(&buffer[0], "variables9");
18515 for(MInt i = 0; i < noInternalCells(); i++) {
18516 a_oldVariable(i, CV->RHO_VV[0]) = buffer[i];
18517 }
18518 // rho*v
18519 parallelIo.readArray(&buffer[0], "variables10");
18520 for(MInt i = 0; i < noInternalCells(); i++) {
18521 a_oldVariable(i, CV->RHO_VV[1]) = buffer[i];
18522 }
18523 // rho*w
18524 parallelIo.readArray(&buffer[0], "variables11");
18525 for(MInt i = 0; i < noInternalCells(); i++) {
18526 a_oldVariable(i, CV->RHO_VV[2]) = buffer[i];
18527 }
18528 // rho
18529 parallelIo.readArray(&buffer[0], "variables12");
18530 for(MInt i = 0; i < noInternalCells(); i++) {
18531 a_oldVariable(i, CV->RHO) = buffer[i];
18532 }
18533 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
18534 for(MInt rans = 1; rans < (m_noRansEquations + 1); rans++) {
18535 MString varname = "variables" + to_string(12 + rans);
18536 parallelIo.readArray(&buffer[0], varname);
18537 for(MInt i = 0; i < noInternalCells(); i++) {
18538 a_oldVariable(i, CV->RHO_NN[rans]) = buffer[i];
18539 }
18540 }
18541 }
18542 }
18543 else {
18544 mTerm(1, "bad number of dimensions");
18545 }
18546}
18547
18548template <MInt nDim_, class SysEqn>
18550 TRACE();
18551
18552 m_log << "Reading WM Surface data from restart file ...";
18553
18554 using namespace maia;
18555 using namespace parallel_io;
18556
18557 // This should be the same of the function calling this and providing tmpVar
18558 ParallelIo::size_type dimLen = noInternalCells();
18559 ParallelIo::size_type start = domainOffset(domainId()) - grid().bitOffset();
18560
18561
18562 stringstream varFileName;
18563
18564 if(m_useNonSpecifiedRestartFile) {
18565 // gridFileName << restartDir() << "restartGrid_" << domainId() << ParallelIo::fileExt();
18566 if(m_multipleFvSolver) {
18567 varFileName << restartDir() << "restartVariables" << m_solverId << ParallelIo::fileExt();
18568 } else {
18569 varFileName << restartDir() << "restartVariables" << ParallelIo::fileExt();
18570 }
18571 } else {
18572 if(!isMultilevel()) {
18573 if(m_multipleFvSolver) {
18574 varFileName << restartDir() << "restartVariables" << m_solverId << "_" << m_restartTimeStep
18575 << ParallelIo::fileExt();
18576 } else {
18577 varFileName << restartDir() << "restartVariables_" << m_restartTimeStep << ParallelIo::fileExt();
18578 }
18579 } else {
18580 // For multilevel, use solver-specific file name for restart files
18581 const MInt maxLength = 256;
18582 array<MChar, maxLength> buffer{};
18583 snprintf(buffer.data(), maxLength, "restart_b%02d_t%08d", solverId(), m_restartTimeStep);
18584 varFileName << restartDir() << MString(buffer.data()) << ParallelIo::fileExt();
18585 }
18586 }
18587
18588 ParallelIo parallelIo(varFileName.str().c_str(), maia::parallel_io::PIO_READ, mpiComm());
18589
18590 // set offset for all read operations
18591 parallelIo.setOffset(dimLen, start);
18592
18593 // load variable names :
18594 static constexpr MInt maxVariables(128);
18595 array<MString, maxVariables> varNames;
18596
18597 for(MInt vId = 0; vId < maxVariables; vId++) {
18598 MString varName = "variables" + to_string(vId);
18599
18600 if(!parallelIo.hasDataset(varName)) {
18601 break;
18602 }
18603 MString tmp;
18604 parallelIo.getAttribute(&tmp, "name", varName);
18605 varNames[vId] = tmp;
18606 }
18607
18608 auto varPosition = [&](const MString& _varName) {
18609 auto it = find(varNames.begin(), varNames.end(), _varName);
18610 if(it == varNames.end()) {
18611 mTerm(-1, "Couldn't find variable with name " + _varName + " for solver " + to_string(m_solverId));
18612 }
18613 return "variables" + to_string(distance(varNames.begin(), it));
18614 };
18615
18616 /*
18617 auto hasVar = [&](const MString& _varName) {
18618 auto it = find(varNames.begin(), varNames.end(), _varName);
18619 return !(it == varNames.end());
18620 };
18621 */
18622
18623 // load out variables
18624 MFloatScratchSpace tmpVar((MInt)dimLen, AT_, "tmpVar");
18625
18626 // shear velocity utau
18627 parallelIo.readArray(tmpVar.getPointer(), varPosition("utau"));
18628 for(MUint wmSrfcId = 0; wmSrfcId < m_wmSurfaces.size(); wmSrfcId++) {
18629 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
18630 const MInt cellId = m_bndryCells->a[bndryCellId].m_cellId;
18631 m_wmSurfaces[wmSrfcId].m_wmUTAU = tmpVar.p[cellId];
18632 }
18633
18634 // parallel velocity u_II
18635 parallelIo.readArray(tmpVar.getPointer(), varPosition("u_II"));
18636 for(MUint wmSrfcId = 0; wmSrfcId < m_wmSurfaces.size(); wmSrfcId++) {
18637 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
18638 const MInt cellId = m_bndryCells->a[bndryCellId].m_cellId;
18639 m_wmSurfaces[wmSrfcId].m_wmUII = tmpVar.p[cellId];
18640 }
18641
18642 m_log << " done." << endl;
18643}
18644
18645
18648
18654template <MInt nDim_, class SysEqn>
18656 // TRACE();
18657 const MUint noPVars = PV->noVariables;
18658 const MUint totalNoSlopes = nDim * noPVars * a_noCells();
18659 MFloat* const RESTRICT slopes = ALIGNED_MF(&a_slope(0, 0, 0));
18660 const MInt* const RESTRICT recCellIds = ALIGNED_I(m_reconstructionCellIds.data());
18661 const MInt* const RESTRICT recNghbrIds = ALIGNED_I(m_reconstructionNghbrIds.data());
18662 const MFloat* const RESTRICT cellCoord = ALIGNED_F(&a_coordinate(0, 0));
18663
18664 {
18665// Reset slopes to zero:
18666#ifdef _OPENMP
18667#pragma omp parallel for
18668#endif
18669 for(MUint slopeId = 0; slopeId < totalNoSlopes; ++slopeId) {
18670 slopes[slopeId] = F0;
18671 }
18672
18673 // Compute slopes:
18674 for(MUint k = 0; k < m_reconstructionDataSize; ++k) {
18675 const MFloat* const RESTRICT recNghbrVars = ALIGNED_F(&a_pvariable(recNghbrIds[k], 0));
18676 const MFloat* const RESTRICT recCellVars = ALIGNED_F(&a_pvariable(recCellIds[k], 0));
18677 const MUint slopeId = nDim * noPVars * recCellIds[k];
18678 for(MUint v = 0; v < noPVars; ++v) {
18679 const MFloat tmp = recNghbrVars[v] - recCellVars[v];
18680 slopes[slopeId + v * nDim] += m_reconstructionConstants[nDim * k] * tmp;
18681 slopes[slopeId + v * nDim + 1] += m_reconstructionConstants[nDim * k + 1] * tmp;
18682 IF_CONSTEXPR(nDim == 3) slopes[slopeId + v * nDim + 2] += m_reconstructionConstants[nDim * k + 2] * tmp;
18683 }
18684 }
18685
18686 if(m_reConstSVDWeightMode == 3) {
18687 for(MInt cellId = 0; cellId < a_noCells(); ++cellId) {
18688 if(!a_hasProperty(cellId, SolverCell::HasCoarseNghbr)) {
18689 continue;
18690 }
18691 const MFloat* const RESTRICT recCellVars = ALIGNED_F(&a_pvariable(0, 0) + noPVars * cellId);
18692 const MUint slopeId = nDim * noPVars * cellId;
18693 std::array<MBool, nDim> dirsJmp = {};
18694 for(MInt d = 0; d < nDim; ++d) {
18695 if(m_cells.nghbrInterface(cellId, 2 * d) == 3 || m_cells.nghbrInterface(cellId, 2 * d + 1) == 3) {
18696 dirsJmp[d] = true;
18697 } else {
18698 dirsJmp[d] = false;
18699 }
18700 }
18701
18702 const MUint cc1 = cellId * nDim;
18703 const MFloat* const RESTRICT cellIdCoord = ALIGNED_F(cellCoord + cc1);
18704 for(MUint v = 0; v < noPVars; ++v) {
18705 for(MInt d = 0; d < nDim; ++d) {
18706 if(dirsJmp[d]) {
18707 slopes[slopeId + v * nDim + d] = 0.0;
18708 }
18709 }
18710 }
18711
18712 for(MInt k = a_reconstructionData(cellId); k < a_reconstructionData(cellId + 1); ++k) {
18713 const MFloat* const RESTRICT recNghbrVars = ALIGNED_F(&a_pvariable(0, 0) + noPVars * recNghbrIds[k]);
18714 const MUint cc = recNghbrIds[k] * nDim;
18715 const MUint slopeId2 = nDim * noPVars * cellId;
18716 const MFloat* const RESTRICT nghbrCoord = ALIGNED_F(cellCoord + cc);
18717
18718 for(MUint v = 0; v < noPVars; ++v) {
18719 MFloat tmp = recNghbrVars[v] - recCellVars[v];
18720 for(MInt d = 0; d < nDim; ++d) {
18721 if(!dirsJmp[d]) {
18722 const MFloat dx = nghbrCoord[d] - cellIdCoord[d];
18723 tmp -= slopes[slopeId2 + v * nDim + d] * dx;
18724 }
18725 }
18726 for(MInt d = 0; d < nDim; ++d) {
18727 if(dirsJmp[d]) {
18728 slopes[slopeId + v * nDim + d] += m_reconstructionConstants[nDim * k + d] * tmp;
18729 }
18730 }
18731 }
18732 }
18733 }
18734 }
18735 }
18736}
18737
18742template <MInt nDim_, class SysEqn>
18744 TRACE();
18745 const MInt noSpecies = m_noSpecies;
18746 if(noSpecies == 0) {
18747 LSReconstructCellCenter_(0);
18748 } else if(noSpecies == 1) {
18749 LSReconstructCellCenter_(1);
18750 } else {
18751 LSReconstructCellCenter_(noSpecies);
18752 }
18753}
18754
18755
18762template <MInt nDim_, class SysEqn>
18764 // TRACE();
18765 const MUint noCVars = CV->noVariables;
18766 const MUint noSlopes = nDim * noCVars;
18767 const MUint totalNoSlopes = noSlopes * a_noCells();
18768 const MUint recDataSize = m_reconstructionDataSize;
18769 MFloat* const RESTRICT slopes = ALIGNED_MF(&a_storedSlope(0, 0, 0));
18770 const MInt* const RESTRICT recCellIds = ALIGNED_I(m_reconstructionCellIds.data());
18771 const MInt* const RESTRICT recNghbrIds = ALIGNED_I(m_reconstructionNghbrIds.data());
18772 const MFloat* const RESTRICT vars = ALIGNED_F(&a_variable(0, 0));
18773 const MFloat* const RESTRICT cellCoord = ALIGNED_F(&a_coordinate(0, 0));
18774
18775// Reset slopes to zero:
18776#ifdef _OPENMP
18777#pragma omp parallel for
18778#endif
18779 for(MUint slopeId = 0; slopeId < totalNoSlopes; ++slopeId) {
18780 slopes[slopeId] = F0;
18781 }
18782
18783 // Compute slopes:
18784 for(MUint k = 0; k < recDataSize; ++k) {
18785 const MFloat* const RESTRICT recNghbrVars = ALIGNED_F(vars + noCVars * recNghbrIds[k]);
18786 const MFloat* const RESTRICT recCellVars = ALIGNED_F(vars + noCVars * recCellIds[k]);
18787 const MUint slopeId = noSlopes * recCellIds[k];
18788 for(MUint v = 0; v < noCVars; ++v) {
18789 const MFloat tmp = recNghbrVars[v] - recCellVars[v];
18790 slopes[slopeId + v * nDim] += m_reconstructionConstants[nDim * k] * tmp;
18791 slopes[slopeId + v * nDim + 1] += m_reconstructionConstants[nDim * k + 1] * tmp;
18792 IF_CONSTEXPR(nDim == 3) slopes[slopeId + v * nDim + 2] += m_reconstructionConstants[nDim * k + 2] * tmp;
18793 }
18794 }
18795
18796 if(m_reConstSVDWeightMode == 3) {
18797 for(MInt cellId = 0; cellId < a_noCells(); ++cellId) {
18798 if(!a_hasProperty(cellId, SolverCell::HasCoarseNghbr)) {
18799 continue;
18800 }
18801 const MFloat* const RESTRICT recCellVars = ALIGNED_F(vars + noCVars * cellId);
18802 const MUint slopeId = nDim * noCVars * cellId;
18803 std::array<MBool, nDim> dirsJmp = {};
18804 for(MInt d = 0; d < nDim; ++d) {
18805 if(m_cells.nghbrInterface(cellId, 2 * d) == 3 || m_cells.nghbrInterface(cellId, 2 * d + 1) == 3) {
18806 dirsJmp[d] = true;
18807 } else {
18808 dirsJmp[d] = false;
18809 }
18810 }
18811
18812 const MUint cc1 = cellId * nDim;
18813 const MFloat* const RESTRICT cellIdCoord = ALIGNED_F(cellCoord + cc1);
18814 for(MUint v = 0; v < noCVars; ++v) {
18815 for(MInt d = 0; d < nDim; ++d) {
18816 if(dirsJmp[d]) {
18817 slopes[slopeId + v * nDim + d] = 0.0;
18818 }
18819 }
18820 }
18821
18822 for(MInt k = a_reconstructionData(cellId); k < a_reconstructionData(cellId + 1); ++k) {
18823 const MFloat* const RESTRICT recNghbrVars = ALIGNED_F(vars + noCVars * recNghbrIds[k]);
18824 const MUint cc = recNghbrIds[k] * nDim;
18825 const MUint slopeId2 = nDim * noCVars * cellId;
18826 const MFloat* const RESTRICT nghbrCoord = ALIGNED_F(cellCoord + cc);
18827
18828 for(MUint v = 0; v < noCVars; ++v) {
18829 MFloat tmp = recNghbrVars[v] - recCellVars[v];
18830 for(MInt d = 0; d < nDim; ++d) {
18831 if(!dirsJmp[d]) {
18832 const MFloat dx = nghbrCoord[d] - cellIdCoord[d];
18833 tmp -= slopes[slopeId2 + v * nDim + d] * dx;
18834 }
18835 }
18836 for(MInt d = 0; d < nDim; ++d) {
18837 if(dirsJmp[d]) {
18838 slopes[slopeId + v * nDim + d] += m_reconstructionConstants[nDim * k + d] * tmp;
18839 }
18840 }
18841 }
18842 }
18843 }
18844 }
18845}
18846
18853template <MInt nDim_, class SysEqn>
18854inline void FvCartesianSolverXD<nDim_, SysEqn>::computeSurfaceValues_(const MUint /* noSpecies */) {
18855 // TRACE();
18856 const MUint noSrfcs = a_noSurfaces();
18857 const MUint noPVars = PV->noVariables;
18858 const MUint noSlopes = nDim * noPVars;
18859 const MUint surfaceVarMemory = 2 * noPVars;
18860 const MInt* const RESTRICT nghbrCellIds = ALIGNED_I(&a_surfaceNghbrCellId(0, 0));
18861 const MFloat* const RESTRICT cellCoord = ALIGNED_F(&a_coordinate(0, 0));
18862 const MFloat* const RESTRICT surfaceCoord = ALIGNED_F(&a_surfaceCoordinate(0, 0));
18863 MFloat* const RESTRICT surfaceVar = ALIGNED_MF(&a_surfaceVariable(0, 0, 0));
18864 const MFloat* const RESTRICT cellSlopes = ALIGNED_F(&a_slope(0, 0, 0));
18865 const MFloat* const RESTRICT vars = ALIGNED_F(&a_pvariable(0, 0));
18866
18867#ifdef _OPENMP
18868#pragma omp parallel for
18869#endif
18870 for(MUint srfcId = 0; srfcId < noSrfcs; ++srfcId) {
18871 const MUint sc = srfcId * nDim;
18872 const MInt* const RESTRICT nghbrIds = ALIGNED_I(nghbrCellIds + srfcId * 2);
18873 const MFloat* const RESTRICT srfcCoord = ALIGNED_F(surfaceCoord + sc);
18874 for(MUint side = 0; side < 2; ++side) { // for each surface side
18875 const MUint nghbr = nghbrIds[side];
18876 const MUint cc = nghbr * nDim;
18877 const MFloat* const RESTRICT nghbrCoord = ALIGNED_F(cellCoord + cc);
18878 MFloat dx[nDim];
18879 for(MInt d = 0; d < nDim; ++d) {
18880 dx[d] = srfcCoord[d] - nghbrCoord[d];
18881 }
18882 const MUint srfcVarOffset = srfcId * surfaceVarMemory + side * noPVars;
18883 MFloat* const RESTRICT currentSrfcVars = ALIGNED_MF(surfaceVar + srfcVarOffset);
18884 const MFloat* const RESTRICT nghbrVars = ALIGNED_F(vars + nghbr * noPVars);
18885 for(MUint v = 0; v < noPVars; ++v) {
18886 const MUint sl = nghbr * noSlopes + v * nDim;
18887 const MFloat* const RESTRICT nghbrSlopes = ALIGNED_F(cellSlopes + sl);
18888 currentSrfcVars[v] = nghbrVars[v];
18889 for(MInt d = 0; d < nDim; ++d) {
18890 currentSrfcVars[v] += nghbrSlopes[d] * dx[d];
18891 }
18892 }
18893 }
18894 }
18895}
18896
18901template <MInt nDim_, class SysEqn>
18903 TRACE();
18904
18905
18906 RECORD_TIMER_START(m_timers[Timers::ReconstSrfcCompValues]);
18907 // compute the surface values:
18908 const MUint noSpecies = m_noSpecies;
18909 if(noSpecies == 0) {
18910 computeSurfaceValues_(0);
18911 } else if(noSpecies == 1) {
18912 computeSurfaceValues_(1);
18913 } else {
18914 computeSurfaceValues_(noSpecies);
18915 }
18916 RECORD_TIMER_STOP(m_timers[Timers::ReconstSrfcCompValues]);
18917
18918 RECORD_TIMER_START(m_timers[Timers::ReconstSrfcCorrVars]);
18919 // correct the boundary surface values
18920 IF_CONSTEXPR(nDim == 2) m_fvBndryCnd->correctBoundarySurfaceVariables();
18921 IF_CONSTEXPR(nDim == 3) {
18922 if(m_fvBndryCnd->m_multipleGhostCells) { // Multiple-Ghost-Cell
18923 if(m_fvBndryCnd->m_surfaceGhostCell) {
18924 m_fvBndryCnd->correctBoundarySurfaceVariablesMGCSurface();
18925 } else {
18926 m_fvBndryCnd->correctBoundarySurfaceVariablesMGC();
18927 }
18928 } else {
18929 m_fvBndryCnd->correctBoundarySurfaceVariables();
18930 }
18931 }
18932 RECORD_TIMER_STOP(m_timers[Timers::ReconstSrfcCorrVars]);
18933
18934 RECORD_TIMER_START(m_timers[Timers::ReconstSrfcUpdateGhost]);
18935 // update the ghost cell slopes for viscous flux balance
18936 m_fvBndryCnd->updateGhostCellSlopesViscous();
18937 RECORD_TIMER_STOP(m_timers[Timers::ReconstSrfcUpdateGhost]);
18938
18939 RECORD_TIMER_START(m_timers[Timers::ReconstSrfcUpdateCutOff]);
18940 m_fvBndryCnd->updateCutOffSlopesViscous();
18941 RECORD_TIMER_STOP(m_timers[Timers::ReconstSrfcUpdateCutOff]);
18942}
18943
18944
18947template <MInt nDim_, class SysEqn>
18949#define VENKATAKRISHNAN
18950 // VENKATAKRISHNAN VENKATAKRISHNAN_MOD
18951 TRACE();
18952 const MInt noCells = a_noCells();
18953 MFloat* const RESTRICT cellSlopes = ALIGNED_MF(&a_slope(0, 0, 0));
18954 const MInt slopeMemory = m_slopeMemory;
18955
18956 for(MInt cellId = 0; cellId < noCells; cellId++) {
18957 if(a_isBndryGhostCell(cellId)) continue;
18958 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
18959 for(MInt it = 0; it < m_noLimitedSlopesVar; it++) {
18960 MInt varId = m_limitedSlopesVar[it];
18961
18962 MFloat minNghbrDelta = F0;
18963 MFloat maxNghbrDelta = F0;
18964 MFloat effNghbrDelta = F0;
18965 const MFloat cellValue = a_pvariable(cellId, varId);
18966 // 1. get the abs min value of the max and min value from the reconstruction neighbours
18967 for(MInt rcnstructnNghbr = 0; rcnstructnNghbr < a_noReconstructionNeighbors(cellId); rcnstructnNghbr++) {
18968 const MInt rcnstrctnNghbrId = a_reconstructionNeighborId(cellId, rcnstructnNghbr);
18969 const MFloat rcnstrctnNghbrValue = a_pvariable(rcnstrctnNghbrId, varId);
18970 const MFloat tmpDelta = rcnstrctnNghbrValue - cellValue;
18971 if(tmpDelta > maxNghbrDelta) {
18972 maxNghbrDelta = tmpDelta;
18973 } else if(tmpDelta < minNghbrDelta) {
18974 minNghbrDelta = tmpDelta;
18975 }
18976 }
18977 effNghbrDelta = mMin(maxNghbrDelta, abs(minNghbrDelta));
18978 // 2. get srfcDelta and compute the minimum phi
18979 const MFloat dx = F1B2 * c_cellLengthAtCell(cellId);
18980 MFloat srfcDelta = F0;
18981 for(MInt dim = 0; dim < nDim; dim++)
18982 srfcDelta += abs(cellSlopes[cellId * slopeMemory + varId * nDim + dim]) * dx;
18983#ifdef BART_AND_JESPERSON
18984 const MFloat eps = 1e-12;
18985 const MFloat phi_max = effNghbrDelta / (srfcDelta + eps);
18986 const MFloat minPhi = mMin(phi_max, F1);
18987#endif
18988#ifdef VENKATAKRISHNAN
18989 const MFloat eps = 1e-12;
18990 const MFloat y = effNghbrDelta / (srfcDelta + eps);
18991 const MFloat minPhi = mMin((y * y + F2 * y) / (y * y + y + F2), F1);
18992#endif
18993#ifdef VENKATAKRISHNAN_MOD
18994 const MFloat K = F2;
18995 const MFloat epsSqr = pow(K * dx, F3);
18996 const MFloat minPhi = (pow(effNghbrDelta, F2) + epsSqr + F2 * effNghbrDelta * srfcDelta)
18997 / (pow(effNghbrDelta, F2) + F2 * pow(srfcDelta, F2) + effNghbrDelta * srfcDelta + epsSqr);
18998#endif
18999 // 3. limit slopes with the minimum phi
19000 for(MInt dim = 0; dim < nDim; dim++)
19001 cellSlopes[cellId * slopeMemory + varId * nDim + dim] *= minPhi;
19002 }
19003 }
19004
19005 // compute the surface values:
19006 if(m_noSpecies == 0) {
19007 computeSurfaceValues_(0);
19008 } else if(m_noSpecies == 1) {
19009 computeSurfaceValues_(1);
19010 } else {
19011 computeSurfaceValues_(m_noSpecies);
19012 }
19013
19014 // correct the boundary surface values
19015 IF_CONSTEXPR(nDim == 2) m_fvBndryCnd->correctBoundarySurfaceVariables();
19016 IF_CONSTEXPR(nDim == 3) {
19017 if(m_fvBndryCnd->m_multipleGhostCells) { // Multiple-Ghost-Cell
19018 if(m_fvBndryCnd->m_surfaceGhostCell) {
19019 m_fvBndryCnd->correctBoundarySurfaceVariablesMGCSurface();
19020 } else {
19021 m_fvBndryCnd->correctBoundarySurfaceVariablesMGC();
19022 }
19023 } else {
19024 m_fvBndryCnd->correctBoundarySurfaceVariables();
19025 }
19026 }
19027
19028 // update the ghost cell slopes for viscous flux balance
19029 m_fvBndryCnd->updateGhostCellSlopesViscous();
19030 m_fvBndryCnd->updateCutOffSlopesViscous();
19031}
19032
19033//----------------------------------------------------------------------------
19034
19042template <MInt nDim_, class SysEqn>
19044 TRACE();
19045
19046 m_log << " first step of initialization of computeSurfaceValuesLimitedSlopesMan" << endl;
19058 MInt limDist = Context::getSolverProperty<MInt>("slopeLimiterDistance1", m_solverId, AT_, &limDist);
19069 MString filename = Context::getSolverProperty<MString>("slopeLimiterFilename", m_solverId, AT_, &filename);
19070
19071 mAlloc(m_limPhi, a_noCells(), "m_limPhi", F1, AT_);
19072
19073 vector<MInt> markedCells;
19074 MIntScratchSpace propDist(/*a_noCells()*/ grid().raw().treeb().size(), AT_, "propDist");
19075 propDist.fill(numeric_limits<MInt>::max());
19076
19077 IF_CONSTEXPR(nDim == 2) {
19078 Geometry2D* auxGeom = new Geometry2D(0, filename, mpiComm());
19079 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
19080 const MFloat cellHalfLength = c_cellLengthAtLevel(a_level(cellId) + 1);
19081 if(!c_noChildren(cellId) && auxGeom->isOnGeometry(cellHalfLength, &a_coordinate(cellId, 0), "SAT")
19082 && a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel))
19083 if(grid().tree().solver2grid(cellId) > -1) markedCells.push_back(grid().tree().solver2grid(cellId));
19084 }
19085 }
19086 IF_CONSTEXPR(nDim == 3) {
19087 Geometry3D* auxGeom = new Geometry3D(0, filename, mpiComm());
19088 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
19089 const MFloat cellHalfLength = c_cellLengthAtLevel(a_level(cellId) + 1);
19090 if(!c_noChildren(cellId) && auxGeom->isOnGeometry(cellHalfLength, &a_coordinate(cellId, 0), "SAT")
19091 && a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel))
19092 if(grid().tree().solver2grid(cellId) > -1) markedCells.push_back(grid().tree().solver2grid(cellId));
19093 }
19094 }
19095
19096 // TODO labels:FV,toenhance Is a cell that completely contains a closed surface cut by it? If Yes,
19097 // we could loop down from the partition cells to the cut leaf cells and skip a lot
19098 // calls of cellIsOnGeometry of definetily uncut cells.
19099
19100 MLong tmp = markedCells.size();
19101 MPI_Allreduce(MPI_IN_PLACE, &tmp, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "tmp");
19102 m_log << " overall cells on shock: " << tmp << endl;
19103 tmp = 0;
19104
19105 grid().raw().propagateDistance(markedCells, propDist, limDist);
19106
19107 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
19108 const MInt gridCellId = grid().tree().solver2grid(cellId);
19109 if(gridCellId < 0) continue;
19110 if(propDist[gridCellId] != numeric_limits<MInt>::max()) {
19111 m_limPhi[cellId] = F1B2 - F1B2 * cos(PI * ((MFloat)propDist[gridCellId]) / ((MFloat)limDist));
19112 tmp++;
19113 }
19114 }
19115
19116 MPI_Allreduce(MPI_IN_PLACE, &tmp, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "tmp");
19117 m_log << " overall limited cells: " << tmp << endl;
19118}
19119
19120//----------------------------------------------------------------------------
19121
19129template <MInt nDim_, class SysEqn>
19131 TRACE();
19132
19133 m_log << " second step of initialization of computeSurfaceValuesLimitedSlopesMan" << endl;
19134
19145 MFloat limDistF = F0;
19146 limDistF = Context::getSolverProperty<MFloat>("slopeLimiterDistance2", m_solverId, AT_, &limDistF);
19147
19148 vector<MInt> markedCells;
19149 MIntScratchSpace propDist(/*a_noCells()*/ grid().raw().treeb().size(), AT_, "propDist");
19150 propDist.fill(numeric_limits<MInt>::max());
19151
19152 MInt tmp = 0;
19153 if(limDistF > F0) {
19154 for(MInt bc = 0; bc < m_fvBndryCnd->m_noCutOffBndryCndIds; bc++) {
19155 if(m_fvBndryCnd->m_cutOffBndryCndIds[bc] / 10 == 272 || m_fvBndryCnd->m_cutOffBndryCndIds[bc] / 10 == 271) {
19156 for(MInt lvl = maxUniformRefinementLevel(); lvl <= maxRefinementLevel(); lvl++) {
19157 for(MInt i = 0; i < m_fvBndryCnd->m_sortedCutOffCells[bc]->size(); i++) {
19158 if(a_level(m_fvBndryCnd->m_sortedCutOffCells[bc]->a[i]) == lvl)
19159 if(grid().tree().solver2grid(m_fvBndryCnd->m_sortedCutOffCells[bc]->a[i]) > -1)
19160 markedCells.push_back(grid().tree().solver2grid(m_fvBndryCnd->m_sortedCutOffCells[bc]->a[i]));
19161 }
19162 auto limDist = (MInt)(limDistF / c_cellLengthAtLevel(lvl) + F1B2);
19163 grid().raw().propagateDistance(markedCells, propDist, limDist);
19164 markedCells.clear();
19165 }
19166 }
19167 }
19168 // set limiter value
19169 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
19170 const MInt gridCellId = grid().tree().solver2grid(cellId);
19171 if(gridCellId < 0) continue;
19172 if(propDist[gridCellId] != numeric_limits<MInt>::max()) {
19173 // compute distance from propDist depending on level
19174 MInt lvl = a_level(cellId);
19175 MFloat dist = (propDist[gridCellId] + F1B2) * c_cellLengthAtLevel(lvl);
19176 m_limPhi[cellId] = F1B2 - F1B2 * cos(PI * dist / limDistF);
19177 tmp++;
19178 }
19179 }
19180 }
19181
19182 MPI_Allreduce(MPI_IN_PLACE, &tmp, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "tmp");
19183 m_log << " added overall limited cells: " << tmp << endl;
19184}
19185
19186//----------------------------------------------------------------------------
19187
19193template <MInt nDim_, class SysEqn>
19195 TRACE();
19196
19197 const MInt noCells = a_noCells();
19198 MFloat* const RESTRICT cellSlopes = ALIGNED_MF(&a_slope(0, 0, 0));
19199 const MInt slopeMemory = m_slopeMemory;
19200
19201 for(MInt cellId = 0; cellId < noCells; cellId++) {
19202 // if(a_hasProperty(cellId, SolverCell::IsCutOff))
19203 // continue;
19204 for(MInt it = 0; it < m_noLimitedSlopesVar; it++) {
19205 MInt varId = m_limitedSlopesVar[it];
19206
19207 // limit slopes with the minimum phi
19208 for(MInt dim = 0; dim < nDim; dim++)
19209 cellSlopes[cellId * slopeMemory + varId * nDim + dim] *= m_limPhi[cellId];
19210 }
19211 }
19212
19213 // compute the surface values:
19214 if(m_noSpecies == 0) {
19215 computeSurfaceValues_(0);
19216 } else if(m_noSpecies == 1) {
19217 computeSurfaceValues_(1);
19218 } else {
19219 computeSurfaceValues_(m_noSpecies);
19220 }
19221
19222 // correct the boundary surface values
19223 if(m_fvBndryCnd->m_multipleGhostCells) { // Multiple-Ghost-Cell
19224 if(m_fvBndryCnd->m_surfaceGhostCell) {
19225 m_fvBndryCnd->correctBoundarySurfaceVariablesMGCSurface();
19226 } else {
19227 m_fvBndryCnd->correctBoundarySurfaceVariablesMGC();
19228 }
19229 } else {
19230 m_fvBndryCnd->correctBoundarySurfaceVariables();
19231 }
19232
19233 // update the ghost cell slopes for viscous flux balance
19234 m_fvBndryCnd->updateGhostCellSlopesViscous();
19235 m_fvBndryCnd->updateCutOffSlopesViscous();
19236}
19237
19238
19243template <MInt nDim_, class SysEqn>
19245 TRACE();
19246
19247 if(string2enum(m_advectiveFluxScheme) == AUSM) {
19248 Ausm_<AUSM>(sysEqn());
19249 } else if(string2enum(m_advectiveFluxScheme) == AUSMPLUS) {
19250 Ausm_<AUSMPLUS>(sysEqn());
19251 } else if(string2enum(m_advectiveFluxScheme) == SLAU) {
19252 Ausm_<SLAU>(sysEqn());
19253 }
19254}
19255
19256template <MInt nDim_, class SysEqn>
19257template <MInt stencil, class F>
19259 const MUint noPVars = PV->noVariables;
19260 const MUint noFluxVars = FV->noVariables;
19261 const MUint noSurfaceCoefficients = hasSC ? SC->m_noSurfaceCoefficients : 0;
19262 const MUint surfaceVarMemory = 2 * noPVars;
19263 const MUint noSurfaces = a_noSurfaces();
19264 const MUint noInternalSurfaces = m_bndrySurfacesOffset;
19265
19266 MFloat* const RESTRICT fluxes = ALIGNED_MF(&a_surfaceFlux(0, 0));
19267 const MFloat* const RESTRICT surfaceVars = ALIGNED_F(&a_surfaceVariable(0, 0, 0));
19268 const MFloat* const RESTRICT surfaceCoefficients = hasSC ? ALIGNED_F(&a_surfaceCoefficient(0, 0)) : nullptr;
19269 const MFloat* const RESTRICT upwindCoefficients = ALIGNED_F(&a_surfaceUpwindCoefficient(0));
19270 const MFloat* const RESTRICT area = ALIGNED_F(&a_surfaceArea(0));
19271 const MInt* const RESTRICT orientations = ALIGNED_I(&a_surfaceOrientation(0));
19272 const MInt* const RESTRICT bndryCndIds = ALIGNED_I(&a_surfaceBndryCndId(0));
19273
19274// loop over all surfaces
19275#ifdef _OPENMP
19276#pragma omp parallel for
19277#endif
19278 for(MUint srfcId = 0; srfcId < noSurfaces; ++srfcId) {
19279 const MUint orientation = orientations[srfcId];
19280
19281 const MUint offset = srfcId * surfaceVarMemory;
19282 const MFloat* const RESTRICT leftVars = ALIGNED_F(surfaceVars + offset);
19283 const MFloat* const RESTRICT rightVars = ALIGNED_F(leftVars + noPVars);
19284
19285 const MUint coefficientOffset = srfcId * noSurfaceCoefficients;
19286 const MFloat* const RESTRICT srfcCoeff = hasSC ? ALIGNED_F(surfaceCoefficients + coefficientOffset) : nullptr;
19287
19288 const MFloat A = area[srfcId];
19289
19290 const MUint fluxOffset = srfcId * noFluxVars;
19291 MFloat* const RESTRICT flux = ALIGNED_MF(fluxes + fluxOffset);
19292
19293 const MFloat upwindCoefficient = upwindCoefficients[srfcId];
19294
19295 fluxFct.template Ausm<stencil>(orientation, upwindCoefficient, A, leftVars, rightVars, srfcCoeff, flux);
19296 }
19297
19298 // find if there is a boundary condition that needs flux correction
19299 // (assumes no moving boundaries between domains)
19300 MBool& checkedBndryCndIds = m_static_computeSurfaceValuesLimitedSlopesMan_checkedBndryCndIds;
19301 MBool& correctWallBndryFluxes = m_static_computeSurfaceValuesLimitedSlopesMan_correctWallBndryFluxes;
19302 if(!checkedBndryCndIds) {
19303 for(MUint srfcId = noInternalSurfaces; srfcId < noSurfaces; ++srfcId) {
19304 if((bndryCndIds[srfcId] > 1999 && bndryCndIds[srfcId] < 4000)) {
19305 correctWallBndryFluxes = true;
19306 }
19307 }
19308 checkedBndryCndIds = true;
19309 }
19310
19311 if(correctWallBndryFluxes) {
19312 // correct all wall boundary surfaces
19313 for(MUint srfcId = noInternalSurfaces; srfcId < noSurfaces; ++srfcId) {
19314 if(!(bndryCndIds[srfcId] > 1999 && bndryCndIds[srfcId] < 4000)) {
19315 continue;
19316 }
19317
19318 const MUint orientation = orientations[srfcId];
19319
19320 const MUint offset = srfcId * surfaceVarMemory;
19321 const MFloat* leftVars = surfaceVars + offset;
19322 const MFloat* rightVars = leftVars + noPVars;
19323
19324 const MFloat A = area[srfcId];
19325 const MUint fluxOffset = srfcId * noFluxVars;
19326 MFloat* const RESTRICT flux = fluxes + fluxOffset;
19327
19328 fluxFct.AusmBndryCorrection(orientation, A, leftVars, rightVars, flux);
19329 }
19330 }
19331}
19332
19333template <MInt nDim_, class SysEqn>
19335 TRACE();
19336 if(string2enum(m_viscousFluxScheme) == FIVE_POINT) {
19337 viscousFlux_<FIVE_POINT>(sysEqn());
19338 } else if(string2enum(m_viscousFluxScheme) == THREE_POINT) {
19339 viscousFluxCompact_<THREE_POINT>(sysEqn());
19340 } else if(string2enum(m_viscousFluxScheme) == FIVE_POINT_STABILIZED) {
19341 viscousFluxCompact_<FIVE_POINT_STABILIZED>(sysEqn());
19342 }
19343 IF_CONSTEXPR(isEEGas<SysEqn>) {
19344 if(m_EEGas.bubblePathDispersion) bubblePathDispersion();
19345 }
19346}
19347
19360template <MInt nDim_, class SysEqn>
19361template <MInt stencil, class F>
19363 // TRACE();
19364 const MUint noPVars = PV->noVariables;
19365 const MUint noFluxVars = FV->noVariables;
19366 const MUint noSurfaceCoefficients = hasSC ? SC->m_noSurfaceCoefficients : 0;
19367 const MUint surfaceVarMemory = 2 * noPVars;
19368 const MUint noSlopes = nDim * noPVars;
19369 const MUint noSurfaces = a_noSurfaces();
19370
19371#ifdef FV_FREE_SURFACE_BC // See TODO labels:FV below
19372 const MInt* const bndryCndIds RESTRICT = ALIGNED_I(&a_surfaceBndryCndId(0));
19373#endif
19374 const MInt* const RESTRICT orientations = ALIGNED_I(&a_surfaceOrientation(0));
19375 const MInt* const RESTRICT nghbrCellIds = ALIGNED_I(&a_surfaceNghbrCellId(0, 0));
19376 const MFloat* const RESTRICT surfaceVars = ALIGNED_F(&a_surfaceVariable(0, 0, 0));
19377 const MFloat* const RESTRICT surfaceCoefficients = hasSC ? ALIGNED_F(&a_surfaceCoefficient(0, 0)) : nullptr;
19378 const MFloat* const RESTRICT factor = ALIGNED_F(&a_surfaceFactor(0, 0));
19379 const MFloat* const RESTRICT slope = ALIGNED_F(&a_slope(0, 0, 0));
19380 const MFloat* const RESTRICT area = ALIGNED_F(&a_surfaceArea(0));
19381 MFloat* const RESTRICT fluxes = ALIGNED_MF(&a_surfaceFlux(0, 0));
19382
19383#ifdef _OPENMP
19384#pragma omp parallel for
19385#endif
19386 for(MUint srfcId = 0; srfcId < noSurfaces; srfcId++) {
19387 // TODO labels:FV,totest is this really necessary / is this the right place to do this??
19388#ifdef FV_FREE_SURFACE_BC
19389 // correct all free surface viscous boundaries flux to zero, Christoph Siewert
19390 if((MInt)srfcId > m_bndrySurfacesOffset) {
19391 if(bndryCndId[srfcId] == 5000) {
19392 continue;
19393 }
19394 }
19395#endif
19396
19397 const MUint offset = srfcId * surfaceVarMemory;
19398 const MFloat* const RESTRICT vars0 = ALIGNED_F(surfaceVars + offset);
19399 const MFloat* const RESTRICT vars1 = ALIGNED_F(vars0 + noPVars);
19400
19401 const MUint orientation = orientations[srfcId];
19402 const MFloat A = area[srfcId];
19403
19404 const MFloat f0 = factor[srfcId * 2];
19405 const MFloat f1 = factor[srfcId * 2 + 1];
19406 const MUint offset0 = nghbrCellIds[2 * srfcId] * noSlopes;
19407 const MUint offset1 = nghbrCellIds[2 * srfcId + 1] * noSlopes;
19408 const MFloat* const RESTRICT slope0 = ALIGNED_F(slope + offset0);
19409 const MFloat* const RESTRICT slope1 = ALIGNED_F(slope + offset1);
19410
19411 const MUint coefficientOffset = srfcId * noSurfaceCoefficients;
19412 const MFloat* const RESTRICT srfcCoeff = hasSC ? ALIGNED_F(surfaceCoefficients + coefficientOffset) : nullptr;
19413
19414 const MUint fluxOffset = srfcId * noFluxVars;
19415 MFloat* const RESTRICT flux = ALIGNED_MF(fluxes + fluxOffset);
19416
19417 viscousFluxFct.template viscousFlux<stencil>(orientation, A, vars0, vars1, slope0, slope1, srfcCoeff, f0, f1, flux);
19418 }
19419
19420
19421 // correct viscous fluxes on WMLES bndry surfaces
19422 // \author Thomas Luerkens
19423 if(m_wmLES) {
19424 RECORD_TIMER_START(m_timers[Timers::WMSurfaceLoop]);
19425 const MInt noWMSurfaces = m_wmSurfaces.size();
19426#ifdef _OPENMP
19427#pragma omp parallel for
19428#endif
19429 for(MInt wmSrfcId = 0; wmSrfcId < noWMSurfaces; wmSrfcId++) {
19430 const MFloat mue_wm = computeWMViscositySpalding(wmSrfcId);
19431 const MInt bndryCellId = m_wmSurfaces[wmSrfcId].m_bndryCellId;
19432 const MInt bndrySrfcId = m_wmSurfaces[wmSrfcId].m_bndrySrfcId;
19433
19434 for(MInt dim = 0; dim < nDim; dim++) {
19435 const MInt srfcId = m_bndryCells->a[bndryCellId].m_srfcVariables[bndrySrfcId]->m_srfcId[dim];
19436
19437 if(srfcId < 0) continue;
19438
19439 const MUint offset = srfcId * surfaceVarMemory;
19440 const MFloat* const RESTRICT vars0 = ALIGNED_F(surfaceVars + offset);
19441 const MFloat* const RESTRICT vars1 = ALIGNED_F(vars0 + noPVars);
19442
19443 const MUint orientation = orientations[srfcId];
19444 const MFloat A = area[srfcId];
19445
19446 const MFloat f0 = factor[srfcId * 2];
19447 const MFloat f1 = factor[srfcId * 2 + 1];
19448 const MUint offset0 = nghbrCellIds[2 * srfcId] * noSlopes;
19449 const MUint offset1 = nghbrCellIds[2 * srfcId + 1] * noSlopes;
19450 const MFloat* const RESTRICT slope0 = ALIGNED_F(slope + offset0);
19451 const MFloat* const RESTRICT slope1 = ALIGNED_F(slope + offset1);
19452
19453 const MUint fluxOffset = srfcId * noPVars;
19454 MFloat* const RESTRICT flux = ALIGNED_MF(fluxes + fluxOffset);
19455
19456 RECORD_TIMER_START(m_timers[Timers::WMFluxCorrection]);
19457 viscousFluxFct.template wmViscousFluxCorrection<stencil>(orientation, A, vars0, vars1, slope0, slope1, f0, f1,
19458 flux, mue_wm);
19459 RECORD_TIMER_STOP(m_timers[Timers::WMFluxCorrection]);
19460 }
19461 }
19462 RECORD_TIMER_STOP(m_timers[Timers::WMSurfaceLoop]);
19463 }
19464}
19465
19474template <MInt nDim_, class SysEqn>
19475template <MInt stencil, class F>
19477 const MUint noPVars = PV->noVariables;
19478 const MUint noFluxVars = FV->noVariables;
19479 const MUint surfaceVarMemory = 2 * noPVars;
19480 const MUint noSlopes = nDim * noPVars;
19481 const MUint noSurfaces = a_noSurfaces();
19482
19483 const MInt* const RESTRICT orientations = ALIGNED_I(&a_surfaceOrientation(0));
19484 const MInt* const RESTRICT nghbrCellIds = ALIGNED_I(&a_surfaceNghbrCellId(0, 0));
19485 const MFloat* const RESTRICT surfaceVars = ALIGNED_F(&a_surfaceVariable(0, 0, 0));
19486 const MFloat* const RESTRICT scoords = ALIGNED_F(&a_surfaceCoordinate(0, 0));
19487 const MFloat* const RESTRICT factor = ALIGNED_F(&a_surfaceFactor(0, 0));
19488 const MFloat* const RESTRICT slope = ALIGNED_F(&a_slope(0, 0, 0));
19489 const MFloat* const RESTRICT ccoords = ALIGNED_F(&a_coordinate(0, 0));
19490 const MFloat* const RESTRICT area = ALIGNED_F(&a_surfaceArea(0));
19491 const MFloat* const RESTRICT cellvars = ALIGNED_F(&a_pvariable(0, 0));
19492 MFloat* const RESTRICT fluxes = ALIGNED_MF(&a_surfaceFlux(0, 0));
19493
19494#ifdef _OPENMP
19495#pragma omp parallel for
19496#endif
19497 for(MUint srfcId = 0; srfcId < noSurfaces; srfcId++) {
19498 const MUint offset = srfcId * surfaceVarMemory;
19499 const MFloat* const RESTRICT vars0 = ALIGNED_F(surfaceVars + offset);
19500 const MFloat* const RESTRICT vars1 = ALIGNED_F(vars0 + noPVars);
19501
19502 const MFloat f0 = factor[srfcId * 2];
19503 const MFloat f1 = factor[srfcId * 2 + 1];
19504
19505 const MUint orientation = orientations[srfcId];
19506 const MFloat A = area[srfcId];
19507
19508 const MBool isBndry = a_surfaceBndryCndId(srfcId) > -1;
19509
19510 const MUint offsetSurfaceCoord = nDim * srfcId;
19511 const MFloat* const RESTRICT surfaceCoord = ALIGNED_F(scoords + offsetSurfaceCoord);
19512
19513 const MUint off0 = nghbrCellIds[2 * srfcId] * nDim;
19514 const MUint off1 = nghbrCellIds[2 * srfcId + 1] * nDim;
19515 const MFloat* const RESTRICT coord0 = ALIGNED_F(ccoords + off0);
19516 const MFloat* const RESTRICT coord1 = ALIGNED_F(ccoords + off1);
19517
19518 const MUint voff0 = nghbrCellIds[2 * srfcId] * noPVars;
19519 const MUint voff1 = nghbrCellIds[2 * srfcId + 1] * noPVars;
19520 const MFloat* const RESTRICT cellVars0 = ALIGNED_F(cellvars + voff0);
19521 const MFloat* const RESTRICT cellVars1 = ALIGNED_F(cellvars + voff1);
19522
19523 const MUint offset0 = nghbrCellIds[2 * srfcId] * noSlopes;
19524 const MUint offset1 = nghbrCellIds[2 * srfcId + 1] * noSlopes;
19525 const MFloat* const RESTRICT slope0 = ALIGNED_F(slope + offset0);
19526 const MFloat* const RESTRICT slope1 = ALIGNED_F(slope + offset1);
19527
19528 const MUint fluxOffset = srfcId * noFluxVars;
19529 MFloat* const RESTRICT flux = ALIGNED_MF(fluxes + fluxOffset);
19530
19531 viscousFluxFct.template viscousFlux<stencil>(orientation, A, isBndry, surfaceCoord, coord0, coord1, cellVars0,
19532 cellVars1, vars0, vars1, slope0, slope1, f0, f1, flux);
19533 }
19534}
19535
19536template <MInt nDim, class SysEqn>
19537template <class _, std::enable_if_t<isEEGas<SysEqn>, _*>>
19539 TRACE();
19540 const MUint noPVars = PV->noVariables;
19541 const MUint noFluxVars = FV->noVariables;
19542 const MUint surfaceVarMemory = 2 * noPVars;
19543 // const MUint noSlopes = nDim * noPVars;
19544 const MUint noSurfaces = a_noSurfaces();
19545
19546 const MInt* const RESTRICT orientations = ALIGNED_I(&a_surfaceOrientation(0));
19547 const MInt* const RESTRICT nghbrCellIds = ALIGNED_I(&a_surfaceNghbrCellId(0, 0));
19548 const MFloat* const RESTRICT surfaceVars = ALIGNED_F(&a_surfaceVariable(0, 0, 0));
19549 const MFloat* const RESTRICT factor = ALIGNED_F(&a_surfaceFactor(0, 0));
19550 // const MFloat* const RESTRICT slope = ALIGNED_F(&a_slope(0, 0, 0));
19551 const MFloat* const RESTRICT area = ALIGNED_F(&a_surfaceArea(0));
19552 MFloat* const RESTRICT fluxes = ALIGNED_MF(&a_surfaceFlux(0, 0));
19553
19554 // bubble path dispersion (see Mohammadi 2019 eq. (23) / Sokolichin 2004)
19555 const MFloat fScRe0 = F1 / (m_EEGas.schmidtNumber * sysEqn().m_Re0);
19556#ifdef _OPENMP
19557#pragma omp parallel for
19558#endif
19559 for(MUint srfcId = 0; srfcId < noSurfaces; ++srfcId) {
19560 const MInt leftCellId = nghbrCellIds[2 * srfcId];
19561 const MInt rightCellId = nghbrCellIds[2 * srfcId + 1];
19562
19563 const MUint orientation = orientations[srfcId];
19564 const MUint offset = srfcId * surfaceVarMemory;
19565 const MFloat* const RESTRICT leftVars = ALIGNED_F(surfaceVars + offset);
19566 const MFloat* const RESTRICT rightVars = ALIGNED_F(leftVars + noPVars);
19567 const MFloat A = area[srfcId];
19568 const MFloat f0 = factor[srfcId * 2];
19569 const MFloat f1 = factor[srfcId * 2 + 1];
19570
19571 const MFloat alphaSlopeL = m_cells.slope(leftCellId, PV->A, orientation);
19572 const MFloat RHOL = leftVars[PV->RHO];
19573 const MFloat nutL = a_nuEffOtherPhase(leftCellId);
19574
19575 const MFloat alphaSlopeR = m_cells.slope(rightCellId, PV->A, orientation);
19576 const MFloat RHOR = rightVars[PV->RHO];
19577 const MFloat nutR = a_nuEffOtherPhase(rightCellId);
19578
19579 const MFloat alphaSlopeLR = f0 * alphaSlopeL + f1 * alphaSlopeR;
19580 const MFloat RHOLR = 0.5 * (RHOL + RHOR);
19581 const MFloat nutLR = f0 * nutL + f1 * nutR;
19582
19583 if(fabs(alphaSlopeLR) < 1e-10) continue;
19584
19585 const MUint fluxOffset = srfcId * noFluxVars;
19586 MFloat* const RESTRICT flux = ALIGNED_MF(fluxes + fluxOffset);
19587 flux[FV->A_RHO] -= fScRe0 * alphaSlopeLR * RHOLR * nutLR * A;
19588 }
19589}
19590
19591//---------------------------------------------------------------------------------------
19592template <MInt nDim_, class SysEqn>
19594 TRACE();
19595
19596#ifdef _OPENMP
19597#pragma omp parallel for
19598#endif
19599 for(MInt ac = 0; ac < m_noActiveCells; ac++) {
19600 const MInt cellId = m_activeCellIds[ac];
19601
19602 if(a_isBndryGhostCell(cellId)) continue;
19603 if(a_isInactive(cellId)) continue;
19604
19605 MFloat* vars = &a_pvariable(0, 0);
19606 MFloat* rhs = &a_rightHandSide(cellId, 0);
19607 const MFloat cellVol = a_cellVolume(cellId);
19608 const MFloat* const slopes = &a_slope(0, 0, 0);
19609 const MInt* const recNghbr = &a_reconstructionNeighborId(cellId, 0);
19610 const MInt noRecNghbr = a_noReconstructionNeighbors(cellId);
19611 const MInt recData = a_reconstructionData(cellId);
19612 const MFloat* const recConst = &m_reconstructionConstants[0];
19613
19614 MFloat dist = F1;
19615 if(m_levelSetRans) {
19616 dist = a_levelSetFunction(cellId, 0);
19617 } else {
19618 // You can define an analytical wall distance here
19619 dist = a_coordinate(cellId, 1);
19620 }
19621
19622 sysEqn().computeVolumeForces(cellId, vars, rhs, cellVol, slopes, recData, recNghbr, recConst, noRecNghbr, dist);
19623 }
19624}
19625
19643template <MInt nDim, class SysEqn>
19644template <class _, std::enable_if_t<!isEEGas<SysEqn>, _*>>
19645inline MBool FvCartesianSolverXD<nDim, SysEqn>::rungeKuttaStep_(const MUint /* noSpecies_ */) {
19646 TRACE();
19647
19648 const MUint noCVars = CV->noVariables;
19649 const MUint noFVars = FV->noVariables;
19650
19651 // Include the timestep in the rkFactor if dual time stepping is disabled:
19652 const MFloat rkAlpha = m_RKalpha[m_RKStep];
19653 const MFloat dt = timeStep(true);
19654 const MFloat rkFactor = m_dualTimeStepping ? rkAlpha : rkAlpha * dt;
19655
19656 const MUint last = m_noActiveHaloCellOffset > 0 ? m_activeCellIds[m_noActiveHaloCellOffset - 1] + 1
19657 : std::numeric_limits<MUint>::min();
19658 MFloat* const RESTRICT oldVars = &a_oldVariable(0, 0);
19659 MFloat* const RESTRICT vars = &a_variable(0, 0);
19660 const MFloat* const RESTRICT fCellVol = &a_FcellVolume(0);
19661 const MFloat* const RESTRICT localTimeStep = m_dualTimeStepping ? &a_localTimeStep(0) : nullptr;
19662 const MFloat* const RESTRICT rhs = &a_rightHandSide(0, 0);
19663
19664 if(m_RKStep == 0) {
19665#ifdef _OPENMP
19666#pragma omp parallel for
19667#endif
19668 for(MUint cellId = m_activeCellIds[0]; cellId < last; ++cellId) {
19669#if !defined(DISABLE_FV_MG)
19670 IF_CONSTEXPR(nDim == 2) {
19671 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
19672 continue;
19673 }
19674 }
19675#endif
19676 const MUint cellOffset = cellId * noCVars;
19677 MFloat* const RESTRICT oldCellVars = oldVars + cellOffset;
19678 const MFloat* const RESTRICT cellVars = vars + cellOffset;
19679 for(MUint varId = 0; varId < noCVars; ++varId) {
19680 oldCellVars[varId] = cellVars[varId];
19681 }
19682 }
19683 }
19684
19685 // 2nd order and 3rd order Runge-Kutta Schemes
19686 switch(m_rungeKuttaOrder) {
19688 case 2: {
19689 if(!m_dualTimeStepping) { // -> timestep is constant (see rkAlpha init)
19690#ifdef _OPENMP
19691#pragma omp parallel for
19692#endif
19693 for(MUint cellId = m_activeCellIds[0]; cellId < last; ++cellId) {
19694#if !defined(DISABLE_FV_MG)
19695 IF_CONSTEXPR(nDim == 2) {
19696 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
19697 continue;
19698 }
19699 }
19700#endif
19701 const MFloat factor = rkFactor * fCellVol[cellId];
19702 const MUint cellOffset = cellId * noCVars;
19703 const MFloat* const RESTRICT oldCellVars = oldVars + cellOffset;
19704 const MFloat* const RESTRICT cellRhs = rhs + cellOffset;
19705 MFloat* const RESTRICT cellVars = vars + cellOffset;
19706
19707 for(MUint varId = 0; varId < noCVars; ++varId) {
19708 cellVars[varId] = oldCellVars[varId] - factor * cellRhs[varId];
19709 }
19710 }
19711 } else {
19712#ifdef _OPENMP
19713#pragma omp parallel for
19714#endif
19715 for(MUint cellId = m_activeCellIds[0]; cellId < last; ++cellId) {
19716#if !defined(DISABLE_FV_MG)
19717 IF_CONSTEXPR(nDim == 2) {
19718 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
19719 continue;
19720 }
19721 }
19722#endif
19723 const MFloat factor = rkFactor * fCellVol[cellId] * localTimeStep[cellId];
19724 const MUint cellOffset = cellId * noCVars;
19725 const MUint cellRhsOffset = cellId * noFVars;
19726 const MFloat* const RESTRICT oldCellVars = oldVars + cellOffset;
19727 const MFloat* const RESTRICT cellRhs = rhs + cellRhsOffset;
19728 MFloat* const RESTRICT cellVars = vars + cellOffset;
19729 for(MUint varId = 0; varId < noCVars; ++varId) {
19730 cellVars[varId] = oldCellVars[varId] - factor * cellRhs[varId];
19731 }
19732 }
19733 }
19734 break;
19735 }
19737 case 3: {
19738 if(!m_dualTimeStepping) { // -> timestep is constant (see rkAlpha init)
19739#ifdef _OPENMP
19740#pragma omp parallel for
19741#endif
19742 for(MUint cellId = m_activeCellIds[0]; cellId < last; ++cellId) {
19743#if !defined(DISABLE_FV_MG)
19744 IF_CONSTEXPR(nDim == 2) {
19745 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
19746 continue;
19747 }
19748 }
19749#endif
19750 const MFloat factor = rkFactor * fCellVol[cellId];
19751 const MUint cellOffset = cellId * noCVars;
19752 const MUint cellRhsOffset = cellId * noFVars;
19753 const MFloat* const RESTRICT oldCellVars = oldVars + cellOffset;
19754 const MFloat* const RESTRICT cellRhs = rhs + cellRhsOffset;
19755 MFloat* const RESTRICT cellVars = vars + cellOffset;
19756 for(MUint varId = 0; varId < noCVars; ++varId) {
19757 cellVars[varId] = rkAlpha * cellVars[varId] + (F1 - rkAlpha) * oldCellVars[varId] - factor * cellRhs[varId];
19758 }
19759 }
19760 } else {
19761#ifdef _OPENMP
19762#pragma omp parallel for
19763#endif
19764 for(MUint cellId = m_activeCellIds[0]; cellId < last; ++cellId) {
19765#if !defined(DISABLE_FV_MG)
19766 IF_CONSTEXPR(nDim == 2) {
19767 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
19768 continue;
19769 }
19770 }
19771#endif
19772 const MFloat factor = rkAlpha * fCellVol[cellId] * localTimeStep[cellId];
19773 const MUint cellOffset = cellId * noCVars;
19774 const MUint cellRhsOffset = cellId * noFVars;
19775 const MFloat* const RESTRICT oldCellVars = oldVars + cellOffset;
19776 const MFloat* const RESTRICT cellRhs = rhs + cellRhsOffset;
19777 MFloat* const RESTRICT cellVars = vars + cellOffset;
19778 for(MUint varId = 0; varId < noCVars; ++varId) {
19779 cellVars[varId] = rkAlpha * cellVars[varId] + (F1 - rkAlpha) * oldCellVars[varId] - factor * cellRhs[varId];
19780 }
19781 }
19782 }
19783 break;
19784 }
19785 default: {
19786 stringstream errorMessage;
19787 errorMessage << "Runge-Kutta Order (property 'rungeKuttaOrder) " << m_rungeKuttaOrder << " is not implemented.";
19788 mTerm(1, AT_, errorMessage.str());
19789 }
19790 }
19791
19792 m_RKStep++;
19793 if(m_RKStep == m_noRKSteps) {
19794 if(!m_dualTimeStepping) {
19795 m_physicalTime += dt * m_timeRef; // timestep is dimensionless t/a_0 (right)
19796 }
19797
19798 // Time is the "internal" time based on stagnation values
19799 m_time += dt;
19800 m_RKStep = 0;
19801
19802 return true;
19803 }
19804 return false;
19805}
19806
19807
19812template <MInt nDim_, class SysEqn>
19814 const MUint noSpecies = m_noSpecies;
19815
19816 IF_CONSTEXPR(isEEGas<SysEqn>) { return rungeKuttaStepEEGas(); }
19817 else {
19818 if(noSpecies == 0) {
19819 return rungeKuttaStep_(0);
19820 } else if(noSpecies == 1) {
19821 return rungeKuttaStep_(1);
19822 } else {
19823 return rungeKuttaStep_(noSpecies);
19824 }
19825 }
19826}
19827
19841template <MInt nDim_, class SysEqn>
19842template <class _, std::enable_if_t<isEEGas<SysEqn>, _*>>
19844 TRACE();
19845
19846 const MUint noCVars = CV->noVariables;
19847 const MUint noFVars = FV->noVariables;
19848
19849 // Include the timestep in the rkFactor if dual time stepping is disabled:
19850 const MFloat rkAlpha = m_RKalpha[m_RKStep];
19851 const MFloat dt = timeStep(true);
19852 const MFloat rkFactor = rkAlpha * dt;
19853
19854 const MUint noActiveCells = m_noActiveCells;
19855 const MUint last = m_activeCellIds[noActiveCells - 1] + 1;
19856 MFloat* const RESTRICT oldVars = &a_oldVariable(0, 0);
19857 MFloat* const RESTRICT vars = &a_variable(0, 0);
19858 const MFloat* const RESTRICT fCellVol = &a_FcellVolume(0);
19859 const MFloat* const RESTRICT rhs = &a_rightHandSide(0, 0);
19860
19861
19862 if(m_RKStep == 0) {
19863#ifdef _OPENMP
19864#pragma omp parallel for
19865#endif
19866 for(MUint cellId = m_activeCellIds[0]; cellId < last; ++cellId) {
19867 const MUint cellOffset = cellId * noCVars;
19868 MFloat* const RESTRICT oldCellVars = oldVars + cellOffset;
19869 const MFloat* const RESTRICT cellVars = vars + cellOffset;
19870 for(MUint varId = 0; varId < noCVars; ++varId) {
19871 oldCellVars[varId] = cellVars[varId];
19872 }
19873 }
19874 }
19875
19876 // 2nd order and 3rd order Runge-Kutta Schemes
19877 switch(m_rungeKuttaOrder) {
19879 case 2: {
19880 if(!m_dualTimeStepping) { // -> timestep is constant (see rkAlpha init)
19881#ifdef _OPENMP
19882#pragma omp parallel for
19883#endif
19884 for(MUint cellId = m_activeCellIds[0]; cellId < last; ++cellId) {
19885 const MFloat factor = rkFactor * fCellVol[cellId];
19886 const MUint cellOffset = cellId * noCVars;
19887 const MUint cellRhsOffset = cellId * noFVars;
19888 const MFloat* const RESTRICT oldCellVars = oldVars + cellOffset;
19889 const MFloat* const RESTRICT cellRhs = rhs + cellRhsOffset;
19890 MFloat* const RESTRICT cellVars = vars + cellOffset;
19891
19892 cellVars[CV->RHO] = oldCellVars[CV->RHO] - factor * cellRhs[CV->RHO];
19893 for(MUint dir = 0; dir < nDim; dir++) {
19894 const MFloat C_1 = a_implicitCoefficient(cellId, dir * 2);
19895 const MFloat C_2 = a_implicitCoefficient(cellId, dir * 2 + 1);
19896 MFloat rhoAlpha = F1;
19897 if(cellVars[CV->RHO] > -m_EEGas.eps) {
19898 rhoAlpha = mMax(cellVars[CV->RHO], m_EEGas.eps);
19899 } else {
19900 rhoAlpha = cellVars[CV->RHO];
19901 }
19902 cellVars[CV->RHO_VV[dir]] = (-cellRhs[CV->RHO_VV[dir]] + C_1 + oldCellVars[CV->RHO_VV[dir]] / factor)
19903 / (F1 / factor - C_2 / rhoAlpha);
19904 }
19905 }
19906 } else {
19907 mTerm(1, AT_, "Dual timestepping not implemented for semi implicit EEGas!");
19908 }
19909 break;
19910 }
19911 default: {
19912 stringstream errorMessage;
19913 errorMessage << "Runge-Kutta Order (property 'rungeKuttaOrder) " << m_rungeKuttaOrder << " is not implemented.";
19914 mTerm(1, AT_, errorMessage.str());
19915 }
19916 }
19917
19918 m_RKStep++;
19919 if(m_RKStep == m_noRKSteps) {
19920 if(!m_dualTimeStepping) {
19921 m_physicalTime += dt * m_timeRef; // timestep is dimensionless t/a_0 (right)
19922 }
19923
19924 // Time is the "internal" time based on stagnation values
19925 m_time += dt;
19926 m_RKStep = 0;
19927
19928 return true;
19929 }
19930 return false;
19931}
19932
19937template <MInt nDim_, class SysEqn>
19939 const MUint noFVars = FV->noVariables;
19940 const MInt* const RESTRICT nghbrCellIds = ALIGNED_I(&a_surfaceNghbrCellId(0, 0));
19941 const MFloat* const RESTRICT fluxes = ALIGNED_F(&a_surfaceFlux(0, 0));
19942 MFloat* const RESTRICT rhs = ALIGNED_MF(&a_rightHandSide(0, 0));
19943
19944 // Loop is not OpenMP parallelizable!
19945 for(MUint srfcId = 0; srfcId < static_cast<MUint>(a_noSurfaces()); ++srfcId) {
19946 const MUint offset0 = nghbrCellIds[srfcId * 2] * noFVars;
19947 const MUint offset1 = nghbrCellIds[srfcId * 2 + 1] * noFVars;
19948 const MUint fluxOffset = srfcId * noFVars;
19949 const MFloat* const RESTRICT flux = ALIGNED_F(fluxes + fluxOffset);
19950 for(MUint var = 0; var < noFVars; ++var) {
19951 rhs[offset0 + var] += flux[var];
19952 rhs[offset1 + var] -= flux[var];
19953 }
19954 }
19955 // for E-E multiphase, the pressure term was collected seperately and has to be applied now
19956 IF_CONSTEXPR(isEEGas<SysEqn>) {
19957 const MUint noCells = a_noCells();
19958#ifdef _OPENMP
19959#pragma omp parallel for
19960#endif
19961 for(MUint cellId = 0; cellId < noCells; ++cellId) {
19962 const MFloat alpha = a_alphaGas(cellId);
19963 for(MUint i = 0; i < nDim; i++) {
19964 rhs[cellId * noFVars + CV->A_RHO_VV[i]] += rhs[cellId * noFVars + FV->P_RHO_VV[i]] * alpha;
19965 }
19966 }
19967 }
19968}
19969
19975template <MInt nDim_, class SysEqn>
19977 TRACE();
19978
19979 IF_CONSTEXPR(isDetChem<SysEqn>) { computeMeanMolarWeights_CV(); }
19980
19981 computePrimitiveVariables_();
19982
19983 computePrimitiveVariablesCoarseGrid(noInternalCells()); // return command for non-combustion computations
19984}
19985
19992template <MInt nDim, class SysEqn>
19994 const MUint noCells = a_noCells();
19995 const MUint noPVars = PV->noVariables;
19996 const MUint noCVars = CV->noVariables;
19997 const MUint noAVars = hasAV ? AV->noVariables : 0;
19998
19999 MFloat* const RESTRICT cvars = &a_variable(0, 0);
20000 MFloat* const RESTRICT pvars = &a_pvariable(0, 0);
20001 MFloat* const RESTRICT avars = hasAV ? &a_avariable(0, 0) : nullptr;
20002 const MFloat* const RESTRICT uOtherPhase = isEEGas<SysEqn> ? &a_uOtherPhase(0, 0) : nullptr;
20003
20004#ifdef _OPENMP
20005#pragma omp parallel for
20006#endif
20007 for(MUint cellId = 0; cellId < noCells; ++cellId) {
20008 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
20009 const MUint cellPVarOffset = cellId * noPVars;
20010 const MUint cellCVarOffset = cellId * noCVars;
20011 const MUint cellAVarOffset = hasAV ? cellId * noAVars : 0;
20012 const MFloat* const RESTRICT cvarsCell = cvars + cellCVarOffset;
20013 MFloat* const RESTRICT pvarsCell = pvars + cellPVarOffset;
20014 const MFloat* const RESTRICT avarsCell = hasAV ? avars + cellAVarOffset : nullptr;
20015 sysEqn().computePrimitiveVariables(cvarsCell, pvarsCell, avarsCell);
20016 }
20017 IF_CONSTEXPR(isEEGas<SysEqn>)
20018 if(m_EEGas.uDLimiter) {
20019#ifdef _OPENMP
20020#pragma omp parallel for
20021#endif
20022 for(MInt cellId = 0; cellId < m_bndryGhostCellsOffset; ++cellId) {
20023 const MInt cellPVarOffset = cellId * noPVars;
20024 const MInt cellCVarOffset = cellId * noCVars;
20025 const MUint cellAVarOffset = hasAV ? cellId * noAVars : 0;
20026 const MInt uOthOffset = cellId * nDim;
20027 MFloat* const RESTRICT pvarsCell = pvars + cellPVarOffset;
20028 MFloat* const RESTRICT cvarsCell = cvars + cellCVarOffset;
20029 const MFloat* const RESTRICT avarsCell = hasAV ? avars + cellAVarOffset : nullptr;
20030 const MFloat* const RESTRICT uOtherPhaseCell = uOtherPhase + uOthOffset;
20031 const MBool change = uDLimiter(uOtherPhaseCell, pvarsCell);
20032 if(change) sysEqn().computeConservativeVariables(pvarsCell, cvarsCell, avarsCell);
20033 }
20034 }
20035}
20036
20037//-------------------------------------------------------------------------------------------
20042template <MInt nDim_, class SysEqn>
20044 const MFloat* const cvarsCell = &a_variable(cellId, 0);
20045 MFloat* const pvarsCell = &a_pvariable(cellId, 0);
20046 const MFloat* const avarsCell = hasAV ? &a_avariable(cellId, 0) : nullptr;
20047
20048 IF_CONSTEXPR(isDetChem<SysEqn>) setMeanMolarWeight_CV(cellId);
20049
20050 sysEqn().computePrimitiveVariables(cvarsCell, pvarsCell, avarsCell);
20051
20052 IF_CONSTEXPR(isEEGas<SysEqn>) {
20053 MBool change = false;
20054 if(m_EEGas.uDLimiter) {
20055 change = uDLimiter(&a_uOtherPhase(cellId, 0), &a_pvariable(cellId, 0));
20056 }
20057 if(change) setConservativeVariables(cellId);
20058 }
20059}
20060
20067template <MInt nDim_, class SysEqn>
20069 const MUint noCells = a_noCells();
20070 const MUint noPVars = PV->noVariables;
20071 const MUint noCVars = CV->noVariables;
20072 const MUint noAVars = hasAV ? AV->noVariables : 0;
20073
20074 const MFloat* const RESTRICT pvars = &a_pvariable(0, 0);
20075 MFloat* const RESTRICT cvars = &a_variable(0, 0);
20076 MFloat* const RESTRICT avars = hasAV ? &a_avariable(0, 0) : nullptr;
20077
20078#ifdef _OPENMP
20079#pragma omp parallel for
20080#endif
20081 for(MUint cellId = 0; cellId < noCells; ++cellId) {
20082 const MUint cellPVarOffset = cellId * noPVars;
20083 const MUint cellCVarOffset = cellId * noCVars;
20084 const MUint cellAVarOffset = hasAV ? (cellId * noAVars) : 0;
20085 const MFloat* const RESTRICT pvarsCell = pvars + cellPVarOffset;
20086 MFloat* const RESTRICT cvarsCell = cvars + cellCVarOffset;
20087 const MFloat* const RESTRICT avarsCell = hasAV ? avars + cellAVarOffset : nullptr;
20088
20089 sysEqn().computeConservativeVariables(pvarsCell, cvarsCell, avarsCell);
20090 }
20091}
20092
20099template <MInt nDim_, class SysEqn>
20101 TRACE();
20102
20103 if(!m_combustion) { // since the function is called in the methods there is a return at this position for the other
20104 // maia users
20105 return;
20106 }
20107
20108 for(MInt level_ = maxLevel() - 1; level_ >= minLevel(); --level_) {
20109#ifdef _OPENMP
20110#pragma omp parallel for
20111#endif
20112 for(MInt cellId = 0; cellId < noCells; cellId++) {
20113 if(a_isBndryGhostCell(cellId)) continue;
20114
20115 if(level_ != a_level(cellId)) {
20116 continue;
20117 }
20118
20119 if(c_isLeafCell(cellId)) {
20120 continue;
20121 }
20122
20123 MInt noChildren = 0;
20124 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
20125 if(c_childId(cellId, childId) > -1) {
20126 noChildren++;
20127 }
20128 }
20129 if(noChildren == 0) {
20130 continue;
20131 }
20132
20133 const MFloat FnoChildren = F1 / (MFloat)noChildren;
20134
20135 for(MInt i = 0; i < PV->noVariables; i++) {
20136 a_pvariable(cellId, i) = F0;
20137 }
20138
20139 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
20140 if(c_childId(cellId, childId) < 0) {
20141 continue;
20142 }
20143
20144 for(MInt i = 0; i < PV->noVariables; i++) {
20145 a_pvariable(cellId, i) += FnoChildren * a_pvariable(c_childId(cellId, childId), i);
20146 // a_FcellVolume( c_childId( cellId , childId ) ) *a_pvariable( c_childId( cellId , childId ) , i );
20147 }
20148 }
20149 }
20150 }
20151 ASSERT(m_combustion, "someone changed the code -> this code is only needed for combustion computations");
20152}
20153
20154
20161template <MInt nDim_, class SysEqn>
20163 TRACE();
20164 if(!m_combustion) // just to be sure
20165 return;
20166
20167 MInt noCells = a_noCells();
20168
20169 computePrimitiveVariablesCoarseGrid(noCells);
20170 ASSERT(m_combustion, "someone changed the code -> this code is only needed for combustion computations");
20171}
20172
20179template <MInt nDim_, class SysEqn>
20181 TRACE();
20182 if(!m_combustion) // since the function is called in the methods there is a return at this position for the other maia
20183 // users
20184 return;
20185
20186 const MUint noCells = a_noCells();
20187
20188
20189 for(MInt level_ = maxLevel() - 1; level_ >= minLevel(); --level_) {
20190 for(MUint cellId = 0; cellId < noCells; cellId++) {
20191 if(a_isBndryGhostCell(cellId)) continue;
20192 if(level_ != a_level(cellId)) continue;
20193
20194 if(c_isLeafCell(cellId)) continue;
20195
20196 MInt noChildren = 0;
20197 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
20198 if(c_childId(cellId, childId) > -1) {
20199 noChildren++;
20200 }
20201 }
20202
20203 if(noChildren == 0) continue;
20204
20205 MFloat FnoChildren = 1.0 / noChildren;
20206
20207 for(MInt i = 0; i < CV->noVariables; i++) {
20208 a_variable(cellId, i) = F0;
20209 }
20210
20211 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
20212 if(c_childId(cellId, childId) < 0) continue;
20213
20214 for(MInt i = 0; i < CV->noVariables; i++) {
20215 a_variable(cellId, i) +=
20216 FnoChildren
20217 * a_variable(c_childId(cellId, childId), i); // a_FcellVolume( c_childId( cellId , childId ) ) *
20218 // a_variable(c_childId( cellId , childId ), i );
20219 }
20220 }
20221 }
20222 }
20223 ASSERT(m_combustion, "someone changed the code -> this code is only needed for combustion computations");
20224}
20225
20231template <MInt nDim_, class SysEqn>
20233 TRACE();
20234
20235 IF_CONSTEXPR(isDetChem<SysEqn>) { computeMeanMolarWeights_PV(); }
20236
20237 computeConservativeVariables_();
20238 computeConservativeVariablesCoarseGrid(); // return command for non-combustion computations
20239}
20240
20251template <MInt nDim_, class SysEqn>
20253 MFloat* vars) {
20254 TRACE();
20255 // Function pointer to a_pvariable
20256 std::function<MFloat(const MInt, const MInt)> varPtr = [&](const MInt cellId_, const MInt varId_) {
20257 return static_cast<MFloat>(a_pvariable(cellId_, varId_));
20258 };
20259 interpolateVariablesInCell<0, nDim + 2>(cellId, position, varPtr, vars);
20260 ASSERT(noVariables() == nDim + 2, "ERROR: Number of variables not correct.");
20261}
20262
20263
20274template <MInt nDim_, class SysEqn>
20276 MFloat* vars) {
20277 // TRACE();
20278
20279 interpolateVariables<0, nDim + 2>(cellId, position, vars);
20280
20281 ASSERT(noVariables() == nDim + 2, "ERROR: Number of variables not correct.");
20282}
20283
20284
20295template <MInt nDim_, class SysEqn>
20296template <MInt noSpecies>
20298 MFloat* vars) {
20299 // TRACE();
20300
20301 interpolateVariables<0, nDim + 2 + noSpecies>(cellId, position, vars);
20302
20303 ASSERT(noVariables() == nDim + 2 + noSpecies, "ERROR: Number of variables not correct.");
20304}
20305
20306
20317template <MInt nDim_, class SysEqn>
20318template <MInt a, MInt b, MBool old>
20320 MFloat* interpolatedVar) {
20321 // TRACE();
20322 ASSERT((b - a) > 0, "ERROR: Difference between b and a needs to be positive!");
20323 ASSERT(cellId >= 0, "ERROR: Invalid cellId!");
20324
20325 const MFloat originX = a_coordinate(cellId, 0);
20326 const MFloat originY = a_coordinate(cellId, 1);
20327 const MFloat originZ = a_coordinate(cellId, 2);
20328
20332 vector<MInt> nghbrList;
20333#ifdef _OPENMP
20334#pragma omp critical
20335#endif
20336 {
20337 if(m_cellToNghbrHood.count(cellId) > 0) {
20338 nghbrList = m_cellToNghbrHood[cellId];
20339 // std::cout << "Old use existing hood with " << nghbrList.size() << " for " << cellId << std::endl;
20340 } else {
20341 findDirectNghbrs(cellId, nghbrList);
20342 // std::cout << "Old find hood with " << nghbrList.size() << std::endl;
20343 if(nghbrList.size() < 12) {
20344 findNeighborHood(cellId, 2, nghbrList);
20345 // std::cout << "Old find better hood with " << nghbrList.size() << std::endl;
20346#ifndef NDEBUG
20347 if(nghbrList.size() < 14) {
20348 cout << "WARNING: Only found " << nghbrList.size() << " neighbors during interpolation!" << endl;
20349 }
20350#endif
20351 }
20352 m_cellToNghbrHood.emplace(make_pair(cellId, nghbrList));
20353 }
20354 }
20355
20356 // std::cout << "Old Interpolation with " << nghbrList.size() << " points" << std::endl;
20357
20358 // check for boundary ghost cells belonging to cells in the neighbor list
20359 // for these cell a pseudoCell element is added, carrying position and velocity
20360 // on the boundary surface
20361 vector<array<MFloat, b - a>> pseudoCellVar(nghbrList.size());
20362 vector<array<MFloat, nDim>> pseudoCellPos(nghbrList.size());
20363
20364 for(MUint nId = 0; nId < nghbrList.size(); nId++) {
20365 const MInt nghbrId = nghbrList[nId];
20366 if(nghbrId >= 0 && a_bndryId(nghbrId) > -1) {
20367 // mark as pseudo cell
20368 nghbrList[nId] = -1;
20369 for(MInt i = 0; i < nDim; i++) {
20370 pseudoCellPos[nId][i] = m_bndryCells->a[a_bndryId(nghbrId)].m_srfcs[0]->m_coordinates[i];
20371 }
20372
20373 // const MInt bndryCndId = m_fvBndryCnd->m_bndryCndIds[a_bndryId(nghbrId)];
20374
20375 for(MInt i = a; i < b; i++) {
20376 // todo labels:FV bndCnd need to be implemented here (assumes bnd result equals cell result)
20377 if(old) {
20378 pseudoCellVar[nId][i - a] = a_oldVariable(cellId, i);
20379 } else {
20380 pseudoCellVar[nId][i - a] = a_variable(cellId, i);
20381 }
20382 }
20383
20384 // if(bndryCndId == 3003){ //no-slip wall
20385 // for(MInt i = a; i < 3; i++){
20386 // pseudoCellVar[nId][i - a] = 0;
20387 // }
20388 // }
20389 }
20390 }
20391 // std::cout << "Old interpolation with " << nghbrList.size() << " points at cell gid " << c_globalId(cellId) <<
20392 // std::endl;
20393 for(MUint nId = 0; nId < nghbrList.size(); nId++) {
20394 const MInt nghbrId = nghbrList[nId];
20395 // const MFloat a0 = 343.203775724;
20396 if(a_bndryId(nghbrId) > -1) {
20397 // std::cout << "Old outside " << pseudoCellVar[nId][0]*a0 << " " << pseudoCellVar[nId][1]*a0 << " " <<
20398 // pseudoCellVar[nId][2]*a0 << std::endl;
20399 } else {
20400 // std::cout << "Old inside " << a_variable(nghbrId,0)*a0 << " " << a_variable(nghbrId,1)*a0 << " " <<
20401 // a_variable(nghbrId,2)*a0 << std::endl;
20402 }
20403 }
20404
20407 if(nghbrList.size() < 10) {
20408 vector<MFloat> dist(nghbrList.size(), 0);
20409 for(MUint nId = 0; nId < nghbrList.size(); nId++) {
20410 const MInt nghbrId = nghbrList[nId];
20411 // calculate distance for each neighbor to the origin
20412 if(nghbrId < 0) {
20413 IF_CONSTEXPR(nDim == 2) {
20414 dist[nId] = POW2(pseudoCellPos[nId][0] - position[0]) + POW2(pseudoCellPos[nId][1] - position[1]);
20415 }
20416 else {
20417 dist[nId] = POW2(pseudoCellPos[nId][0] - position[0]) + POW2(pseudoCellPos[nId][1] - position[1])
20418 + POW2(pseudoCellPos[nId][2] - position[2]);
20419 }
20420 } else {
20421 IF_CONSTEXPR(nDim == 2) {
20422 dist[nId] = POW2(a_coordinate(nghbrId, 0) - position[0]) + POW2(a_coordinate(nghbrId, 1) - position[1]);
20423 }
20424 else {
20425 dist[nId] = POW2(a_coordinate(nghbrId, 0) - position[0]) + POW2(a_coordinate(nghbrId, 1) - position[1])
20426 + POW2(a_coordinate(nghbrId, 2) - position[2]);
20427 }
20428 }
20429 }
20430
20431 MFloat sum = accumulate(dist.begin(), dist.end(), 0.0);
20432
20433 for(MInt k = a; k < b; k++) {
20434 MFloat var = 0;
20435 interpolatedVar[k] = 0.0;
20436
20437 for(MUint nId = 1; nId < nghbrList.size(); nId++) {
20438 const MInt nghbrId = nghbrList[nId];
20439 if(nghbrId < 0) {
20440 var = pseudoCellVar[nId][k - a];
20441 } else {
20442 if(old) {
20443 var = a_oldVariable(nghbrId, k);
20444 } else {
20445 var = a_variable(nghbrId, k);
20446 }
20447 }
20448 interpolatedVar[k] += dist[nId] / sum * var;
20449 }
20450 }
20451
20452#ifndef NDEBUG
20453 // cout << "WARNING: Not enough neighbors found to use LS using weighted averaging instead!" << endl;
20454 m_log << "WARNING: Not enough neighbors found to use LS using weighted averaging instead!" << endl;
20455#endif
20456 } else {
20460 MFloatTensor LSMatrix(2 * nDim + pow(2, nDim - 1), 2 * nDim + pow(2, nDim - 1));
20461 MFloatTensor rhs(2 * nDim + pow(2, nDim - 1));
20462 // MFloatTensor weights(2 * nDim + pow(2, nDim - 1));
20463 MFloatTensor matInv(2 * nDim + pow(2, nDim - 1), 2 * nDim + pow(2, nDim - 1));
20464
20465 LSMatrix.set(0.0);
20466 // weights.set(1.0);
20467 matInv.set(0.0);
20468
20469 MFloat sumX = 0;
20470 MFloat sumY = 0;
20471 MFloat sumZ = 0;
20472 MFloat sumXY = 0;
20473 MFloat sumXZ = 0;
20474 MFloat sumYZ = 0;
20475 MFloat sumX2 = 0;
20476 MFloat sumY2 = 0;
20477 MFloat sumZ2 = 0;
20478 MFloat sumXYZ = 0;
20479 MFloat sumX2Y = 0;
20480 MFloat sumX2Z = 0;
20481 MFloat sumXY2 = 0;
20482 MFloat sumY2Z = 0;
20483 MFloat sumXZ2 = 0;
20484 MFloat sumYZ2 = 0;
20485 MFloat sumX3 = 0;
20486 MFloat sumY3 = 0;
20487 MFloat sumZ3 = 0;
20488 MFloat sumX3Y = 0;
20489 MFloat sumX3Z = 0;
20490 MFloat sumXY3 = 0;
20491 MFloat sumY3Z = 0;
20492 MFloat sumXZ3 = 0;
20493 MFloat sumYZ3 = 0;
20494 MFloat sumX2Y2 = 0;
20495 MFloat sumX2Z2 = 0;
20496 MFloat sumX2YZ = 0;
20497 MFloat sumY2Z2 = 0;
20498 MFloat sumXY2Z = 0;
20499 MFloat sumXYZ2 = 0;
20500 MFloat sumX4 = 0;
20501 MFloat sumY4 = 0;
20502 MFloat sumZ4 = 0;
20503
20504
20505 // 2.1 Calculate intermediate variables
20506 for(MUint nId = 1; nId < nghbrList.size(); nId++) {
20507 MFloat x = 0;
20508 MFloat y = 0;
20509 MFloat z = 0;
20510 const MInt nghbrId = nghbrList[nId];
20511 if(nghbrId < 0) {
20512 x = pseudoCellPos[nId][0] - originX;
20513 y = pseudoCellPos[nId][1] - originY;
20514 IF_CONSTEXPR(nDim == 3) { z = pseudoCellPos[nId][2] - originZ; }
20515 } else {
20516 x = a_coordinate(nghbrId, 0) - originX;
20517 y = a_coordinate(nghbrId, 1) - originY;
20518 IF_CONSTEXPR(nDim == 3) { z = a_coordinate(nghbrId, 2) - originZ; }
20519 }
20520
20521 sumX += x;
20522 sumY += y;
20523 sumZ += z;
20524 sumXY += x * y;
20525 sumXZ += x * z;
20526 sumYZ += y * z;
20527 sumX2 += x * x;
20528 sumY2 += y * y;
20529 sumZ2 += z * z;
20530 sumXYZ += x * y * z;
20531 sumX2Y += x * x * y;
20532 sumX2Z += x * x * z;
20533 sumXY2 += x * y * y;
20534 sumY2Z += y * y * z;
20535 sumXZ2 += z * z * x;
20536 sumYZ2 += z * z * y;
20537 sumX3 += x * x * x;
20538 sumY3 += y * y * y;
20539 sumZ3 += z * z * z;
20540 sumX3Y += x * x * x * y;
20541 sumX3Z += x * x * x * z;
20542 sumXY3 += y * y * y * x;
20543 sumY3Z += y * y * y * z;
20544 sumXZ3 += z * z * z * x;
20545 sumYZ3 += z * z * z * y;
20546 sumX2Y2 += x * x * y * y;
20547 sumX2Z2 += x * x * z * z;
20548 sumX2YZ += x * x * y * z;
20549 sumY2Z2 += y * y * z * z;
20550 sumXY2Z += x * y * y * z;
20551 sumXYZ2 += x * y * z * z;
20552 sumX4 += x * x * x * x;
20553 sumY4 += y * y * y * y;
20554 sumZ4 += z * z * z * z;
20555 }
20556
20557 // 2.2 Use intermediate variables to build LSMatrix
20558 IF_CONSTEXPR(nDim == 2) {
20559 // diagonal
20560 LSMatrix(0, 0) = sumX4;
20561 LSMatrix(1, 1) = sumY4;
20562 LSMatrix(2, 2) = sumX2Y2;
20563 LSMatrix(3, 3) = sumX2;
20564 LSMatrix(4, 4) = sumY2;
20565 LSMatrix(5, 5) = nghbrList.size();
20566
20567 // first column/row
20568 LSMatrix(0, 1) = LSMatrix(1, 0) = sumX2Y2;
20569 LSMatrix(0, 2) = LSMatrix(2, 0) = sumX3Y;
20570 LSMatrix(0, 3) = LSMatrix(3, 0) = sumX3;
20571 LSMatrix(0, 4) = LSMatrix(4, 0) = sumX2Y;
20572 LSMatrix(0, 5) = LSMatrix(5, 0) = sumX2;
20573
20574 // second column/row
20575 LSMatrix(1, 2) = LSMatrix(2, 1) = sumXY3;
20576 LSMatrix(1, 3) = LSMatrix(3, 1) = sumXY2;
20577 LSMatrix(1, 4) = LSMatrix(4, 1) = sumY3;
20578 LSMatrix(1, 5) = LSMatrix(5, 1) = sumY2;
20579
20580 // third column/row
20581 LSMatrix(2, 3) = LSMatrix(3, 2) = sumX2Y;
20582 LSMatrix(2, 4) = LSMatrix(4, 2) = sumXY2;
20583 LSMatrix(2, 5) = LSMatrix(5, 2) = sumXY;
20584
20585 // fourth column/row
20586 LSMatrix(3, 4) = LSMatrix(4, 3) = sumXY;
20587 LSMatrix(3, 5) = LSMatrix(5, 3) = sumX;
20588
20589 // fifth coulmn/row
20590 LSMatrix(4, 5) = LSMatrix(5, 4) = sumY;
20591 }
20592 else {
20593 // diagonal
20594 LSMatrix(0, 0) = sumX4;
20595 LSMatrix(1, 1) = sumY4;
20596 LSMatrix(2, 2) = sumZ4;
20597 LSMatrix(3, 3) = sumX2Y2;
20598 LSMatrix(4, 4) = sumX2Z2;
20599 LSMatrix(5, 5) = sumY2Z2;
20600 LSMatrix(6, 6) = sumX2;
20601 LSMatrix(7, 7) = sumY2;
20602 LSMatrix(8, 8) = sumZ2;
20603 LSMatrix(9, 9) = nghbrList.size();
20604
20605 // first column/row
20606 LSMatrix(0, 1) = LSMatrix(1, 0) = sumX2Y2;
20607 LSMatrix(0, 2) = LSMatrix(2, 0) = sumX2Z2;
20608 LSMatrix(0, 3) = LSMatrix(3, 0) = sumX3Y;
20609 LSMatrix(0, 4) = LSMatrix(4, 0) = sumX3Z;
20610 LSMatrix(0, 5) = LSMatrix(5, 0) = sumX2YZ;
20611 LSMatrix(0, 6) = LSMatrix(6, 0) = sumX3;
20612 LSMatrix(0, 7) = LSMatrix(7, 0) = sumX2Y;
20613 LSMatrix(0, 8) = LSMatrix(8, 0) = sumX2Z;
20614 LSMatrix(0, 9) = LSMatrix(9, 0) = sumX2;
20615
20616 // second column/row
20617 LSMatrix(1, 2) = LSMatrix(2, 1) = sumY2Z2;
20618 LSMatrix(1, 3) = LSMatrix(3, 1) = sumXY3;
20619 LSMatrix(1, 4) = LSMatrix(4, 1) = sumXY2Z;
20620 LSMatrix(1, 5) = LSMatrix(5, 1) = sumY3Z;
20621 LSMatrix(1, 6) = LSMatrix(6, 1) = sumXY2;
20622 LSMatrix(1, 7) = LSMatrix(7, 1) = sumY3;
20623 LSMatrix(1, 8) = LSMatrix(8, 1) = sumY2Z;
20624 LSMatrix(1, 9) = LSMatrix(9, 1) = sumY2;
20625
20626 // third column/row
20627 LSMatrix(2, 3) = LSMatrix(3, 2) = sumXYZ2;
20628 LSMatrix(2, 4) = LSMatrix(4, 2) = sumXZ3;
20629 LSMatrix(2, 5) = LSMatrix(5, 2) = sumYZ3;
20630 LSMatrix(2, 6) = LSMatrix(6, 2) = sumXZ2;
20631 LSMatrix(2, 7) = LSMatrix(7, 2) = sumYZ2;
20632 LSMatrix(2, 8) = LSMatrix(8, 2) = sumZ3;
20633 LSMatrix(2, 9) = LSMatrix(9, 2) = sumZ2;
20634
20635 // fourth column, fourth line
20636 LSMatrix(3, 4) = LSMatrix(4, 3) = sumX2YZ;
20637 LSMatrix(3, 5) = LSMatrix(5, 3) = sumXY2Z;
20638 LSMatrix(3, 6) = LSMatrix(6, 3) = sumX2Y;
20639 LSMatrix(3, 7) = LSMatrix(7, 3) = sumXY2;
20640 LSMatrix(3, 8) = LSMatrix(8, 3) = sumXYZ;
20641 LSMatrix(3, 9) = LSMatrix(9, 3) = sumXY;
20642
20643 // fifth coulmn, fifth line
20644 LSMatrix(4, 5) = LSMatrix(5, 4) = sumXYZ2;
20645 LSMatrix(4, 6) = LSMatrix(6, 4) = sumX2Z;
20646 LSMatrix(4, 7) = LSMatrix(7, 4) = sumXYZ;
20647 LSMatrix(4, 8) = LSMatrix(8, 4) = sumXZ2;
20648 LSMatrix(4, 9) = LSMatrix(9, 4) = sumXZ;
20649
20650 // sixth column, sixth line
20651 LSMatrix(5, 6) = LSMatrix(6, 5) = sumXYZ;
20652 LSMatrix(5, 7) = LSMatrix(7, 5) = sumY2Z;
20653 LSMatrix(5, 8) = LSMatrix(8, 5) = sumYZ2;
20654 LSMatrix(5, 9) = LSMatrix(9, 5) = sumYZ;
20655
20656 // seventh column, seventh line
20657 LSMatrix(6, 7) = LSMatrix(7, 6) = sumXY;
20658 LSMatrix(6, 8) = LSMatrix(8, 6) = sumXZ;
20659 LSMatrix(6, 9) = LSMatrix(9, 6) = sumX;
20660
20661 // eigth column, eigth line
20662 LSMatrix(7, 8) = LSMatrix(8, 7) = sumYZ;
20663 LSMatrix(7, 9) = LSMatrix(9, 7) = sumY;
20664
20665 // nineth column, nineth line
20666 LSMatrix(8, 9) = LSMatrix(9, 8) = sumZ;
20667 }
20668
20669 // 2.3 scale solution since the condition number gets really bad for large discrepancies in cell size
20670 const MFloat normalizationFactor = FPOW2(2 * a_level(cellId)) / c_cellLengthAtLevel(0);
20671 for(MInt i = 0; i < 2 * nDim + pow(2, nDim - 1); i++) {
20672 for(MInt j = 0; j < 2 * nDim + pow(2, nDim - 1); j++) {
20673 LSMatrix(i, j) *= normalizationFactor;
20674 }
20675 }
20676
20677 // 2.4 determine the pseudoinverse using SVD
20678 maia::math::invert(LSMatrix, matInv, 2 * nDim + pow(2, nDim - 1), 2 * nDim + pow(2, nDim - 1));
20679
20683 for(MInt k = a; k < b; k++) {
20684 MFloat sumVar = 0;
20685 if(old) {
20686 sumVar = a_oldVariable(cellId, k);
20687 } else {
20688 sumVar = a_variable(cellId, k);
20689 }
20690 MFloat sumVarX = 0;
20691 MFloat sumVarY = 0;
20692 MFloat sumVarZ = 0;
20693 MFloat sumVarXY = 0;
20694 MFloat sumVarXZ = 0;
20695 MFloat sumVarYZ = 0;
20696 MFloat sumVarX2 = 0;
20697 MFloat sumVarY2 = 0;
20698 MFloat sumVarZ2 = 0;
20699
20700 rhs.set(0.0);
20701
20702 // 3.1 Calculate intermediate variables
20703 for(MUint nId = 1; nId < nghbrList.size(); nId++) {
20704 MFloat x = 0;
20705 MFloat y = 0;
20706 MFloat z = 0;
20707 MFloat var = 0;
20708 const MInt nghbrId = nghbrList[nId];
20709 if(nghbrId < 0) {
20710 x = pseudoCellPos[nId][0] - originX;
20711 y = pseudoCellPos[nId][1] - originY;
20712 var = pseudoCellVar[nId][k - a];
20713
20714 IF_CONSTEXPR(nDim == 3) { z = pseudoCellPos[nId][2] - originZ; }
20715 } else {
20716 x = a_coordinate(nghbrId, 0) - originX;
20717 y = a_coordinate(nghbrId, 1) - originY;
20718 if(old) {
20719 var = a_oldVariable(nghbrId, k);
20720 } else {
20721 var = a_variable(nghbrId, k);
20722 }
20723 IF_CONSTEXPR(nDim == 3) { z = a_coordinate(nghbrId, 2) - originZ; }
20724 }
20725
20726 sumVar += var;
20727 sumVarX += var * x;
20728 sumVarY += var * y;
20729 sumVarZ += var * z;
20730 sumVarXY += var * x * y;
20731 sumVarXZ += var * x * z;
20732 sumVarYZ += var * y * z;
20733 sumVarX2 += var * x * x;
20734 sumVarY2 += var * y * y;
20735 sumVarZ2 += var * z * z;
20736 }
20737
20738 // 3.2 assign intermediate variables to rhs
20739 IF_CONSTEXPR(nDim == 2) {
20740 rhs[0] = sumVarX2;
20741 rhs[1] = sumVarY2;
20742 rhs[2] = sumVarXY;
20743 rhs[3] = sumVarX;
20744 rhs[4] = sumVarY;
20745 rhs[5] = sumVar;
20746 }
20747 else {
20748 rhs(0) = sumVarX2;
20749 rhs(1) = sumVarY2;
20750 rhs(2) = sumVarZ2;
20751 rhs(3) = sumVarXY;
20752 rhs(4) = sumVarXZ;
20753 rhs(5) = sumVarYZ;
20754 rhs(6) = sumVarX;
20755 rhs(7) = sumVarY;
20756 rhs(8) = sumVarZ;
20757 rhs(9) = sumVar;
20758 }
20759
20760 // 3.3 scale rhs
20761 for(MInt i = 0; i < 2 * nDim + pow(2, nDim - 1); i++) {
20762 rhs(i) *= normalizationFactor;
20763 }
20764
20765 MFloatTensor coeff(2 * nDim + pow(2, nDim - 1));
20766 coeff.set(0.0);
20767
20768 // 3.4 determine coefficients of the aim function polynomial
20769 for(MInt i = 0; i < 2 * nDim + pow(2, nDim - 1); i++) {
20770 for(MInt j = 0; j < 2 * nDim + pow(2, nDim - 1); j++) {
20771 coeff(i) += matInv(i, j) * rhs(j);
20772 }
20773 }
20774
20778 MFloat positionX = position[0] - originX;
20779 MFloat positionY = position[1] - originY;
20780 MFloat positionZ = 0;
20781 IF_CONSTEXPR(nDim == 3) { positionZ = position[2] - originZ; }
20782 MFloat result = coeff((MInt)(2 * nDim + pow(2, nDim - 1) - 1));
20783 IF_CONSTEXPR(nDim == 2) {
20784 result += coeff(0) * positionX * positionX;
20785 result += coeff(1) * positionY * positionY;
20786 result += coeff(2) * positionX * positionY;
20787 result += coeff(3) * positionX;
20788 result += coeff(4) * positionY;
20789 }
20790 else {
20791 result += coeff(0) * positionX * positionX;
20792 result += coeff(1) * positionY * positionY;
20793 result += coeff(2) * positionZ * positionZ;
20794 result += coeff(3) * positionX * positionY;
20795 result += coeff(4) * positionX * positionZ;
20796 result += coeff(5) * positionY * positionZ;
20797 result += coeff(6) * positionX;
20798 result += coeff(7) * positionY;
20799 result += coeff(8) * positionZ;
20800 }
20801
20802 interpolatedVar[k - a] = result;
20803 }
20804 }
20805
20806 // TRACE_OUT();
20807}
20808
20809
20811template <MInt nDim_, class SysEqn>
20813 ASSERT(cellId >= 0, "ERROR: Invalid cellId!");
20814
20815 if(m_cellInterpolationIndex[cellId] != -1) {
20816 /* std::cerr << "Interpolation for cell " << cellId << " already initialndized." << std::endl; */
20817 return;
20818 }
20819
20820 const MFloat* const origin = &a_coordinate(cellId, 0);
20821
20825 vector<MInt> nghbrList;
20826#ifdef _OPENMP
20827#pragma omp critical
20828#endif
20829 {
20830 findDirectNghbrs(cellId, nghbrList);
20831 if(nghbrList.size() < 12) {
20832 findNeighborHood(cellId, 2, nghbrList);
20833#ifndef NDEBUG
20834 if(nghbrList.size() < 14) {
20835 cout << "WARNING: Only found " << nghbrList.size() << " neighbors during interpolation!" << endl;
20836 }
20837#endif
20838 }
20839 }
20840
20841 // check for boundary ghost cells belonging to cells in the neighbor list
20842 // for these cell a pseudoCell element is added, carrying position and velocity
20843 // on the boundary surface
20844 /* vector<vector<MFloat>> pseudoCellVar(nghbrList.size(), vector<MFloat>(b - a)); */
20845 /* vector<vector<MFloat>> pseudoCellPos(nghbrList.size(), {0, 0, 0}); */
20846
20847 for(MUint nId = 0; nId < nghbrList.size(); nId++) {
20848 const MInt nghbrId = nghbrList[nId];
20849 if(nghbrId >= 0 && a_bndryId(nghbrId) > -1) {
20850 mTerm(1, "boundary cells not handled");
20851 // mark as pseudo cell
20852 /* nghbrList[nId] = -1; */
20853 /* for (MInt i = 0; i < nDim; i++) { */
20854 /* pseudoCellPos[nId][i] = m_bndryCells->a[a_bndryId(nghbrId)].m_srfcs[0]->m_coordinates[i]; */
20855 /* } */
20856 /* for (MInt i = a; i < b; i++) { */
20857 /* // todo labels:FV,toenhance bndCnd need to be implemented here (assumes bnd result equals cell result) */
20858 /* if(old){ */
20859 /* pseudoCellVar[nId][i - a] = a_oldVariable(cellId, i); */
20860 /* } else { */
20861 /* pseudoCellVar[nId][i - a] = a_variable(cellId, i); */
20862 /* } */
20863 /* } */
20864 }
20865 }
20866
20867 if(nghbrList.size() < 10) {
20868 mTerm(1, "too few neighbors");
20869 }
20870
20874 MFloatTensor LSMatrix(2 * nDim + pow(2, nDim - 1), 2 * nDim + pow(2, nDim - 1));
20875 /* MFloatTensor rhs(2 * nDim + pow(2, nDim - 1)); */
20876 // MFloatTensor weights(2 * nDim + pow(2, nDim - 1));
20877 MFloatTensor matInv(2 * nDim + pow(2, nDim - 1), 2 * nDim + pow(2, nDim - 1));
20878
20879 LSMatrix.set(0.0);
20880 // weights.set(1.0);
20881 matInv.set(0.0);
20882
20883 MFloat sumX = 0;
20884 MFloat sumY = 0;
20885 MFloat sumZ = 0;
20886 MFloat sumXY = 0;
20887 MFloat sumXZ = 0;
20888 MFloat sumYZ = 0;
20889 MFloat sumX2 = 0;
20890 MFloat sumY2 = 0;
20891 MFloat sumZ2 = 0;
20892 MFloat sumXYZ = 0;
20893 MFloat sumX2Y = 0;
20894 MFloat sumX2Z = 0;
20895 MFloat sumXY2 = 0;
20896 MFloat sumY2Z = 0;
20897 MFloat sumXZ2 = 0;
20898 MFloat sumYZ2 = 0;
20899 MFloat sumX3 = 0;
20900 MFloat sumY3 = 0;
20901 MFloat sumZ3 = 0;
20902 MFloat sumX3Y = 0;
20903 MFloat sumX3Z = 0;
20904 MFloat sumXY3 = 0;
20905 MFloat sumY3Z = 0;
20906 MFloat sumXZ3 = 0;
20907 MFloat sumYZ3 = 0;
20908 MFloat sumX2Y2 = 0;
20909 MFloat sumX2Z2 = 0;
20910 MFloat sumX2YZ = 0;
20911 MFloat sumY2Z2 = 0;
20912 MFloat sumXY2Z = 0;
20913 MFloat sumXYZ2 = 0;
20914 MFloat sumX4 = 0;
20915 MFloat sumY4 = 0;
20916 MFloat sumZ4 = 0;
20917
20918
20919 // 2.1 Calculate intermediate variables
20920 for(MUint nId = 1; nId < nghbrList.size(); nId++) {
20921 MFloat x = 0;
20922 MFloat y = 0;
20923 MFloat z = 0;
20924 const MInt nghbrId = nghbrList[nId];
20925 if(nghbrId < 0) {
20926 mTerm(1, "not supported");
20927 }
20928 /* x = pseudoCellPos[nId][0] - originX; */
20929 /* y = pseudoCellPos[nId][1] - originY; */
20930 /* IF_CONSTEXPR(nDim == 3) { */
20931 /* z = pseudoCellPos[nId][2] - originZ; */
20932 /* } */
20933 /* } else { */
20934 x = a_coordinate(nghbrId, 0) - origin[0];
20935 y = a_coordinate(nghbrId, 1) - origin[1];
20936 IF_CONSTEXPR(nDim == 3) { z = a_coordinate(nghbrId, 2) - origin[2]; }
20937 /* } */
20938
20939 sumX += x;
20940 sumY += y;
20941 sumZ += z;
20942 sumXY += x * y;
20943 sumXZ += x * z;
20944 sumYZ += y * z;
20945 sumX2 += x * x;
20946 sumY2 += y * y;
20947 sumZ2 += z * z;
20948 sumXYZ += x * y * z;
20949 sumX2Y += x * x * y;
20950 sumX2Z += x * x * z;
20951 sumXY2 += x * y * y;
20952 sumY2Z += y * y * z;
20953 sumXZ2 += z * z * x;
20954 sumYZ2 += z * z * y;
20955 sumX3 += x * x * x;
20956 sumY3 += y * y * y;
20957 sumZ3 += z * z * z;
20958 sumX3Y += x * x * x * y;
20959 sumX3Z += x * x * x * z;
20960 sumXY3 += y * y * y * x;
20961 sumY3Z += y * y * y * z;
20962 sumXZ3 += z * z * z * x;
20963 sumYZ3 += z * z * z * y;
20964 sumX2Y2 += x * x * y * y;
20965 sumX2Z2 += x * x * z * z;
20966 sumX2YZ += x * x * y * z;
20967 sumY2Z2 += y * y * z * z;
20968 sumXY2Z += x * y * y * z;
20969 sumXYZ2 += x * y * z * z;
20970 sumX4 += x * x * x * x;
20971 sumY4 += y * y * y * y;
20972 sumZ4 += z * z * z * z;
20973 }
20974
20975 // 2.2 Use intermediate variables to build LSMatrix
20976 IF_CONSTEXPR(nDim == 2) {
20977 // diagonal
20978 LSMatrix(0, 0) = sumX4;
20979 LSMatrix(1, 1) = sumY4;
20980 LSMatrix(2, 2) = sumX2Y2;
20981 LSMatrix(3, 3) = sumX2;
20982 LSMatrix(4, 4) = sumY2;
20983 LSMatrix(5, 5) = nghbrList.size();
20984
20985 // first column/row
20986 LSMatrix(0, 1) = LSMatrix(1, 0) = sumX2Y2;
20987 LSMatrix(0, 2) = LSMatrix(2, 0) = sumX3Y;
20988 LSMatrix(0, 3) = LSMatrix(3, 0) = sumX3;
20989 LSMatrix(0, 4) = LSMatrix(4, 0) = sumX2Y;
20990 LSMatrix(0, 5) = LSMatrix(5, 0) = sumX2;
20991
20992 // second column/row
20993 LSMatrix(1, 2) = LSMatrix(2, 1) = sumXY3;
20994 LSMatrix(1, 3) = LSMatrix(3, 1) = sumXY2;
20995 LSMatrix(1, 4) = LSMatrix(4, 1) = sumY3;
20996 LSMatrix(1, 5) = LSMatrix(5, 1) = sumY2;
20997
20998 // third column/row
20999 LSMatrix(2, 3) = LSMatrix(3, 2) = sumX2Y;
21000 LSMatrix(2, 4) = LSMatrix(4, 2) = sumXY2;
21001 LSMatrix(2, 5) = LSMatrix(5, 2) = sumXY;
21002
21003 // fourth column/row
21004 LSMatrix(3, 4) = LSMatrix(4, 3) = sumXY;
21005 LSMatrix(3, 5) = LSMatrix(5, 3) = sumX;
21006
21007 // fifth coulmn/row
21008 LSMatrix(4, 5) = LSMatrix(5, 4) = sumY;
21009 }
21010 else {
21011 // diagonal
21012 LSMatrix(0, 0) = sumX4;
21013 LSMatrix(1, 1) = sumY4;
21014 LSMatrix(2, 2) = sumZ4;
21015 LSMatrix(3, 3) = sumX2Y2;
21016 LSMatrix(4, 4) = sumX2Z2;
21017 LSMatrix(5, 5) = sumY2Z2;
21018 LSMatrix(6, 6) = sumX2;
21019 LSMatrix(7, 7) = sumY2;
21020 LSMatrix(8, 8) = sumZ2;
21021 LSMatrix(9, 9) = nghbrList.size();
21022
21023 // first column/row
21024 LSMatrix(0, 1) = LSMatrix(1, 0) = sumX2Y2;
21025 LSMatrix(0, 2) = LSMatrix(2, 0) = sumX2Z2;
21026 LSMatrix(0, 3) = LSMatrix(3, 0) = sumX3Y;
21027 LSMatrix(0, 4) = LSMatrix(4, 0) = sumX3Z;
21028 LSMatrix(0, 5) = LSMatrix(5, 0) = sumX2YZ;
21029 LSMatrix(0, 6) = LSMatrix(6, 0) = sumX3;
21030 LSMatrix(0, 7) = LSMatrix(7, 0) = sumX2Y;
21031 LSMatrix(0, 8) = LSMatrix(8, 0) = sumX2Z;
21032 LSMatrix(0, 9) = LSMatrix(9, 0) = sumX2;
21033
21034 // second column/row
21035 LSMatrix(1, 2) = LSMatrix(2, 1) = sumY2Z2;
21036 LSMatrix(1, 3) = LSMatrix(3, 1) = sumXY3;
21037 LSMatrix(1, 4) = LSMatrix(4, 1) = sumXY2Z;
21038 LSMatrix(1, 5) = LSMatrix(5, 1) = sumY3Z;
21039 LSMatrix(1, 6) = LSMatrix(6, 1) = sumXY2;
21040 LSMatrix(1, 7) = LSMatrix(7, 1) = sumY3;
21041 LSMatrix(1, 8) = LSMatrix(8, 1) = sumY2Z;
21042 LSMatrix(1, 9) = LSMatrix(9, 1) = sumY2;
21043
21044 // third column/row
21045 LSMatrix(2, 3) = LSMatrix(3, 2) = sumXYZ2;
21046 LSMatrix(2, 4) = LSMatrix(4, 2) = sumXZ3;
21047 LSMatrix(2, 5) = LSMatrix(5, 2) = sumYZ3;
21048 LSMatrix(2, 6) = LSMatrix(6, 2) = sumXZ2;
21049 LSMatrix(2, 7) = LSMatrix(7, 2) = sumYZ2;
21050 LSMatrix(2, 8) = LSMatrix(8, 2) = sumZ3;
21051 LSMatrix(2, 9) = LSMatrix(9, 2) = sumZ2;
21052
21053 // fourth column, fourth line
21054 LSMatrix(3, 4) = LSMatrix(4, 3) = sumX2YZ;
21055 LSMatrix(3, 5) = LSMatrix(5, 3) = sumXY2Z;
21056 LSMatrix(3, 6) = LSMatrix(6, 3) = sumX2Y;
21057 LSMatrix(3, 7) = LSMatrix(7, 3) = sumXY2;
21058 LSMatrix(3, 8) = LSMatrix(8, 3) = sumXYZ;
21059 LSMatrix(3, 9) = LSMatrix(9, 3) = sumXY;
21060
21061 // fifth coulmn, fifth line
21062 LSMatrix(4, 5) = LSMatrix(5, 4) = sumXYZ2;
21063 LSMatrix(4, 6) = LSMatrix(6, 4) = sumX2Z;
21064 LSMatrix(4, 7) = LSMatrix(7, 4) = sumXYZ;
21065 LSMatrix(4, 8) = LSMatrix(8, 4) = sumXZ2;
21066 LSMatrix(4, 9) = LSMatrix(9, 4) = sumXZ;
21067
21068 // sixth column, sixth line
21069 LSMatrix(5, 6) = LSMatrix(6, 5) = sumXYZ;
21070 LSMatrix(5, 7) = LSMatrix(7, 5) = sumY2Z;
21071 LSMatrix(5, 8) = LSMatrix(8, 5) = sumYZ2;
21072 LSMatrix(5, 9) = LSMatrix(9, 5) = sumYZ;
21073
21074 // seventh column, seventh line
21075 LSMatrix(6, 7) = LSMatrix(7, 6) = sumXY;
21076 LSMatrix(6, 8) = LSMatrix(8, 6) = sumXZ;
21077 LSMatrix(6, 9) = LSMatrix(9, 6) = sumX;
21078
21079 // eigth column, eigth line
21080 LSMatrix(7, 8) = LSMatrix(8, 7) = sumYZ;
21081 LSMatrix(7, 9) = LSMatrix(9, 7) = sumY;
21082
21083 // nineth column, nineth line
21084 LSMatrix(8, 9) = LSMatrix(9, 8) = sumZ;
21085 }
21086
21087 // 2.3 scale solution since the condition number gets really bad for large discrepancies in cell
21088 // size
21089 const MFloat normalizationFactor = FPOW2(2 * a_level(cellId)) / grid().cellLengthAtLevel(0);
21090 for(MInt i = 0; i < 2 * nDim + pow(2, nDim - 1); i++) {
21091 for(MInt j = 0; j < 2 * nDim + pow(2, nDim - 1); j++) {
21092 LSMatrix(i, j) *= normalizationFactor;
21093 }
21094 }
21095
21096 // 2.4 determine the pseudoinverse using SVD
21097 maia::math::invert(LSMatrix, matInv, 2 * nDim + pow(2, nDim - 1), 2 * nDim + pow(2, nDim - 1));
21098
21099 const MInt matSize = 2 * nDim + pow(2, nDim - 1);
21100 std::vector<MFloat> matInvVector(matSize * matSize);
21101
21102 MInt k = 0;
21103 for(MInt i = 0; i < 2 * nDim + pow(2, nDim - 1); i++) {
21104 for(MInt j = 0; j < 2 * nDim + pow(2, nDim - 1); j++) {
21105 matInvVector[k] = matInv(i, j);
21106 k++;
21107 }
21108 }
21109
21110 const MInt interpIndex = m_cellInterpolationIds.size();
21111 // Store interpolation information for points in this cell
21112 m_cellInterpolationIndex[cellId] = interpIndex;
21113 m_cellInterpolationIds.push_back(nghbrList);
21114 m_cellInterpolationMatrix.push_back(matInvVector);
21115}
21116
21117
21120template <MInt nDim_, class SysEqn>
21121template <MInt a, MInt b>
21123 std::function<MFloat(MInt, MInt)> variables,
21124 MFloat* interpolatedVar) {
21125 ASSERT((b - a) > 0, "ERROR: Difference between b and a needs to be positive!");
21126 ASSERT(cellId >= 0, "ERROR: Invalid cellId!");
21127
21128 const MInt interpIndex = m_cellInterpolationIndex[cellId];
21129 if(interpIndex < 0) {
21130 mTerm(1, "Interpolation for cell not initialized");
21131 /* std::cerr << "Interpolation for cell " << cellId << " not initialized." << std::endl; */
21132 // interpolateVariables<a, b>(cellId, position, variables, interpolatedVar);
21133 /* return; */
21134 }
21135
21136 const MFloat originX = a_coordinate(cellId, 0);
21137 const MFloat originY = a_coordinate(cellId, 1);
21138 MFloat originZ = 0.0;
21139 IF_CONSTEXPR(nDim == 3) { originZ = a_coordinate(cellId, 2); }
21140
21141 const MFloat normalizationFactor = FPOW2(2 * a_level(cellId)) / grid().cellLengthAtLevel(0);
21142
21143 const MInt noNghbrs = m_cellInterpolationIds[interpIndex].size();
21144 const MInt* const nghbrList = &m_cellInterpolationIds[interpIndex][0];
21145
21146 const MInt matSize = 2 * nDim + pow(2, nDim - 1);
21147 MFloatTensor interpMatInv(&m_cellInterpolationMatrix[interpIndex][0], matSize, matSize);
21148
21152 MFloat rhs[10];
21153 MFloat coeff[10];
21154
21155 for(MInt k = a; k < b; k++) {
21156 MFloat sumVar = variables(cellId, k);
21157 MFloat sumVarX = 0;
21158 MFloat sumVarY = 0;
21159 MFloat sumVarZ = 0;
21160 MFloat sumVarXY = 0;
21161 MFloat sumVarXZ = 0;
21162 MFloat sumVarYZ = 0;
21163 MFloat sumVarX2 = 0;
21164 MFloat sumVarY2 = 0;
21165 MFloat sumVarZ2 = 0;
21166
21167 std::fill_n(&rhs[0], matSize, 0.0);
21168
21169 // 3.1 Calculate intermediate variables
21170 for(MInt nId = 1; nId < noNghbrs; nId++) {
21171 const MInt nghbrId = nghbrList[nId];
21172 const MFloat x = a_coordinate(nghbrId, 0) - originX;
21173 const MFloat y = a_coordinate(nghbrId, 1) - originY;
21174 const MFloat var = variables(nghbrId, k);
21175 MFloat z = 0.0;
21176 IF_CONSTEXPR(nDim == 3) { z = a_coordinate(nghbrId, 2) - originZ; }
21177
21178 const MFloat varX = var * x;
21179 const MFloat varY = var * y;
21180 const MFloat varZ = var * z;
21181
21182 sumVar += var;
21183 sumVarX += varX;
21184 sumVarY += varY;
21185 sumVarZ += varZ;
21186
21187 sumVarXY += varX * y;
21188 sumVarXZ += varX * z;
21189 sumVarYZ += varY * z;
21190
21191 sumVarX2 += varX * x;
21192 sumVarY2 += varY * y;
21193 sumVarZ2 += varZ * z;
21194 }
21195
21196 // 3.2 assign intermediate variables to rhs
21197 IF_CONSTEXPR(nDim == 2) {
21198 rhs[0] = sumVarX2;
21199 rhs[1] = sumVarY2;
21200 rhs[2] = sumVarXY;
21201 rhs[3] = sumVarX;
21202 rhs[4] = sumVarY;
21203 rhs[5] = sumVar;
21204 }
21205 else {
21206 rhs[0] = sumVarX2;
21207 rhs[1] = sumVarY2;
21208 rhs[2] = sumVarZ2;
21209
21210 rhs[3] = sumVarXY;
21211 rhs[4] = sumVarXZ;
21212 rhs[5] = sumVarYZ;
21213
21214 rhs[6] = sumVarX;
21215 rhs[7] = sumVarY;
21216 rhs[8] = sumVarZ;
21217 rhs[9] = sumVar;
21218 }
21219
21220 // 3.3 scale rhs
21221 for(MInt i = 0; i < matSize; i++) {
21222 rhs[i] *= normalizationFactor;
21223 }
21224
21225 std::fill_n(&coeff[0], matSize, 0.0);
21226
21227 // 3.4 determine coefficients of the aim function polynomial
21228 for(MInt i = 0; i < matSize; i++) {
21229 for(MInt j = 0; j < matSize; j++) {
21230 coeff[i] += interpMatInv(i, j) * rhs[j];
21231 }
21232 }
21233
21237 const MFloat positionX = position[0] - originX;
21238 const MFloat positionY = position[1] - originY;
21239 MFloat positionZ = 0.0;
21240 IF_CONSTEXPR(nDim == 3) { positionZ = position[2] - originZ; }
21241
21242 MFloat result = coeff[matSize - 1];
21243 IF_CONSTEXPR(nDim == 2) {
21244 result += coeff[0] * positionX * positionX;
21245 result += coeff[1] * positionY * positionY;
21246 result += coeff[2] * positionX * positionY;
21247 result += coeff[3] * positionX;
21248 result += coeff[4] * positionY;
21249 }
21250 else {
21251 result += coeff[0] * positionX * positionX;
21252 result += coeff[1] * positionY * positionY;
21253 result += coeff[2] * positionZ * positionZ;
21254 result += coeff[3] * positionX * positionY;
21255 result += coeff[4] * positionX * positionZ;
21256 result += coeff[5] * positionY * positionZ;
21257 result += coeff[6] * positionX;
21258 result += coeff[7] * positionY;
21259 result += coeff[8] * positionZ;
21260 }
21261
21262 interpolatedVar[k - a] = result;
21263 }
21264}
21265
21266
21268template <MInt nDim_, class SysEqn>
21270 const MInt sampleVarId, MFloat* state,
21271 const MBool interpolate) {
21272 // Note: interpolateVariablesInCell() requires variables for all cells
21273 switch(sampleVarId) {
21274 case FV_PV: {
21275 if(interpolate) {
21276 const MInt noSpecies = PV->m_noSpecies;
21277 constexpr MInt noVarsNoSpecies = (nDim == 2) ? 4 : 5;
21278 // Function pointer to a_pvariable
21279 std::function<MFloat(const MInt, const MInt)> varPtr = [&](const MInt cellId_, const MInt varId_) {
21280 return static_cast<MFloat>(a_pvariable(cellId_, varId_));
21281 };
21282 if(noSpecies == 0) {
21283 ASSERT(noVarsNoSpecies == PV->noVariables, "wrong number of variables");
21284 interpolateVariablesInCell<0, noVarsNoSpecies>(id, point, varPtr, state);
21285 } else if(noSpecies == 1) {
21286 interpolateVariablesInCell<0, noVarsNoSpecies + 1>(id, point, varPtr, state);
21287 } else {
21288 mTerm(1, "Fixme: noSpecies > 1");
21289 }
21290 } else {
21291 const MInt noVars = PV->noVariables;
21292 std::copy_n(&a_pvariable(id, 0), noVars, state);
21293 }
21294 break;
21295 }
21296 case FV_VORT: {
21297 const MInt noVort = (nDim == 2) ? 1 : 3;
21298 if(interpolate) {
21299 std::function<MFloat(const MInt, const MInt)> vortPointer = [&](const MInt cellId_, const MInt varId_) {
21300 return m_samplingVariables[sampleVarId][cellId_][varId_];
21301 };
21302 interpolateVariablesInCell<0, noVort>(id, point, vortPointer, state);
21303 } else {
21304 const MFloat** vortPointer = const_cast<const MFloat**>(m_samplingVariables[sampleVarId]);
21305 std::copy_n(vortPointer[id], noVort, state);
21306 }
21307 break;
21308 }
21309 case FV_HEAT_RELEASE: {
21310 if(interpolate) {
21311 mTerm(1, "Fixme: interpolation of heat release");
21312 }
21313 state[0] = m_heatRelease[id];
21314 break;
21315 }
21316 default: {
21317 mTerm(1, "Invalid variable id");
21318 break;
21319 }
21320 }
21321}
21322
21328template <MInt nDim_, class SysEqn>
21330 TRACE();
21331
21332 m_physicalTime += m_physicalTimeStep;
21333
21334 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
21335 for(MInt varId = 0; varId < CV->noVariables; varId++) {
21336 a_dt2Variable(cellId, varId) = a_dt1Variable(cellId, varId);
21337 a_dt1Variable(cellId, varId) = a_variable(cellId, varId);
21338 }
21339 }
21340}
21341
21347template <MInt nDim_, class SysEqn>
21349 TRACE();
21350
21351 MBool cellOk;
21352 MFloat dt;
21353 const MFloat F4B2 = 2.0;
21354
21355
21356 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
21357 // multilevel
21358 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
21359 if(!a_isBndryGhostCell(cellId)) {
21360 cellOk = true;
21361 if(a_bndryId(cellId) > -1) {
21362 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_linkedCellId != -1) {
21363 cellOk = false;
21364 }
21365 }
21366 if(cellOk) {
21367 dt = a_cellVolume(cellId) / m_physicalTimeStep;
21368
21369 for(MInt varId = 0; varId < CV->noVariables; varId++) {
21370 a_rightHandSide(cellId, varId) += (F3B2 * a_variable(cellId, varId) - F4B2 * a_dt1Variable(cellId, varId)
21371 + F1B2 * a_dt2Variable(cellId, varId))
21372 * dt;
21373 }
21374 }
21375 }
21376 }
21377 }
21378}
21379
21381template <MInt nDim_, class SysEqn>
21383 IF_CONSTEXPR(!hasE<SysEqn>)
21384 mTerm(1, AT_, "Not compatible with SysEqn without RHO_E!");
21385 MFloat momentumDensitySquare = F0;
21386 for(MInt d = 0; d < nDim; ++d) {
21387 momentumDensitySquare += POW2((a_variable(cellId, CV->RHO_VV[d])));
21388 }
21389 return sysEqn().pressure(a_variable(cellId, CV->RHO), momentumDensitySquare, a_variable(cellId, CV->RHO_E));
21390}
21391
21393template <MInt nDim_, class SysEqn>
21395 return sysEqn().temperature_ES(a_variable(cellId, CV->RHO), cv_p(cellId));
21396}
21397
21399template <MInt nDim_, class SysEqn>
21401 return sysEqn().speedOfSound(a_variable(cellId, CV->RHO), cv_p(cellId));
21402}
21403
21404
21405// debug
21410template <MInt nDim_, class SysEqn>
21412 MFloat a;
21413 IF_CONSTEXPR(!hasE<SysEqn>)
21414 mTerm(1, AT_, "Not compatible with SysEqn without RHO_E!");
21415
21416 IF_CONSTEXPR(isDetChem<SysEqn>) {
21417 MFloat gamma = a_avariable(cellId, AV->GAMMA);
21418 MFloat p = a_pvariable(cellId, PV->P);
21419 MFloat rho = a_pvariable(cellId, PV->RHO);
21420 a = sqrt(gamma * mMax(MFloatEps, p / mMax(MFloatEps, rho)));
21421 }
21422 else {
21423 a = cv_a(cellId);
21424 }
21425
21426 MFloat dt = std::numeric_limits<MFloat>::max();
21427 const MFloat Frho = 1. / a_variable(cellId, CV->RHO);
21428 const MFloat dx = c_cellLengthAtCell(cellId);
21429 for(MInt d = 0; d < nDim; ++d) {
21430 MFloat abs_u_d = fabs(a_variable(cellId, CV->RHO_VV[d]) * Frho);
21431 MFloat dt_dir = m_cfl * dx / (abs_u_d + a);
21432 dt = mMin(dt, dt_dir);
21433 }
21434
21435 return dt;
21436}
21440template <MInt nDim_, class SysEqn>
21442 ASSERT(((SolverType)string2enum(Context::getSolverProperty<MString>("solvertype", m_solverId, AT_))) == MAIA_FV_APE,
21443 "FV_APE solver not selected");
21444
21445 const MFloat dx = c_cellLengthAtCell(cellId);
21446
21447 MFloat lambdaMaxSum = (m_initialCondition == 1184) ? 0.0 : nDim; // 0 for LAE(IC1184), nDim for APE
21448 MFloat advectionVelocity[nDim];
21449 for(MInt d = 0; d < nDim; ++d) {
21450 advectionVelocity[d] =
21451 Context::getSolverProperty<MFloat>("advectionVelocity", m_solverId, AT_, &advectionVelocity[d], d);
21452 lambdaMaxSum += fabs(advectionVelocity[d]);
21453 }
21454 return m_cfl * dx / (lambdaMaxSum);
21455}
21456
21460template <MInt nDim_, class SysEqn>
21462 MFloat C, MFloat dx) const noexcept {
21463 return sysEqn().computeTimeStepDiffusion(SUTHERLANDLAW(temperature) / (density * Re), C, dx);
21464}
21465
21469// template <MInt nDim_, class SysEqn>
21470// MFloat FvCartesianSolverXD<nDim_, SysEqn>::computeTimeStepDiffusionNS(MFloat density, MFloat temperature, MFloat Re,
21471// MFloat C, MFloat dx) const noexcept {
21472// return computeTimeStepDiffusion(SUTHERLANDLAW(temperature) / (density * Re), C, dx);
21473// }
21474
21476template <MInt nDim_, class SysEqn>
21478 switch(m_timeStepMethod) {
21479 default: {
21480 if(m_timeStepFixedValue > 0.) {
21481 return m_timeStepFixedValue;
21482 }
21483 mTerm(1, AT_, "unknown time-step method: " + to_string(m_timeStepMethod));
21484 }
21485 case 17511: // this uses a different time-step during the simulation but writes
21486 // the one that was read from a restart file to the next file
21487 case 1: {
21488 return computeTimeStepEulerDirectional(cellId);
21489 }
21490 case 2: {
21491 return computeTimeStepApeDirectional(cellId);
21492 }
21493 case 6: {
21494 return m_cfl * c_cellLengthAtLevel(maxRefinementLevel());
21495 // prior version used m_maxGCellLevel from the levelSet-Solver!
21496 }
21497 // Infinity values:
21498 case 100: {
21499 const MFloat dx = c_cellLengthAtLevel(maxRefinementLevel());
21500 std::array<MFloat, nDim> u = {};
21501 u[0] = m_UInfinity;
21502 u[1] = m_VInfinity;
21503 IF_CONSTEXPR(nDim == 3) u[2] = m_WInfinity;
21504 const MFloat dt_inv = sysEqn().computeTimeStepEulerMagnitude(m_rhoInfinity, u, m_PInfinity, m_cfl, dx);
21505 const MFloat dt_visc = computeTimeStepDiffusionNS(m_rhoInfinity, m_TInfinity, sysEqn().m_Re0, m_cflViscous, dx);
21506 return mMin(dt_inv, dt_visc);
21507 }
21508 }
21509}
21510
21511template <MInt nDim_, class SysEqn>
21513 MFloat dtCell = computeTimeStepMethod(cellId);
21514
21515 // Applies volume weighting to boundary cells
21516 if(m_timeStepVolumeWeighted && a_bndryId(cellId) != -1) {
21517 dtCell *= a_cellVolume(cellId) / grid().cellVolumeAtLevel(a_level(cellId));
21518 }
21519 return dtCell;
21520}
21521
21523template <MInt nDim_, class SysEqn>
21525 // Skip cells in other MG levels:
21526 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
21527 return false;
21528 }
21529 // Skip ghost-cells? (TODO labels:FV,totest is this the proper check for that?)
21530 if(a_bndryId(cellId) < -1) {
21531 return false;
21532 }
21533 // TODO labels:FV,totest check how many testcases this breaks:
21534 // if (a_hasProperty(cellId, Cell:IsGhost)) { return false; }
21535
21536 // Skip small cells
21537 //
21538 // TODO labels:FV doesn't work with noMerging which has no master/slave cells, all
21539 // small cells have m_linkedCellId == -1, so right now they always participate
21540 // in the time-step computation. This will probably explode if one enables
21541 // volume weighting of boundary cells in combination with noMerging.
21542 if(a_bndryId(cellId) > -1 && m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_linkedCellId != -1) {
21543 return false;
21544 }
21545
21546 // Skip halo cells
21547 if(a_isHalo(cellId)) {
21548 return false;
21549 }
21550
21551 // skip cells which are inactive (negative ls-value)
21552 if(a_hasProperty(cellId, SolverCell::IsInactive)) {
21553 return false;
21554 }
21555
21556 // Skip cells which are stabilized by other means (smallCellCorrection, linking)
21557 if(a_hasProperty(cellId, SolverCell::IsTempLinked)) {
21558 return false;
21559 }
21560 if(a_hasProperty(cellId, SolverCell::IsSplitChild)) {
21561 return false;
21562 }
21563 if(!m_fvBndryCnd->m_cellMerging && a_isBndryCell(cellId)
21564 && a_cellVolume(cellId) / grid().cellVolumeAtLevel(maxLevel()) <= m_fvBndryCnd->m_volumeLimitWall) {
21565 // maxLevelChange use maxLevel() instead of maxRefinementLevel!
21566 return false;
21567 }
21568
21569
21570 return true;
21571}
21572
21577template <MInt nDim_, class SysEqn>
21579 TRACE();
21580
21581 const MFloat invalidTimeStep = std::numeric_limits<MFloat>::max();
21582 // Compute the global time step:
21583 MFloat newTimeStep = invalidTimeStep;
21584 const MInt noCells = a_noCells();
21585
21586 // Initialize dualTimeStepping:
21587 if(m_dualTimeStepping || m_localTS) {
21588 for(MInt cellId = 0; cellId < noCells; cellId++) {
21589 a_localTimeStep(cellId) = invalidTimeStep;
21590 }
21591 }
21592
21593 // Compute the time-step for every non-small-cell and non-ghost-cell
21594 MInt noCellsOnWhichTheTimeStepIsComputed = 0;
21595 for(MInt cellId = 0; cellId < noCells; ++cellId) {
21596 if(!cellParticipatesInTimeStep(cellId)) {
21597 if(m_dualTimeStepping) {
21598 a_localTimeStep(cellId) = F0;
21599 }
21600 continue;
21601 }
21602
21603 MFloat dtCell = computeTimeStep(cellId);
21604 newTimeStep = mMin(newTimeStep, dtCell);
21605 if(m_dualTimeStepping) {
21606 a_localTimeStep(cellId) = dtCell;
21607 }
21608
21609 ++noCellsOnWhichTheTimeStepIsComputed;
21610 }
21611
21612
21613 // some domains have only cells that do not participate in the time-step
21614 // computation
21615 if(noCellsOnWhichTheTimeStepIsComputed != 0 && approx(newTimeStep, invalidTimeStep, m_eps)) {
21616 mTerm(1, AT_, "failed to compute the time-step " + std::to_string(m_solverId));
21617 }
21618
21619 // Use a fixed user-provided time-step:
21620 if(m_timeStepFixedValue > 0.) {
21621 MPI_Allreduce(MPI_IN_PLACE, &newTimeStep, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "m_timeStep");
21622 if(m_timeStepFixedValue > newTimeStep && domainId() == 0) { // Still check the CFL condition
21623 std::cerr << endl
21624 << endl
21625 << "WARNING: timeStepFixedvalue = " << m_timeStepFixedValue
21626 << " > computedGlobalTimeStep = " << newTimeStep << endl
21627 << endl
21628 << endl;
21629 }
21630 const MString msg = "FV-Solver globalTimeStep " + std::to_string(globalTimeStep)
21631 + ", using fixed time step: " + std::to_string(m_timeStepFixedValue)
21632 + " (computeGlobalTimeStep = " + std::to_string(newTimeStep) + ")";
21633 m_log << msg << std::endl;
21634 if(domainId() == 0) {
21635 std::cerr << msg << std::endl;
21636 }
21637
21638 newTimeStep = m_timeStepFixedValue;
21639
21640 if(m_dualTimeStepping) { // also check the CFL condition for local time stepping
21641 for(MInt cellId = 0; cellId < noCells; ++cellId) {
21642 if(m_timeStepFixedValue < a_localTimeStep(cellId)) {
21643 m_log << "Warning: cell " << cellId << "timeStepFixedvalue = " << m_timeStepFixedValue
21644 << " < computedLocalTimeStep = " << a_localTimeStep(cellId) << endl;
21645 }
21646 a_localTimeStep(cellId) = m_timeStepFixedValue;
21647 }
21648 }
21649 forceTimeStep(newTimeStep);
21650 } else {
21651 // If the time-step is not fixed to a single constant value, exchange:
21652 RECORD_TIMER_START(m_tcomm);
21653 RECORD_TIMER_START(m_texchangeDt);
21654
21655 forceTimeStep(newTimeStep);
21656 ASSERT(m_timeStepAvailable, "overlapping time-step computations?!");
21657#ifndef MAIA_MS_COMPILER
21658 MPI_Iallreduce(MPI_IN_PLACE, &m_timeStep, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), &m_timeStepReq, AT_, "MPI_IN_PLACE",
21659 "m_timeStep");
21660#else
21661 MPI_Allreduce(MPI_IN_PLACE, &m_timeStep, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "m_timeStep");
21662#endif
21663
21664 m_timeStepAvailable = false;
21665 if(!m_timeStepNonBlocking) {
21666 timeStep(true);
21667 }
21668 RECORD_TIMER_STOP(m_texchangeDt);
21669 RECORD_TIMER_STOP(m_tcomm);
21670
21671 }
21672}
21673
21674// This is the interface to the methods class
21675// author: Daniel Hartmann, July 2007
21676template <MInt nDim_, class SysEqn>
21678 TRACE();
21679
21680 if(!useTimeStepFromRestartFile()) {
21681 computeAndSetTimeStep();
21682 }
21683
21684 m_timeStepUpdated = true;
21685
21686
21687 IF_CONSTEXPR(nDim == 2) {
21688 // TODOs labels:FV
21689 // - since computeSamplingTimeStep overwrites m_timeStep it belongs to timeStepMethods
21690 // - however it expects the previous time-step (before the one being modified)
21691 // to be written to a file. For this reason:
21692 // - m_restartFileOutputTimeStep exists which writes out a different dt than the one used
21693 // - some level set test cases have a timeStep of -1 in their restart files...
21694 // - this seems to be only somehow relevant for 2D level set which means
21695 // 3D flames are using a completely different time-step
21696 m_restartFileOutputTimeStep =
21697 (m_timeStepMethod == 17511 || m_timeStepMethod == 6) ? timeStep(true) : m_restartFileOutputTimeStep;
21698 if(m_timeStepMethod == 17511) {
21699 computeSamplingTimeStep(); // TODO labels:FV 2d_forced_flame_serial cruft
21700 }
21701 }
21702}
21703
21704
21705//---------------------------------------------------------------------------
21706
21707
21718template <MInt nDim_, class SysEqn>
21720 TRACE();
21721
21722 if(globalTimeStep % m_residualInterval != 0) {
21723 return true;
21724 }
21725
21726 // Return if this is not the primary solver in a multilevel computation
21727 if(isMultilevel() && !isMultilevelPrimary()) {
21728 return true;
21729 }
21730
21731 RECORD_TIMER_START(m_timers[Timers::TimeInt]);
21732 RECORD_TIMER_START(m_timers[Timers::Residual]);
21733
21734 const MInt noCells = a_noCells();
21735 const MInt noCVars = CV->noVariables;
21736 MFloatScratchSpace rmsResidual(noCVars + 1, AT_, "rmsResidual");
21737 MFloatScratchSpace maxResidual(noCVars, AT_, "maxResidual");
21738 MFloatScratchSpace avgResidual(noCVars + 1, AT_, "rmsResidual");
21739 rmsResidual.fill(F0);
21740
21741 //---end of initialization
21742
21743 // Compute residual
21744 // ----------------
21745 for(MInt cellId = 0; cellId < noCells; cellId++) {
21746 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
21747 if(a_isHalo(cellId)) continue;
21748 if(a_isBndryGhostCell(cellId)) continue;
21749 if(a_isPeriodic(cellId)) continue;
21750 if(a_hasProperty(cellId, SolverCell::IsPeriodicWithRot)) continue;
21751 if(a_hasProperty(cellId, SolverCell::IsCutOff)) continue;
21752 if(a_hasProperty(cellId, SolverCell::IsInvalid)) continue;
21753 MInt gridcellId = cellId;
21754 if(a_hasProperty(cellId, SolverCell::IsSplitClone) || a_hasProperty(cellId, SolverCell::IsSplitChild)) {
21755 gridcellId = m_splitChildToSplitCell.find(cellId)->second;
21756 }
21757 if(c_noChildren(gridcellId) > 0) continue;
21758 if(a_bndryId(cellId) > -1 && m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_linkedCellId > -1) continue;
21759 if(a_isInactive(cellId)) continue;
21760
21761 rmsResidual(0) += a_cellVolume(cellId);
21762 avgResidual(0)++;
21763 for(MInt var = 0; var < noCVars; var++) {
21764 if(!m_localTS) {
21765 MBool useOldResidual = true;
21766 if(useOldResidual) {
21767 rmsResidual(1 + var) += a_cellVolume(cellId) * POW2(a_FcellVolume(cellId) * a_rightHandSide(cellId, var));
21768 } else {
21769 rmsResidual(1 + var) += a_cellVolume(cellId) * POW2(a_variable(cellId, var) - a_oldVariable(cellId, var));
21770 }
21771 avgResidual(1 + var) += POW2(a_variable(cellId, var) - a_oldVariable(cellId, var));
21772 maxResidual(var) = mMax(maxResidual(var), POW2(a_variable(cellId, var) - a_oldVariable(cellId, var)));
21773 } else {
21774 rmsResidual(1 + var) +=
21775 a_cellVolume(cellId) * POW2(a_variable(cellId, var) - a_oldVariable(cellId, var)) / a_localTimeStep(cellId);
21776 avgResidual(1 + var) += POW2(a_variable(cellId, var) - a_oldVariable(cellId, var)) / a_localTimeStep(cellId);
21777 maxResidual(var) = mMax(maxResidual(var),
21778 POW2(a_variable(cellId, var) - a_oldVariable(cellId, var)) / a_localTimeStep(cellId));
21779 }
21780 }
21781 }
21782
21783 RECORD_TIMER_START(m_timers[Timers::ResidualMpi]);
21784 MPI_Allreduce(MPI_IN_PLACE, &rmsResidual(0), rmsResidual.size(), MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
21785 "rmsResidual(0)");
21786 MPI_Allreduce(MPI_IN_PLACE, &maxResidual(0), maxResidual.size(), MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
21787 "maxResidual(0)");
21788 MPI_Allreduce(MPI_IN_PLACE, &avgResidual(0), avgResidual.size(), MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
21789 "avgResidual(0)");
21790 RECORD_TIMER_STOP(m_timers[Timers::ResidualMpi]);
21791
21792 // compute RMS error (volume integral)
21793 for(MInt var = 0; var < noCVars; var++) {
21794 if(!m_localTS) {
21795 rmsResidual(1 + var) = sqrt(rmsResidual(1 + var) / rmsResidual(0));
21796 avgResidual(1 + var) = sqrt(avgResidual(1 + var) / avgResidual(0));
21797 maxResidual(var) = sqrt(maxResidual(var));
21798 } else {
21799 rmsResidual(1 + var) = sqrt(rmsResidual(1 + var) / rmsResidual(0)) / timeStep();
21800 avgResidual(1 + var) = sqrt(avgResidual(1 + var) / avgResidual(0)) / timeStep();
21801 maxResidual(var) = sqrt(maxResidual(var)) / timeStep();
21802 }
21803 }
21804
21805 if(mode == 0 && this->m_adaptation && this->m_resTriggeredAdapt && maxResidual(1 + PV->RHO) < 0.00001) {
21806 MInt limit = m_localTS ? 10 : 350;
21807 if(globalTimeStep - m_lastAdapTS < limit) {
21808 if(domainId() == 0) {
21809 cerr << "Residual threshold reached within 100 TS after last adaptation at " << globalTimeStep << endl;
21810 cerr << " -> Deactivating residual triggered Adaptation" << endl;
21811 }
21812 this->m_resTriggeredAdapt = false;
21813 } else {
21814 if(domainId() == 0) {
21815 cerr << "Forcing residual-based adaptation at time-step " << globalTimeStep << " with rms-density Residual of "
21816 << rmsResidual(1 + PV->RHO) << endl;
21817 }
21818 m_forceAdaptation = true;
21819 }
21820 }
21821
21822 MBool abort = false;
21823 MFloat maxRes = F0;
21824 for(MInt var = 0; var < noCVars; var++) {
21825 // Exit on NaN of average residual
21826 if(!(rmsResidual(1 + var) >= F0 || rmsResidual(1 + var) < F0)) {
21827 if(domainId() == 0) {
21828 cerr << "Solution diverged, average residual is nan " << endl;
21829 }
21830 m_log << "Solution diverged, average residual is nan " << endl;
21831 abort = true;
21832 }
21833 maxRes = mMax(maxRes, rmsResidual(1 + var));
21834 }
21835
21836 if(abort) {
21837 // Save output and exit
21838 disableDlbTimers();
21839 m_vtuWritePointData = false;
21840 m_vtuLevelThreshold = maxRefinementLevel();
21841 saveSolverSolution(1);
21842 if(!m_levelSetMb) {
21843 mTerm(1, AT_, "Solution diverged, average residual is NaN!");
21844 }
21845 }
21846
21847 if(mode == 1) return false;
21848
21849 if(domainId() == 0) {
21850 MString surname;
21851 if(!m_multipleFvSolver || (isMultilevel() && isMultilevelPrimary())) {
21852 surname = "Residual";
21853 } else {
21854 surname = "Residual_s" + to_string(solverId());
21855 }
21856 MString surnameBAK = surname + "_BAK";
21857
21858 // Output, residual
21859 // -----------------------
21860 FILE* datei;
21861 if(globalTimeStep == m_residualInterval) {
21862 struct stat buffer;
21863 if(stat(surname.c_str(), &buffer) == 0) {
21864 rename(surname.c_str(), "Residual_BAK");
21865 }
21866 datei = fopen(surname.c_str(), "w");
21867 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
21868 IF_CONSTEXPR(nDim == 3) {
21869 fprintf(datei, "%s",
21870 "# 1:time_step 2:hydrodynamic_time 3:acoustic_time 4:res_rhoU 5:res_rhoV 6:res_rhoW 7:res_rhoE "
21871 " 8:res_rho "
21872 "9:res_rhon 10:maxRes_rhoU 11:maxRes_rhoV 12:maxRes_rhoW 13:maxRes_rhoE 14:maxRes_rho "
21873 "15:avgRes_rhoU 16:avgRes_rhoV 17:avgRes_rhoW 18:avgRes_rhoE 19:avgRes_rho\n");
21874 }
21875 else {
21876 fprintf(datei, "%s",
21877 "# 1:time_step 2:hydrodynamic_time 3:acoustic_time 4:res_rhoU 5:res_rhoV 6:res_rhoE 7:res_rho "
21878 "8:res_rhon 9:maxRes_rhoU 10:maxRes_rhoV 11:maxRes_rhoE 12:maxRes_rho "
21879 "13:avgRes_rhoU 14:avgRes_rhoV 15:avgRes_rhoE 16:avgRes_rho\n");
21880 }
21881 }
21882 else {
21883 IF_CONSTEXPR(nDim == 3) {
21884 fprintf(datei, "%s",
21885 "# 1:time_step 2:hydrodynamic_time 3:acoustic_time 4:res_rhoU 5:res_rhoV 6:res_rhoW 7:res_rhoE "
21886 " 8:res_rho "
21887 "9:maxRes_rhoU 10:maxRes_rhoV 11:maxRes_rhoW 12:maxRes_rhoE 13:maxRes_rho "
21888 "14:avgRes_rhoU 15:avgRes_rhoV 16:avgRes_rhoW 17:avgRes_rhoE 18:avgRes_rho\n");
21889 }
21890 else {
21891 fprintf(datei, "%s",
21892 "# 1:time_step 2:hydrodynamic_time 3:acoustic_time 4:res_rhoU 5:res_rhoV 6:res_rhoE 7:res_rho "
21893 "8:maxRes_rhoU 9:maxRes_rhoV 10:maxRes_rhoE 11:maxRes_rho "
21894 "12:avgRes_rhoU 13:avgRes_rhoV 14:avgRes_rhoE 15:avgRes_rho\n");
21895 }
21896 }
21897 } else {
21898 datei = fopen(surname.c_str(), "a");
21899 }
21900 fprintf(datei, "%d", globalTimeStep);
21901 fprintf(datei, " %f", m_physicalTime);
21902 fprintf(datei, " %f", m_time);
21903 for(MInt var = 0; var < noCVars; var++) {
21904 fprintf(datei, " %.8g", rmsResidual(1 + var));
21905 }
21906 for(MInt var = 0; var < noCVars; var++) {
21907 fprintf(datei, " %.8g", maxResidual(var));
21908 }
21909 for(MInt var = 0; var < noCVars; var++) {
21910 fprintf(datei, " %.8g", avgResidual(1 + var));
21911 }
21912 fprintf(datei, "\n");
21913 fclose(datei);
21914 }
21915
21916 RECORD_TIMER_STOP(m_timers[Timers::Residual]);
21917 RECORD_TIMER_STOP(m_timers[Timers::TimeInt]);
21918
21919 if(maxRefinementLevel() == maxLevel() && maxRes < m_timeStepConvergenceCriterion) {
21920 return true;
21921 }
21922
21923 return false;
21924}
21925
21926
21939template <MInt nDim_, class SysEqn>
21941 TRACE();
21942
21943 if(!calcSlopesAfterStep()) {
21944 RECORD_TIMER_START(m_timers[Timers::MusclReconst]);
21945 LSReconstructCellCenter();
21946 RECORD_TIMER_STOP(m_timers[Timers::MusclReconst]);
21947
21948 // copy the slopes from the master to the slave cells
21949 RECORD_TIMER_START(m_timers[Timers::MusclCopy]);
21950 m_fvBndryCnd->copySlopesToSmallCells();
21951 RECORD_TIMER_STOP(m_timers[Timers::MusclCopy]);
21952
21953 // update the ghost cell slopes for reconstruction of the primitive variables
21954 // on the surfaces for the AUSM scheme
21955 RECORD_TIMER_START(m_timers[Timers::MusclGhostSlopes]);
21956 m_fvBndryCnd->updateGhostCellSlopesInviscid();
21957 RECORD_TIMER_STOP(m_timers[Timers::MusclGhostSlopes]);
21958
21959 RECORD_TIMER_START(m_timers[Timers::MusclCutSlopes]);
21960 m_fvBndryCnd->updateCutOffSlopesInviscid();
21961 RECORD_TIMER_STOP(m_timers[Timers::MusclCutSlopes]);
21962 // m_fvBndryCnd->updateGhostCellSlopesViscous();
21963 }
21964
21965 // reconstruction of the slopes and variables at the center of the surfaces
21966 RECORD_TIMER_START(m_timers[Timers::MusclReconstSrfc]);
21967 (this->*m_reconstructSurfaceData)(-1);
21968 RECORD_TIMER_STOP(m_timers[Timers::MusclReconstSrfc]);
21969
21970 if(m_useSandpaperTrip) {
21971 RECORD_TIMER_START(m_timers[Timers::SandpaperTrip]);
21972 applySandpaperTrip();
21973 RECORD_TIMER_STOP(m_timers[Timers::SandpaperTrip]);
21974 }
21975
21976 if(m_useChannelForce) {
21977 applyChannelForce();
21978 }
21979}
21980
21981
21988template <MInt nDim_, class SysEqn>
21990 TRACE();
21991
21992 MInt noCVars = CV->noVariables;
21993 MFloat delta;
21994 MFloat childDistance, cellDistance, nghbrDistance;
21995 MFloat factor, cellFactor, nghbrFactor;
21996
21997 // compute distances
21998
21999 // compute the distance of the child cell normal to the boundary
22000 childDistance = 0;
22001 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
22002 childDistance += (a_coordinate(child, spaceId)
22003 - m_fvBndryCnd->m_bndryCells->a[a_bndryId(child)].m_srfcs[0]->m_coordinates[spaceId])
22004 * m_fvBndryCnd->m_bndryCells->a[a_bndryId(child)].m_srfcs[0]->m_normalVector[spaceId];
22005 }
22006 childDistance = fabs(childDistance);
22007 // compute the distance of cellId normal to the boundary
22008 cellDistance = 0;
22009 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
22010 cellDistance += (a_coordinate(cellId, spaceId)
22011 - m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_coordinates[spaceId])
22012 * m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcs[0]->m_normalVector[spaceId];
22013 }
22014 cellDistance = fabs(cellDistance);
22015 // compute the distance of stencilCellIds[ 1 ] normal to the boundary
22016 nghbrDistance = 0;
22017 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
22018 nghbrDistance += (a_coordinate(stencilCellIds[1], spaceId)
22019 - m_fvBndryCnd->m_bndryCells->a[a_bndryId(stencilCellIds[1])].m_srfcs[0]->m_coordinates[spaceId])
22020 * m_fvBndryCnd->m_bndryCells->a[a_bndryId(stencilCellIds[1])].m_srfcs[0]->m_normalVector[spaceId];
22021 }
22022 nghbrDistance = fabs(nghbrDistance);
22023
22024 // compute interpolation factors...
22025 // ...for cellId
22026 cellFactor = (cellDistance - childDistance) / (2.0 * cellDistance);
22027 // ...for nghbr
22028 nghbrFactor = (nghbrDistance - childDistance) / (2.0 * nghbrDistance);
22029
22030 // compute the distance between child and ...
22031 // ...cellId
22032 cellDistance = 0;
22033 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
22034 delta = a_coordinate(cellId, spaceId) - a_coordinate(child, spaceId);
22035 cellDistance += delta * delta;
22036 }
22037 // ...nghbrId
22038 nghbrDistance = 0;
22039 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
22040 delta = a_coordinate(stencilCellIds[1], spaceId) - a_coordinate(child, spaceId);
22041 nghbrDistance += delta * delta;
22042 }
22043
22044 // another interpolation factor
22045 factor = nghbrDistance / (nghbrDistance + cellDistance);
22046
22047 // interpolation of the variables:
22048 // factor * interpolated cell value + ( 1 - factor ) * interpolated neighbor value
22049 for(MInt varId = 0; varId < noCVars; varId++) {
22050 a_variable(child, varId) =
22051 factor * (cellFactor * a_variable(stencilCellIds[0], varId) + (1.0 - cellFactor) * a_variable(cellId, varId))
22052 + (1.0 - factor)
22053 * (nghbrFactor * a_variable(stencilCellIds[2], varId)
22054 + (1.0 - cellFactor) * a_variable(stencilCellIds[1], varId));
22055 }
22056}
22057
22058template <MInt nDim_, class SysEqn>
22060 const MFloat* point) {
22061 TRACE();
22062
22063 MInt count = 0;
22064 const MInt stencilSize = IPOW2(nDim);
22065 if(!a_hasProperty(cellId, SolverCell::IsSplitCell)) {
22066 // add cellId itself and possible bndry-ghost cell
22067 interpolationCells[count++] = cellId;
22068 if(a_isBndryCell(cellId)) {
22069 interpolationCells[count++] = a_bndryGhostCellId(a_bndryId(cellId), 0);
22070 }
22071 } else {
22072 // for split cell: add closest split-child and its bndry-ghost-cell
22073 MInt scId = -1;
22074 for(MInt sc = 0; sc < a_noSplitCells(); sc++) {
22075 const MInt splitCell = m_splitCells[sc];
22076 if(splitCell == cellId) {
22077 scId = sc;
22078 break;
22079 }
22080 }
22081 // fill distance array
22082 MFloatScratchSpace dist(a_noSplitChilds(scId), AT_, "neighborDistance");
22083 for(MInt ssc = 0; ssc < a_noSplitChilds(scId); ssc++) {
22084 const MInt splitChild = a_splitChildId(scId, ssc);
22085 IF_CONSTEXPR(nDim == 2) {
22086 dist(ssc) = sqrt(POW2(point[0] - a_coordinate(splitChild, 0)) + POW2(point[1] - a_coordinate(splitChild, 1)));
22087 }
22088 else {
22089 dist(ssc) = sqrt(POW2(point[0] - a_coordinate(splitChild, 0)) + POW2(point[1] - a_coordinate(splitChild, 1))
22090 + POW2(point[2] - a_coordinate(splitChild, 2)));
22091 }
22092 }
22093 // find child with lowest distance
22094 MInt sscId = -1;
22095 MInt minDist = 99;
22096 for(MInt ssc = 0; ssc < a_noSplitChilds(scId); ssc++) {
22097 if(dist(ssc) < minDist) {
22098 minDist = dist(ssc);
22099 sscId = ssc;
22100 }
22101 }
22102 const MInt splitChildId = a_splitChildId(scId, sscId);
22103 interpolationCells[count++] = splitChildId;
22104 interpolationCells[count++] = a_bndryGhostCellId(a_bndryId(splitChildId), 0);
22105 }
22106
22107#ifndef NDEBUG
22108 MInt debugId = -1;
22109 MInt debugDomainId = -1;
22110
22111 if(cellId == debugId && domainId() == debugDomainId) {
22112 if(count == 1) {
22113 cerr << "Cell has only " << interpolationCells[0] << " s" << count << endl;
22114 } else {
22115 cerr << "Cell has " << interpolationCells[0] << " and bndry-ghost-cell " << interpolationCells[1] << " s" << count
22116 << endl;
22117 }
22118 cerr << "Cell is " << cellId << " " << c_noCells() << a_hasProperty(cellId, SolverCell::IsSplitCell) << endl;
22119 }
22120#endif
22121
22122 // compute distance to all neighbor cells
22123 MFloatScratchSpace neighborDistance(m_noDirs, AT_, "neighborDistance");
22124 for(MInt dir = 0; dir < m_noDirs; dir++) {
22125 if(!checkNeighborActive(cellId, dir) || !a_hasNeighbor(cellId, dir)) {
22126 neighborDistance[dir] = 99.9;
22127 } else {
22128 IF_CONSTEXPR(nDim == 2) {
22129 neighborDistance[dir] = sqrt(POW2(point[0] - a_coordinate(c_neighborId(cellId, dir), 0))
22130 + POW2(point[1] - a_coordinate(c_neighborId(cellId, dir), 1)));
22131 }
22132 else {
22133 neighborDistance[dir] = sqrt(POW2(point[0] - a_coordinate(c_neighborId(cellId, dir), 0))
22134 + POW2(point[1] - a_coordinate(c_neighborId(cellId, dir), 1))
22135 + POW2(point[2] - a_coordinate(c_neighborId(cellId, dir), 2)));
22136 }
22137 }
22138 }
22139
22140#ifndef NDEBUG
22141 if(cellId == debugId && domainId() == debugDomainId) {
22142 for(MInt i = 0; i < m_noDirs; i++) {
22143 const MInt nghbrId = c_neighborId(cellId, i);
22144 MInt ghostCell = -1;
22145 if(nghbrId > -1 && a_isBndryCell(nghbrId)) {
22146 ghostCell = a_bndryGhostCellId(a_bndryId(nghbrId), 0);
22147 }
22148 cerr << "distance " << i << " " << neighborDistance[i] << " neighbor " << nghbrId << " neighbor-ghost "
22149 << ghostCell << " " << a_hasProperty(nghbrId, SolverCell::IsSplitCell) << endl;
22150 }
22151 }
22152#endif
22153
22154 // use first matching neighbors with lowest distance
22155 for(MInt i = 0; i < m_noDirs; i++) {
22156 MInt minId = -1;
22157 MFloat minDistance = 99;
22158 for(MInt dir = 0; dir < m_noDirs; dir++) {
22159 if(neighborDistance[dir] < minDistance) {
22160 minDistance = neighborDistance[dir];
22161 minId = dir;
22162 }
22163 }
22164 if(minId > -1) {
22165 const MInt nghbrId = c_neighborId(cellId, minId);
22166 interpolationCells[count++] = nghbrId;
22167
22168#ifndef NDEBUG
22169 if(cellId == debugId && domainId() == debugDomainId) {
22170 cerr << "Adding " << interpolationCells[count - 1] << " in dir " << minId << " s" << count << endl;
22171 }
22172#endif
22173
22174 if(count < stencilSize && a_isBndryCell(nghbrId) && a_bndryGhostCellId(a_bndryId(nghbrId), 0) > -1) {
22175 // NOTE: bndry-ghost cell can be -1 for a bndry split-cell!
22176 interpolationCells[count++] = a_bndryGhostCellId(a_bndryId(nghbrId), 0);
22177
22178#ifndef NDEBUG
22179 if(cellId == debugId && domainId() == debugDomainId) {
22180 cerr << "Adding ghost-cell" << interpolationCells[count - 1] << " from dir " << minId << " s" << count
22181 << endl;
22182 }
22183#endif
22184 }
22185 neighborDistance[minId] = 99;
22186 }
22187 if(count == stencilSize) {
22188 break;
22189 }
22190 }
22191
22192 return count;
22193}
22194
22201template <MInt nDim_, class SysEqn>
22203 TRACE();
22204
22205 MBool a0Computed, a1Computed;
22206 MInt noCVars = CV->noVariables;
22207 MFloat rightHandSide1, rightHandSide2;
22208 MFloat xy, xy0, xy1, xy2, y2y1, xy1xy0, xy2xy0;
22209 MFloat r0, r1, r2;
22210 MFloat rhs1, rhs2, lhs2;
22211 MFloat x1term, x2term, y1term, y2term;
22212 MFloat ratio;
22213 MFloat coordinates[4 * nDim];
22214 MFloat epsilon = c_cellLengthAtLevel(maxRefinementLevel()) / 100.0;
22215 MFloat parameter[4] = {0, 0, 0, 0};
22216 //---
22217
22218
22219 // solve: phi(x,y) = a0*x + a1*y + a2*xy + a3
22220 a0Computed = false;
22221 a1Computed = false;
22222
22223 // shift coordinates such that the coordinates of cellId are (0,0)
22224 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
22225 coordinates[spaceId] = a_coordinate(child, spaceId) - a_coordinate(cellId, spaceId);
22226 coordinates[nDim + spaceId] = a_coordinate(stencilCellIds[0], spaceId) - a_coordinate(cellId, spaceId);
22227 coordinates[2 * nDim + spaceId] = a_coordinate(stencilCellIds[1], spaceId) - a_coordinate(cellId, spaceId);
22228 coordinates[3 * nDim + spaceId] = a_coordinate(stencilCellIds[2], spaceId) - a_coordinate(cellId, spaceId);
22229 }
22230
22231 // compute constants
22232 xy = coordinates[0] * coordinates[1];
22233 xy0 = coordinates[nDim] * coordinates[nDim + 1];
22234 xy1 = coordinates[2 * nDim] * coordinates[2 * nDim + 1];
22235 xy2 = coordinates[3 * nDim] * coordinates[3 * nDim + 1];
22236
22237 for(MInt varId = 0; varId < noCVars; varId++) {
22238 // 1.: check if a0 can be easily computed (check 1-coordinate)
22239 if(fabs(coordinates[nDim + 1]) < epsilon) {
22240 parameter[0] = (a_variable(stencilCellIds[0], varId) - a_variable(cellId, varId)) / coordinates[nDim];
22241 a0Computed = true;
22242 } else {
22243 if(fabs(coordinates[2 * nDim + 1] - coordinates[3 * nDim + 1]) < epsilon) {
22244 parameter[0] = (a_variable(stencilCellIds[2], varId) - a_variable(stencilCellIds[1], varId))
22245 / (coordinates[3 * nDim] - coordinates[2 * nDim]);
22246 a0Computed = true;
22247 }
22248 }
22249
22250 // 2.: check if a1 can be easily computed (check 0-coordinate)
22251 if(fabs(coordinates[2 * nDim]) < epsilon) {
22252 parameter[1] = (a_variable(stencilCellIds[1], varId) - a_variable(cellId, varId)) / coordinates[2 * nDim + 1];
22253 a1Computed = true;
22254 } else {
22255 if(fabs(coordinates[nDim] - coordinates[3 * nDim]) < epsilon) {
22256 parameter[1] = (a_variable(stencilCellIds[2], varId) - a_variable(stencilCellIds[0], varId))
22257 / (coordinates[3 * nDim + 1] - coordinates[nDim + 1]);
22258 a1Computed = true;
22259 }
22260 }
22261
22262 // 3. compute a3
22263 parameter[3] = a_variable(cellId, varId);
22264
22265 // 4. compute remaining parameters
22266 if(a0Computed && a1Computed) {
22267 parameter[2] = (a_variable(stencilCellIds[2], varId) - parameter[3] - parameter[0] * coordinates[3 * nDim]
22268 - parameter[1] * coordinates[3 * nDim + 1])
22269 / xy2;
22270
22271 } else {
22272 if(a0Computed) {
22273 rightHandSide1 = a_variable(stencilCellIds[1], varId) - parameter[3] - parameter[0] * coordinates[2 * nDim];
22274 rightHandSide2 = a_variable(stencilCellIds[2], varId) - parameter[3] - parameter[0] * coordinates[3 * nDim];
22275 ratio = coordinates[3 * nDim + 1] / coordinates[2 * nDim + 1];
22276
22277 parameter[2] = (rightHandSide2 - ratio * rightHandSide1) / (xy2 - ratio * xy1);
22278 parameter[1] = (rightHandSide1 - xy1 * parameter[2]) / coordinates[2 * nDim + 1];
22279
22280 } else {
22281 if(a1Computed) {
22282 rightHandSide1 = a_variable(stencilCellIds[0], varId) - parameter[3] - parameter[1] * coordinates[nDim + 1];
22283 rightHandSide2 =
22284 a_variable(stencilCellIds[2], varId) - parameter[3] - parameter[1] * coordinates[3 * nDim + 1];
22285 ratio = coordinates[3 * nDim] / coordinates[nDim];
22286
22287 parameter[2] = (rightHandSide2 - ratio * rightHandSide1) / (xy2 - ratio * xy0);
22288 parameter[0] = (rightHandSide1 - xy0 * parameter[2]) / coordinates[nDim];
22289
22290 } else {
22291 // Interpolation with skewed stencil
22292 // The system of equations is solved with parameters in reversed order!!!
22293
22294 // compute constants
22295 xy1xy0 = xy1 / xy0;
22296 xy2xy0 = xy2 / xy0;
22297 x1term = coordinates[2 * nDim] - xy1xy0 * coordinates[nDim];
22298 x2term = coordinates[3 * nDim] - xy2xy0 * coordinates[nDim];
22299 y1term = coordinates[2 * nDim + 1] - xy1xy0 * coordinates[nDim + 1];
22300 y2term = coordinates[3 * nDim + 1] - xy2xy0 * coordinates[nDim + 1];
22301 y2y1 = y2term / y1term;
22302
22303 parameter[3] = a_variable(cellId, varId);
22304 r0 = a_variable(stencilCellIds[0], varId) - parameter[3];
22305 r1 = a_variable(stencilCellIds[1], varId) - parameter[3];
22306 r2 = a_variable(stencilCellIds[2], varId) - parameter[3];
22307
22308 // compute right and left hand sides
22309 rhs2 = r2 - xy2xy0 * r0 - y2y1 * (r1 - xy1xy0 * r0);
22310 rhs1 = r1 - xy1xy0 * r0;
22311 lhs2 = x2term - y2y1 * (x1term);
22312
22313 // compute parameters
22314 parameter[0] = rhs2 / lhs2;
22315 parameter[1] = (rhs1 - x1term * parameter[0]) / y1term;
22316 parameter[2] = (r0 - coordinates[nDim] * parameter[0] - coordinates[nDim + 1] * parameter[1]) / xy0;
22317 }
22318 }
22319 }
22320
22321
22322 // 5. Interpolate
22323 a_variable(child, varId) =
22324 parameter[0] * coordinates[0] + parameter[1] * coordinates[1] + parameter[2] * xy + parameter[3];
22325 }
22326}
22327
22328
22335template <MInt nDim_, class SysEqn>
22337 TRACE();
22338
22339 MInt noCVars = CV->noVariables;
22340 MFloat coordinates[3 * nDim];
22341 MFloat parameter[3];
22342 MFloat ratio;
22343
22344 // shift coordinates such that the coordinates of cellId are (0,0)
22345 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
22346 coordinates[spaceId] = a_coordinate(child, spaceId) - a_coordinate(cellId, spaceId);
22347 coordinates[nDim + spaceId] = a_coordinate(stencilCellIds[0], spaceId) - a_coordinate(cellId, spaceId);
22348 coordinates[2 * nDim + spaceId] = a_coordinate(stencilCellIds[1], spaceId) - a_coordinate(cellId, spaceId);
22349 }
22350
22351 // interpolate
22352 for(MInt varId = 0; varId < noCVars; varId++) {
22353 parameter[2] = a_variable(cellId, varId);
22354
22355 if(approx(coordinates[2 * nDim], 0.0, MFloatEps)) {
22356 parameter[1] = (a_variable(stencilCellIds[1], varId) - a_variable(cellId, varId)) / coordinates[2 * nDim + 1];
22357 } else {
22358 ratio = coordinates[2 * nDim] / coordinates[nDim];
22359 parameter[1] = (parameter[2] * (ratio - 1.) + a_variable(stencilCellIds[1], varId)
22360 - a_variable(stencilCellIds[0], varId) * ratio)
22361 / (coordinates[2 * nDim + 1] - coordinates[nDim + 1] * ratio);
22362 }
22363
22364 if(approx(coordinates[nDim + 1], 0.0, MFloatEps)) {
22365 parameter[0] = (a_variable(stencilCellIds[0], varId) - a_variable(cellId, varId)) / coordinates[nDim];
22366 } else {
22367 parameter[0] = (a_variable(stencilCellIds[0], varId) - parameter[2] - parameter[1] * coordinates[nDim + 1])
22368 / coordinates[nDim];
22369 }
22370
22371 a_variable(child, varId) = parameter[0] * coordinates[0] + parameter[1] * coordinates[1] + parameter[2];
22372 }
22373}
22374
22375
22386template <MInt nDim_, class SysEqn>
22388 TRACE();
22389
22390 const MInt noCellIds = a_noCells();
22391 const MInt noCVars = CV->noVariables;
22392 mTerm(1, "code does not work, see comment below");
22393
22394 for(MInt cellId = 0; cellId < noCellIds; cellId++) {
22395 for(MInt varId = 0; varId < noCVars; varId++) {
22396 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
22397 a_variable(cellId, varId) -=
22398 a_restrictedVar(cellId, varId); // This code does not work since the level information is ignored!
22399 }
22400 a_tau(cellId, varId) = 0;
22401 }
22402 }
22403}
22404
22405template <MInt nDim_, class SysEqn>
22407 TRACE();
22408
22409 m_fvBndryCnd->copyRHSIntoGhostCells();
22410}
22411
22412
22421// TODO labels:FV use more meaningful name for this function?
22422template <MInt nDim_, class SysEqn>
22424 TRACE();
22425
22426 this->identifyBoundaryCells();
22427
22428 ASSERT(c_noCells() == a_noCells() && a_noCells() == grid().tree().size(),
22429 to_string(c_noCells()) + " " + to_string(a_noCells()) + " " + to_string(grid().tree().size()) + " "
22430 + to_string(m_cells.size()));
22431
22432 // reset a_isInterface if the cell IsInactive (negative Ls-value and no active Corners!)
22433 // and also for nonLeaf-Cells!
22434 // TODO labels:FV why not always reset isInterface for non-leaf cells
22435 if(m_levelSetMb && !m_constructGField) {
22436 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
22437 assertValidGridCellId(cellId);
22438 if(a_isInterface(cellId)) {
22439 if(c_isLeafCell(cellId) && a_hasProperty(cellId, SolverCell::IsInactive)) {
22440 a_isInterface(cellId) = false;
22441 } else if(!c_isLeafCell(cellId)) {
22442 a_isInterface(cellId) = false;
22443 }
22444 }
22445 }
22446 }
22447}
22448
22454template <MInt nDim_, class SysEqn>
22456 TRACE();
22457
22458 const MInt noSrfcs = a_noSurfaces();
22459 MInt nghbrCells[2];
22460 MFloat eps = F1 / FPOW10[10];
22461 MFloat totalDistance, distance;
22462 MFloat factor0, factor1;
22463 //---
22464
22465
22466 // 1) compute the factors 0 and 1 for all surfaces
22467 for(MInt srfcId = 0; srfcId < noSrfcs; srfcId++) {
22468 nghbrCells[0] = a_surfaceNghbrCellId(srfcId, 0);
22469 nghbrCells[1] = a_surfaceNghbrCellId(srfcId, 1);
22470 distance = F0;
22471 totalDistance = F0;
22472 for(MInt i = 0; i < nDim; i++) {
22473 distance += POW2(a_surfaceCoordinate(srfcId, i) - a_coordinate(nghbrCells[0], i));
22474 totalDistance += POW2(a_surfaceCoordinate(srfcId, i) - a_coordinate(nghbrCells[1], i));
22475 }
22476 distance = sqrt(distance);
22477 totalDistance = sqrt(totalDistance) + distance;
22478 factor1 = distance / mMax(eps, totalDistance);
22479 factor0 = F1 - factor1;
22480 a_surfaceFactor(srfcId, 0) = factor0;
22481 a_surfaceFactor(srfcId, 1) = factor1;
22482 }
22483
22484 if(!m_fvBndryCnd->m_cellMerging) {
22485#ifdef _OPENMP
22486#pragma omp parallel for
22487#endif
22488 for(MInt bs = 0; bs < m_fvBndryCnd->m_noBoundarySurfaces; bs++) {
22489 MInt srfcId = m_fvBndryCnd->m_boundarySurfaces[bs];
22490 a_surfaceFactor(srfcId, 0) = F1B2;
22491 a_surfaceFactor(srfcId, 1) = F1B2;
22492 }
22493 }
22494}
22495
22496
22501template <MInt nDim_, class SysEqn>
22503 static constexpr MFloat signStencil[8][3] = {{-F1, -F1, -F1}, {F1, -F1, -F1}, {-F1, F1, -F1}, {F1, F1, -F1},
22504 {-F1, -F1, F1}, {F1, -F1, F1}, {-F1, F1, F1}, {F1, F1, F1}};
22505
22506 if(!g_multiSolverGrid) ASSERT(grid().raw().a_hasProperty(gridCellId, Cell::WasRefined), "");
22507
22508 const MInt noCVars = CV->noVariables;
22509 const MInt noFVars = FV->noVariables;
22510 const MInt noPVars = PV->noVariables;
22511 const MInt childLevel = grid().raw().a_level(gridCellId) + 1;
22512 const MFloat childCellLength = c_cellLengthAtLevel(childLevel);
22513 const MFloat childVolume = grid().cellVolumeAtLevel(childLevel);
22514
22515 const MInt solverCellId = grid().tree().grid2solver(gridCellId);
22516
22517 const MFloat* const pvarsCell = ALIGNED_F(&a_pvariable(solverCellId, 0));
22518 const MFloat* const cvarsCell = ALIGNED_F(&a_variable(solverCellId, 0));
22519 const MFloat* const avarsCell = ALIGNED_F(&a_avariable(solverCellId, 0));
22520 const MFloat* const slopesCell = ALIGNED_F(&a_slope(solverCellId, 0, 0));
22521
22522 if(!g_multiSolverGrid) ASSERT(solverCellId == gridCellId, "");
22523 if(solverCellId < 0) return;
22524
22525 MInt noAddedChilds = 0;
22526
22527 for(MInt c = 0; c < grid().m_maxNoChilds; c++) {
22528 const MInt gridChildId = grid().raw().a_childId(gridCellId, c);
22529
22530 if(gridChildId < 0) continue;
22531 // not necessarily all childs will be used, some have not been added to the grid-tree
22532
22533 if(grid().azimuthalPeriodicity()) {
22534 // Solver flag will be set in proxy
22535 // The cartesianGrid does not know the geometry, therefore it needs to be checked
22536 // that the child actually is inside the geometry
22537 if(grid().checkOutsideGeometry(gridChildId) == 1) {
22538 grid().raw().setSolver(gridChildId, solverId(), false);
22539 continue;
22540 }
22541 }
22542
22543 // solverFlag is set in CartesianGrid<nDim>::setChildSolverFlag
22544 // solverFlag is false if the specific child lies outside the solver geoemtry
22545 if(!grid().solverFlag(gridChildId, solverId())) continue;
22546
22547 // Skip if cell is a partition level ancestor and its child was not newly created
22548 if(!grid().raw().a_hasProperty(gridChildId, Cell::WasNewlyCreated)
22549 && grid().raw().a_hasProperty(gridCellId, Cell::IsPartLvlAncestor)) {
22550 continue;
22551 }
22552
22553 MInt solverChildId = this->createCellId(gridChildId);
22554 noAddedChilds++;
22555
22556 ASSERT(grid().tree().solver2grid(solverChildId) == gridChildId, " ");
22557 if(!g_multiSolverGrid) ASSERT(solverChildId == gridChildId, "");
22558
22559 std::vector<std::vector<MFloat>> dQ(PV->noVariables, std::vector<MFloat>(nDim));
22560 MFloat U2 = F0;
22561 for(MInt i = 0; i < nDim; i++) {
22562 U2 += POW2(a_pvariable(solverCellId, PV->VV[i]));
22563 }
22564
22565 dQ = sysEqn().conservativeSlopes(pvarsCell, cvarsCell, avarsCell, slopesCell);
22566
22567 for(MInt v = 0; v < noCVars; v++) {
22568 for(MInt i = 0; i < nDim; i++) {
22569 dQ[v][i] *= F1B2 * childCellLength;
22570 if(std::isnan(dQ[v][i])) {
22571 dQ[v][i] = 0.0;
22572 }
22573 }
22574 }
22575 for(MInt v = 0; v < noCVars; v++) {
22576 a_variable(solverChildId, v) = a_variable(solverCellId, v);
22577 if(globalTimeStep > 0) {
22578 for(MInt i = 0; i < nDim; i++) {
22579 ASSERT(!std::isnan(dQ[v][i]), "");
22580 a_variable(solverChildId, v) += signStencil[c][i] * dQ[v][i];
22581 }
22582 }
22583 }
22584
22585 IF_CONSTEXPR(isDetChem<SysEqn>) {
22586 for(MUint v = 0; v < PV->m_noSpecies; v++) {
22587 a_speciesReactionRate(solverChildId, v) = a_speciesReactionRate(solverCellId, v);
22588 }
22589 }
22590 else {
22591 // ensure mass-conservancy for species:
22592 for(MInt s = 0; s < m_noSpecies; s++) {
22593 a_variable(solverChildId, CV->RHO_Y[s]) = a_variable(solverCellId, CV->RHO_Y[s]);
22594 }
22595 }
22596
22597 for(MInt v = 0; v < noCVars; v++) {
22598 a_oldVariable(solverChildId, v) = a_variable(solverChildId, v);
22599 }
22600 for(MInt v = 0; v < noFVars; v++) {
22601 a_rightHandSide(solverChildId, v) = FFPOW2(nDim) * a_rightHandSide(solverCellId, v);
22602 }
22603 for(MInt v = 0; v < noPVars; v++) {
22604 for(MInt i = 0; i < nDim; i++) {
22605 a_slope(solverChildId, v, i) = a_slope(solverCellId, v, i);
22606 }
22607 }
22608
22609 // STG adaptation
22610 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) {
22611 if(m_zonal) {
22612 vector<MInt>::iterator findAverageId = find(m_LESAverageCells.begin(), m_LESAverageCells.end(), solverCellId);
22613 vector<MInt>::iterator findAverageChildId =
22614 find(m_LESAverageCells.begin(), m_LESAverageCells.end(), solverChildId);
22615
22616 if(findAverageId != m_LESAverageCells.end() && !a_isHalo(solverChildId)) {
22617 if(findAverageChildId == m_LESAverageCells.end() && !a_isHalo(solverChildId)) {
22618 MInt LESAvgId = distance(m_LESAverageCells.begin(), findAverageId);
22619 for(MInt v = 0; v < m_LESNoVarAverage; v++) {
22620 m_LESVarAverage[v].push_back(m_LESVarAverage[v][LESAvgId]);
22621 }
22622 m_LESAverageCells.push_back(solverChildId);
22623 }
22624 }
22625 }
22626 }
22627
22628 setPrimitiveVariables(solverChildId);
22629
22630 a_bndryId(solverChildId) = -1;
22631
22632 a_cellVolume(solverChildId) = childVolume;
22633 a_FcellVolume(solverChildId) = F1 / childVolume;
22634
22635 a_noReconstructionNeighbors(solverChildId) = 0;
22636 for(MInt k = 0; k < m_cells.noRecNghbrs(); k++) {
22637 a_reconstructionNeighborId(solverChildId, k) = -1;
22638 }
22639
22640 // check-child-values
22641#if defined _MB_DEBUG_ || !defined NDEBUG
22642 for(MInt v = 0; v < noPVars; v++) {
22643 if(std::isnan(a_pvariable(solverChildId, v)) && a_hasProperty(solverCellId, SolverCell::IsOnCurrentMGLevel)
22644 && !a_isHalo(solverCellId)) {
22645 cerr << "Invalid-value in refined-Cell! "
22646 << " " << solverChildId << " " << endl;
22647 }
22648 }
22649 if(a_hasProperty(solverCellId, SolverCell::IsOnCurrentMGLevel) && !a_isHalo(solverCellId)
22650 && a_variable(solverChildId, CV->RHO) < m_eps) {
22651 cerr << "rho is zero or negative-2!" << endl;
22652 }
22653#endif
22654
22655 // necessary for diagonal bndryRefinement!
22656 // TODO labels:FV check why this changes the 2D_cylinder_adaptive-loadbalance_highPartitionLevelShift
22657 // testcase!
22658 if(m_levelSetMb) {
22659 a_hasProperty(solverChildId, SolverCell::IsOnCurrentMGLevel) =
22660 a_hasProperty(solverCellId, SolverCell::IsOnCurrentMGLevel);
22661 a_hasProperty(solverChildId, SolverCell::IsInactive) = a_hasProperty(solverCellId, SolverCell::IsInactive);
22662 }
22663 }
22664 a_noReconstructionNeighbors(solverCellId) = 0;
22665 for(MInt k = 0; k < m_cells.noRecNghbrs(); k++) {
22666 a_reconstructionNeighborId(solverCellId, k) = -1;
22667 }
22668
22669 if(m_sensorParticle && !a_isHalo(solverCellId) && noAddedChilds > 0) {
22670 const MInt noParticles = a_noPart(solverCellId);
22671
22672 MInt noParticlesEach = noParticles / noAddedChilds;
22673 MInt lastChild = -1;
22674 for(MInt child = 0; child < grid().m_maxNoChilds; child++) {
22675 const MInt childId = c_childId(solverCellId, child);
22676 if(childId < 0) continue;
22677 a_noPart(childId) = noParticles > 0 ? noParticlesEach : 0;
22678 lastChild = child;
22679 }
22680 MInt remainingParticles = noParticles - ((c_noChildren(solverCellId) - 1) * noParticlesEach);
22681 if(lastChild > -1) {
22682 a_noPart(c_childId(solverCellId, lastChild)) = noParticles > 0 ? remainingParticles : 0;
22683 }
22684
22685 if(noAddedChilds > 0) {
22686 a_noPart(solverCellId) = 0;
22687 }
22688 }
22689
22690 if(noAddedChilds > 0) {
22691 a_hasProperty(solverCellId, SolverCell::IsOnCurrentMGLevel) = false;
22692 }
22693}
22694
22695
22696// --------------------------------------------------------------------------------------
22697
22702template <MInt nDim_, class SysEqn>
22704 const MInt solverCellId = grid().tree().grid2solver(gridCellId);
22705
22706 ASSERT(solverCellId > -1 && solverCellId < m_cells.size(), "");
22707 ASSERT(c_noChildren(solverCellId) > 0, "");
22708
22709 if(!g_multiSolverGrid) ASSERT(solverCellId == gridCellId, "");
22710 if(!g_multiSolverGrid) ASSERT(m_cells.size() == grid().raw().treeb().size(), "");
22711
22712 // reset the solverCell-properties for the new leaf-cell:
22713 //- volume
22714 //- variables
22715 //- oldVariables only if not already updated in fvmb-version!
22716 //- slope
22717 //- rightHandSide
22718 const MInt noCVars = CV->noVariables;
22719 const MInt noFVars = FV->noVariables;
22720 const MInt noPVars = PV->noVariables;
22721 a_cellVolume(solverCellId) = F0;
22722
22723 for(MInt v = 0; v < noCVars; v++) {
22724 a_variable(solverCellId, v) = F0;
22725 if(!m_levelSetMb) {
22726 a_oldVariable(solverCellId, v) = F0;
22727 }
22728 for(MInt i = 0; i < nDim; i++) {
22729 a_slope(solverCellId, v, i) = F0;
22730 }
22731 }
22732 for(MInt v = 0; v < noFVars; v++) {
22733 a_rightHandSide(solverCellId, v) = F0;
22734 }
22735
22736 MInt isInactive = 0;
22737 MInt noRemovedChilds = 0;
22738 MInt noParticles = 0;
22739
22740 for(MInt c = 0; c < grid().m_maxNoChilds; c++) {
22741 const MInt gridChildId = grid().raw().a_childId(gridCellId, c);
22742 const MInt childId = c_childId(solverCellId, c);
22743
22744 if(childId < 0) continue;
22745 noRemovedChilds++;
22746 if(m_sensorParticle) noParticles += a_noPart(childId);
22747
22748 ASSERT(grid().tree().solver2grid(childId) == gridChildId, "");
22749
22750 // only use active childs for interpolation!
22751 if(!a_hasProperty(childId, SolverCell::IsInactive)) {
22752 const MFloat vol = a_cellVolume(childId);
22753 a_cellVolume(solverCellId) += vol;
22754 for(MInt v = 0; v < noCVars; v++) {
22755 a_variable(solverCellId, v) += vol * a_variable(childId, v);
22756 if(!m_levelSetMb) {
22757 a_oldVariable(solverCellId, v) += vol * a_oldVariable(childId, v);
22758 }
22759 }
22760 for(MInt v = 0; v < noFVars; v++) {
22761 a_rightHandSide(solverCellId, v) += a_rightHandSide(childId, v);
22762 }
22763 for(MInt v = 0; v < noPVars; v++) {
22764 for(MInt j = 0; j < nDim; j++) {
22765 a_slope(solverCellId, v, j) += vol * a_slope(childId, v, j);
22766 }
22767 }
22768
22769 // STG adaptation
22770 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) {
22771 if(m_zonal) {
22772 vector<MInt>::iterator findAverageChildId =
22773 find(m_LESAverageCells.begin(), m_LESAverageCells.end(), solverCellId);
22774 if(findAverageChildId != m_LESAverageCells.end()) {
22775 MInt LESChildId = distance(m_LESAverageCells.begin(), findAverageChildId);
22776 for(MInt v = 0; v < m_LESNoVarAverage; v++) {
22777 m_LESVarAverage[v].erase(m_LESVarAverage[v].begin() + LESChildId);
22778 }
22779 m_LESAverageCells.erase(m_LESAverageCells.begin() + LESChildId);
22780 // m_noLESAverageCells--;
22781 }
22782 }
22783 }
22784
22785 } else {
22786 isInactive++;
22787 }
22788
22789 a_bndryId(childId) = -1;
22790 this->removeCellId(childId);
22791 }
22792
22793 if(m_sensorParticle) a_noPart(solverCellId) = noParticles;
22794
22795 // update variables and properties for the new leaf-cell:
22796 if(isInactive == noRemovedChilds) {
22797 // if of all childs are inactive, default variables are set!
22798 a_hasProperty(solverCellId, SolverCell::IsInactive) = true;
22799 a_hasProperty(solverCellId, SolverCell::IsOnCurrentMGLevel) = false;
22800 a_cellVolume(solverCellId) = c_cellVolumeAtLevel(a_level(solverCellId));
22801
22802 a_variable(solverCellId, CV->RHO) = m_rhoInfinity;
22803 IF_CONSTEXPR(hasE<SysEqn>)
22804 a_variable(solverCellId, CV->RHO_E) = m_rhoEInfinity;
22805 for(MInt dir = 0; dir < nDim; dir++) {
22806 a_variable(solverCellId, CV->RHO_VV[dir]) = m_rhoVVInfinity[dir];
22807 }
22808 } else {
22809 if(!a_isHalo(solverCellId)) {
22810 ASSERT(a_variable(solverCellId, CV->RHO) > 0, "Zero density when removing childs!");
22811 }
22812 for(MInt v = 0; v < noCVars; v++) {
22813 a_variable(solverCellId, v) /= mMax(m_volumeThreshold, a_cellVolume(solverCellId));
22814 if(!m_levelSetMb) {
22815 a_oldVariable(solverCellId, v) /= mMax(m_volumeThreshold, a_cellVolume(solverCellId));
22816 }
22817 }
22818 for(MInt v = 0; v < noPVars; v++) {
22819 for(MInt i = 0; i < nDim; i++) {
22820 a_slope(solverCellId, v, i) /= mMax(m_volumeThreshold, a_cellVolume(solverCellId));
22821 }
22822 }
22823 a_hasProperty(solverCellId, SolverCell::IsOnCurrentMGLevel) = true;
22824 a_hasProperty(solverCellId, SolverCell::IsInactive) = false;
22825 }
22826
22827 a_FcellVolume(solverCellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(solverCellId));
22828 setPrimitiveVariables(solverCellId);
22829
22830 // only single-solver!
22831 if(!g_multiSolverGrid) ASSERT((m_cells.size() - grid().raw().treeb().size()) <= grid().m_maxNoChilds, "");
22832}
22833
22834
22838template <MInt nDim_, class SysEqn>
22840 const MInt solverCellId = grid().tree().grid2solver(gridCellId);
22841
22842 ASSERT(gridCellId > -1 && gridCellId < grid().raw().treeb().size() && solverCellId > -1
22843 && solverCellId < m_cells.size() && grid().tree().solver2grid(solverCellId) == gridCellId,
22844 "");
22845 ASSERT(c_noChildren(solverCellId) == 0, "");
22846
22847 this->removeCellId(solverCellId);
22848}
22849
22850// --------------------------------------------------------------------------------------
22851
22856template <MInt nDim_, class SysEqn>
22857void FvCartesianSolverXD<nDim_, SysEqn>::swapCells(const MInt cellId0, const MInt cellId1) {
22858 if(cellId1 == cellId0) return;
22859
22860 const MInt noCVars = CV->noVariables;
22861 const MInt noFVars = FV->noVariables;
22862 const MInt noPVars = PV->noVariables;
22863 const MInt noAVars = AV->noVariables;
22864 for(MInt v = 0; v < noCVars; v++) {
22865 std::swap(a_variable(cellId1, v), a_variable(cellId0, v));
22866 std::swap(a_oldVariable(cellId1, v), a_oldVariable(cellId0, v));
22867 if(m_dualTimeStepping) {
22868 std::swap(a_dt1Variable(cellId1, v), a_dt1Variable(cellId0, v));
22869 std::swap(a_dt2Variable(cellId1, v), a_dt2Variable(cellId0, v));
22870 }
22871 }
22872 for(MInt v = 0; v < noFVars; v++) {
22873 std::swap(a_rightHandSide(cellId1, v), a_rightHandSide(cellId0, v));
22874 }
22875 for(MInt v = 0; v < noPVars; v++) {
22876 std::swap(a_pvariable(cellId1, v), a_pvariable(cellId0, v));
22877 for(MInt i = 0; i < nDim; i++) {
22878 std::swap(a_slope(cellId1, v, i), a_slope(cellId0, v, i));
22879 }
22880 }
22881
22882 if(hasAV) {
22883 for(MInt v = 0; v < noAVars; v++) {
22884 std::swap(a_avariable(cellId1, v), a_avariable(cellId0, v));
22885 }
22886 }
22887
22888 std::swap(a_cellVolume(cellId1), a_cellVolume(cellId0));
22889 std::swap(a_FcellVolume(cellId1), a_FcellVolume(cellId0));
22890
22891 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) {
22892 if(m_zonal) {
22893 vector<MInt>::iterator findId0 = find(m_LESAverageCells.begin(), m_LESAverageCells.end(), cellId0);
22894 vector<MInt>::iterator findId1 = find(m_LESAverageCells.begin(), m_LESAverageCells.end(), cellId1);
22895
22896 if(findId0 != m_LESAverageCells.end() && findId1 != m_LESAverageCells.end()) {
22897 MInt LESId0 = distance(m_LESAverageCells.begin(), findId0);
22898 MInt LESId1 = distance(m_LESAverageCells.begin(), findId1);
22899 for(MInt v = 0; v < m_LESNoVarAverage; v++) {
22900 std::swap(m_LESVarAverage[v][LESId0], m_LESVarAverage[v][LESId1]);
22901 }
22902 std::swap(m_LESAverageCells[LESId0], m_LESAverageCells[LESId1]);
22903 } else if(findId0 != m_LESAverageCells.end() && findId1 == m_LESAverageCells.end()) {
22904 MInt LESId0 = distance(m_LESAverageCells.begin(), findId0);
22905 m_LESAverageCells[LESId0] = cellId1;
22906 } else if(findId0 == m_LESAverageCells.end() && findId1 != m_LESAverageCells.end()) {
22907 MInt LESId1 = distance(m_LESAverageCells.begin(), findId1);
22908 m_LESAverageCells[LESId1] = cellId0;
22909 }
22910 }
22911 }
22912
22913 std::swap(a_spongeFactor(cellId1), a_spongeFactor(cellId0));
22914 std::swap(a_spongeBndryId(cellId1, 0), a_spongeBndryId(cellId0, 0));
22915 std::swap(a_spongeBndryId(cellId1, 1), a_spongeBndryId(cellId0, 1));
22916 IF_CONSTEXPR(nDim == 3) { std::swap(a_spongeBndryId(cellId1, 2), a_spongeBndryId(cellId0, 2)); }
22917
22918 const MInt bndryId0 = a_bndryId(cellId0);
22919 const MInt bndryId1 = a_bndryId(cellId1);
22920 if(bndryId0 > -1) {
22921 ASSERT(m_fvBndryCnd->m_bndryCells->a[bndryId0].m_cellId == cellId0, "bndryId not expected");
22922 m_fvBndryCnd->m_bndryCells->a[bndryId0].m_cellId = cellId1;
22923 }
22924 if(bndryId1 > -1) {
22925 ASSERT(m_fvBndryCnd->m_bndryCells->a[bndryId1].m_cellId == cellId1, "bndryId not expected");
22926 m_fvBndryCnd->m_bndryCells->a[bndryId1].m_cellId = cellId0;
22927 }
22928 std::swap(a_bndryId(cellId1), a_bndryId(cellId0));
22929
22930 std::swap(m_cells.properties(cellId1), m_cells.properties(cellId0));
22931
22932 if(m_sensorParticle) {
22933 std::swap(a_noPart(cellId1), a_noPart(cellId0));
22934 }
22935}
22936
22937
22938// --------------------------------------------------------------------------------------
22939
22944template <MInt nDim_, class SysEqn>
22945void FvCartesianSolverXD<nDim_, SysEqn>::swapProxy(const MInt cellId0, const MInt cellId1) {
22946 grid().swapGridIds(cellId0, cellId1);
22947}
22948
22949
22950// --------------------------------------------------------------------------------------
22951
22952
22953// this function should be moved to Solver as soon as cartesiansolver.h has been removed!!!
22954// this function should be moved to Solver as soon as cartesiansolver.h has been removed!!
22955// this function should be moved to Solver as soon as cartesiansolver.h has been removed!!!
22956template <MInt nDim_, class SysEqn>
22958 grid().resizeGridMap(m_cells.size());
22959}
22960
22961
22962// --------------------------------------------------------------------------------------
22963
22968template <MInt nDim_, class SysEqn>
22970 return m_fvBndryCnd->checkOutside(cellId);
22971}
22972
22973
22974// --------------------------------------------------------------------------------------
22975
22980template <MInt nDim_, class SysEqn>
22981MInt FvCartesianSolverXD<nDim_, SysEqn>::cellOutside(const MFloat* coords, const MInt level, const MInt gridCellId) {
22982 if(m_engineSetup) {
22983 return -1;
22984 }
22985
22986 MInt solverCellId = grid().tree().grid2solver(gridCellId);
22987 if(!grid().raw().m_allowInterfaceRefinement) return 0;
22988 if(!a_isInterface(solverCellId)) return 0;
22989 return m_fvBndryCnd->checkOutside(coords, level);
22990}
22991
22992
22993// --------------------------------------------------------------------------------------
22994
22999template <MInt nDim_, class SysEqn>
23001 m_surfaces.clear(); // invalidate all elements and set size to 0
23002 m_fvBndryCnd->m_noBoundarySurfaces = 0;
23003 std::set<MInt>().swap(m_splitSurfaces);
23004}
23005
23006
23007// --------------------------------------------------------------------------------------
23012// FIXME labels:FV; optimization with gnu 7.2 -O3 causes bugs in this function
23013template <MInt nDim_, class SysEqn>
23014ATTRIBUTES1(ATTRIBUTE_NO_AUTOVEC)
23016 const MInt noPVars = PV->noVariables;
23017
23018 if(m_fvBndryCnd->m_cellCoordinatesCorrected) {
23019 m_fvBndryCnd->recorrectCellCoordinates();
23020 }
23021
23022#ifdef _OPENMP
23023#pragma omp parallel for
23024#endif
23025 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
23026 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
23027 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId = -1;
23028 for(MInt i = 0; i < nDim; i++) {
23029 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = -1;
23030 }
23031 }
23032 }
23033
23034 m_bndryGhostCellsOffset = c_noCells();
23035
23036#ifdef _OPENMP
23037#pragma omp parallel for
23038#endif
23039 for(MInt c = m_bndryGhostCellsOffset; c < a_noCells(); c++) {
23040 a_bndryId(c) = -1;
23041 a_isBndryGhostCell(c) = false;
23042 a_resetPropertiesSolver(c);
23043 }
23044
23045
23046#ifdef _OPENMP
23047#pragma omp parallel for
23048#endif
23049 for(MInt c = 0; c < a_noCells(); c++) {
23050 a_hasProperty(c, SolverCell::IsInvalid) = false;
23051 a_hasProperty(c, SolverCell::IsSplitCell) = false;
23052 a_hasProperty(c, SolverCell::IsSplitChild) = false;
23053 a_hasProperty(c, SolverCell::HasSplitFace) = false;
23054 a_hasProperty(c, SolverCell::IsTempLinked) = false;
23055 a_hasProperty(c, SolverCell::IsMovingBnd) = false;
23056 }
23057
23058 // resize fvCellCollector to m_bndryGhostCellsOffset
23059 m_cells.size(m_bndryGhostCellsOffset);
23060 ASSERT(m_cells.size() == c_noCells(), "");
23061
23062
23063 // delete previous moving boundary cells
23064 for(MInt bndryId = m_fvBndryCnd->m_bndryCells->size() - 1; bndryId >= offset; bndryId--) {
23065 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
23066
23067 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
23068 MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
23069 if(ghostCellId > -1) {
23070 ASSERT(a_bndryId(ghostCellId) == -2, "");
23071 a_bndryId(ghostCellId) = -1;
23072 }
23073 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId = -1;
23074 }
23075
23076 a_bndryId(cellId) = -1;
23077
23078 MInt size = m_fvBndryCnd->m_bndryCells->size();
23079 m_fvBndryCnd->m_bndryCells->resetSize(size - 1);
23080
23081 // since the resizing of the cell container above creates invalid cellId we need to make sure only valid cells are
23082 // reset in fvcellcollector
23083 if(cellId < m_bndryGhostCellsOffset) {
23084 a_noReconstructionNeighbors(cellId) = 0;
23085 }
23086 m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.resize(0);
23087 m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst.resize(0);
23088 std::vector<MFloat>().swap(m_fvBndryCnd->m_bndryCell[bndryId].m_faceVertices);
23089 for(MUint i = 0; i < m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream.size(); i++) {
23090 m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream[i].resize(0);
23091 }
23092 m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream.resize(0);
23093 for(MInt srfc = 0; srfc < FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces; srfc++) {
23094 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_noCutPoints = 0;
23095 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst.resize(0);
23096 // FIXME labels:FV,totest
23097 // This is the loop that is optimized and causes a segmentation fault
23098 for(MInt v = 0; v < noPVars; v++) {
23099 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] = BC_UNSET;
23100 }
23101 }
23102 m_bndryCells->a[bndryId].m_noSrfcs = 0;
23103
23104 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > -1) {
23105 MInt pm = m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId;
23106 a_cellVolume(pm) = grid().cellVolumeAtLevel(a_level(pm));
23107 a_FcellVolume(pm) = F1 / mMax(m_volumeThreshold, a_cellVolume(pm));
23108 m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId = -1;
23109 }
23110
23111 m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId = -1;
23112 }
23113
23114
23115 std::vector<MInt>().swap(m_splitCells);
23116 std::vector<std::vector<MInt>>().swap(m_splitChilds);
23117 std::map<MInt, MInt>().swap(m_splitChildToSplitCell);
23118 std::vector<MInt>().swap(m_associatedInternalCells);
23119
23120 m_totalnosplitchilds = 0;
23121 m_totalnoghostcells = 0;
23122 // These are properly deleted in resetCutOff and allocateCutOffMemory in fvCartesianBndryCndxd.cpp
23123 // This clear results in memory leaks!
23124 // m_fvBndryCnd->m_sortedCutOffCells.clear();
23125}
23126
23127
23128// --------------------------------------------------------------------------------------
23129
23134template <MInt nDim_, class SysEqn>
23136 if(noNeighborDomains() == 0) {
23137 if(noDomains() > 1) {
23138 mTerm(1, "Unexpected situation in updateMultiSolverInformation!");
23139 }
23140 return;
23141 }
23142
23143
23144 if(fullReset) {
23145 if(!m_fvBndryCnd->m_cellMerging) {
23146 mDeallocate(m_fvBndryCnd->m_nearBoundaryWindowCells);
23147 mDeallocate(m_fvBndryCnd->m_nearBoundaryHaloCells);
23148 mAlloc(m_fvBndryCnd->m_nearBoundaryWindowCells, noNeighborDomains(), "m_nearBoundaryWindowCells", AT_);
23149 mAlloc(m_fvBndryCnd->m_nearBoundaryHaloCells, noNeighborDomains(), "m_nearBoundaryHaloCells", AT_);
23150 }
23151 mDeallocate(m_mpi_request);
23152 mAlloc(m_mpi_request, noNeighborDomains(), "m_mpi_request", AT_);
23153 if(m_nonBlockingComm) {
23154 mDeallocate(m_mpi_receiveRequest);
23155 mDeallocate(m_mpi_sendRequest);
23156 mAlloc(m_mpi_receiveRequest, noNeighborDomains(), "m_mpi_receiveRequest ", MPI_REQ_NULL, AT_);
23157 mAlloc(m_mpi_sendRequest, noNeighborDomains(), "m_mpi_sendRequest", MPI_REQ_NULL, AT_);
23158 }
23159 }
23160
23161
23162 ScratchSpace<MInt> haloCellsCnt(noNeighborDomains(), AT_, "noHaloCells");
23163 ScratchSpace<MInt> windowCellsCnt(noNeighborDomains(), AT_, "noWindowCells");
23164 for(MInt d = 0; d < noNeighborDomains(); d++) {
23165 haloCellsCnt[d] = noHaloCells(d);
23166 windowCellsCnt[d] = noWindowCells(d);
23167 }
23168 mDeallocate(m_maxLevelHaloCells);
23169 mDeallocate(m_maxLevelWindowCells);
23170 mDeallocate(m_noMaxLevelHaloCells);
23171 mDeallocate(m_noMaxLevelWindowCells);
23172 mAlloc(m_maxLevelHaloCells, noNeighborDomains(), &haloCellsCnt[0], "m_maxLevelHaloCells", AT_);
23173 mAlloc(m_maxLevelWindowCells, noNeighborDomains(), &windowCellsCnt[0], "m_maxLevelWindowCells", AT_);
23174 mAlloc(m_noMaxLevelHaloCells, noNeighborDomains(), "m_noMaxLevelHaloCells", 0, AT_);
23175 mAlloc(m_noMaxLevelWindowCells, noNeighborDomains(), "m_noMaxLevelWindowCells", 0, AT_);
23176
23177 mDeallocate(m_sendBuffers);
23178 mDeallocate(m_receiveBuffers);
23179 mAlloc(m_sendBuffers, noNeighborDomains(), &windowCellsCnt[0], m_dataBlockSize, "m_sendBuffers", AT_);
23180 mAlloc(m_receiveBuffers, noNeighborDomains(), &haloCellsCnt[0], m_dataBlockSize, "m_receiveBuffers", AT_);
23181
23182 if(m_nonBlockingComm) {
23183 mDeallocate(m_sendBuffersNoBlocking);
23184 mDeallocate(m_receiveBuffersNoBlocking);
23185 mAlloc(m_sendBuffersNoBlocking, noNeighborDomains(), &windowCellsCnt[0], m_dataBlockSize, "m_sendBuffersNoBlocking",
23186 AT_);
23187 mAlloc(m_receiveBuffersNoBlocking, noNeighborDomains(), &haloCellsCnt[0], m_dataBlockSize,
23188 "m_receiveBuffersNoBlocking", AT_);
23189 for(MInt i = 0; i < noNeighborDomains(); i++) {
23190 m_mpi_receiveRequest[i] = MPI_REQUEST_NULL;
23191 m_mpi_sendRequest[i] = MPI_REQUEST_NULL;
23192 }
23193 }
23194}
23195
23203template <MInt nDim_, class SysEqn>
23204void FvCartesianSolverXD<nDim_, SysEqn>::sensorInterface(std::vector<std::vector<MFloat>>& sensors,
23205 std::vector<std::bitset<64>>& sensorCellFlag,
23206 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
23207 MInt sen) {
23208 // Setting function pointer for sensorInterface
23209
23210 if(m_levelSet && !m_levelSetMb && !m_combustion) {
23211 sensorInterfaceLs(sensors, sensorCellFlag, sensorWeight, sensorOffset, sen);
23212 } else if(m_levelSetMb && !m_constructGField && m_levelSetAdaptationScheme == 2) {
23213 sensorInterfaceLsMb(sensors, sensorCellFlag, sensorWeight, sensorOffset, sen);
23214 } else {
23215 sensorInterfaceDelta(sensors, sensorCellFlag, sensorWeight, sensorOffset, sen);
23216 }
23217}
23218
23219template <MInt nDim_, class SysEqn>
23220void FvCartesianSolverXD<nDim_, SysEqn>::sensorInterfaceLsMb(std::vector<std::vector<MFloat>>& sensors,
23221 std::vector<std::bitset<64>>& sensorCellFlag,
23222 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
23223 MInt sen) {
23224 m_log << " - Sensor preparation for the interface sensor" << endl;
23225 ScratchSpace<MFloat> distance(a_noCells(), AT_, "distance");
23226 getBoundaryDistance(distance);
23227
23228 MIntScratchSpace inList(a_noCells(), AT_, "inList");
23229
23230 // cast floating array in MInt-array!
23231 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23232 inList(cellId) = 0;
23233 if(a_level(cellId) < this->m_maxSensorRefinementLevel[sen]) {
23234 inList(cellId) = (MInt)distance(cellId);
23235 }
23236 }
23237
23238 for(MInt level = minLevel(); level < this->m_maxSensorRefinementLevel[sen]; level++) {
23239 this->markSurrndCells(inList, m_bandWidth[level], level, m_refineDiagonals);
23240 }
23241
23242 // unset sensor for cells ouside the liner geometry
23243 if(m_engineSetup) {
23244 const MInt linerSet = 1;
23245 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23246 if(inList(cellId) == 0) continue;
23247 if(a_level(cellId) == minLevel()) continue;
23248 if(c_noChildren(cellId) > 0) continue;
23249 if(a_levelSetValuesMb(cellId, linerSet) < -(m_maxLsValue - m_eps)) {
23250 inList(cellId) = 0;
23251 // MInt parentId = c_parentId( cellId );
23252 // while ( parentId > -1 && parentId < a_noCells()) {
23253 // inList(cellId) = 0;
23254 // parentId = c_parentId( parentId );
23255 //}
23256 }
23257 }
23258 }
23259
23260
23261#ifdef _OPENMP
23262#pragma omp parallel for
23263#endif
23264 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23265 ASSERT(!a_isBndryGhostCell(cellId), "");
23266 ASSERT(!a_isHalo(cellId), "");
23267 ASSERT(!c_isToDelete(cellId), "");
23268 if(inList(cellId) == 0) {
23269 if(a_level(cellId) == minLevel()) continue;
23270 if(inList(c_parentId(cellId))) continue;
23271 if(!c_isLeafCell(cellId)) continue;
23272 const MInt gridCellId = grid().tree().solver2grid(cellId);
23273 sensors[sensorOffset + sen][gridCellId] = -1.0;
23274 sensorCellFlag[gridCellId][sensorOffset + sen] = true;
23275 } else {
23276 MInt lvl = this->m_maxSensorRefinementLevel[sen] - 1;
23277 if(m_linerLvlJump && a_coordinate(cellId, 0) > -0.515 && a_coordinate(cellId, 0) < 0.515) {
23278 lvl = this->m_maxSensorRefinementLevel[sen];
23279 }
23280 const MInt sensorLvl = m_linerLvlJump ? lvl : this->m_maxSensorRefinementLevel[sen];
23281 if(a_level(cellId) < sensorLvl) {
23282 // if(c_noChildren(cellId) > 0) continue;
23283 const MInt gridCellId = grid().tree().solver2grid(cellId);
23284 sensors[sensorOffset + sen][gridCellId] = 1.0;
23285 sensorCellFlag[gridCellId][sensorOffset + sen] = true;
23286
23287 MInt parent = c_parentId(cellId);
23288 if(parent > -1 && parent < c_noCells()) {
23289 MInt parentGridCellId = grid().tree().solver2grid(parent);
23290 if(parentGridCellId > -1 && parentGridCellId < grid().raw().m_noInternalCells) {
23291 sensors[sensorOffset + sen][parentGridCellId] = 1.0;
23292 sensorCellFlag[parentGridCellId][sensorOffset + sen] = true;
23293 }
23294 }
23295 }
23296 }
23297 }
23298
23299 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
23300}
23301
23302template <MInt nDim_, class SysEqn>
23303void FvCartesianSolverXD<nDim_, SysEqn>::sensorInterfaceDelta(std::vector<std::vector<MFloat>>& sensors,
23304 std::vector<std::bitset<64>>& sensorCellFlag,
23305 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
23306 MInt sen) {
23307 m_log << " - Sensor preparation for the interface sensor" << endl;
23308
23309 ScratchSpace<MFloat> distance(a_noCells(), AT_, "distance");
23310 distance.fill(MFloatNaN); // fill with NaN to find errors
23311
23312 getBoundaryDistance(distance);
23313
23314#ifdef _OPENMP
23315#pragma omp parallel for
23316#endif
23317 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23318 ASSERT(!a_isBndryGhostCell(cellId), "");
23319 ASSERT(!a_isHalo(cellId), "");
23320 ASSERT(!c_isToDelete(cellId), "");
23321 const MInt gridId = this->grid().tree().solver2grid(cellId);
23322 const MInt level = a_level(cellId);
23323 MFloat delta = F0;
23324 if(level < maxRefinementLevel()) {
23325 delta = mMin(m_outerBandWidth[level] - distance[cellId], distance[cellId] - m_innerBandWidth[level]);
23326 sensors[sensorOffset + sen][gridId] = delta;
23327 sensorCellFlag[gridId][sensorOffset + sen] = true;
23328 }
23329 }
23330
23331 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
23332}
23333
23334
23335template <MInt nDim_, class SysEqn>
23336void FvCartesianSolverXD<nDim_, SysEqn>::sensorInterfaceLs(std::vector<std::vector<MFloat>>& sensors,
23337 std::vector<std::bitset<64>>& sensorCellFlag,
23338 std::vector<MFloat>& sensorWeight, MInt sensorOffset,
23339 MInt sen) {
23340 m_log << " - Sensor preparation for the interface sensor" << endl;
23341
23342 MIntScratchSpace inList(a_noCells(), AT_, "inList");
23343
23344 ScratchSpace<MFloat> distance(a_noCells(), AT_, "distance");
23345 getBoundaryDistance(distance);
23346
23347#ifdef _OPENMP
23348#pragma omp parallel for
23349#endif
23350 // cast floating array in int-array!
23351 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23352 inList(cellId) = 0;
23353 if(a_level(cellId) < this->m_maxSensorRefinementLevel[sen]) {
23354 inList(cellId) = (MInt)distance(cellId);
23355 }
23356 }
23357
23358 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23359 if(inList(cellId) == 0) {
23360 if(a_level(cellId) == minLevel()) continue;
23361 if(c_noChildren(cellId) == 0) {
23362 MInt gridCellId = grid().tree().solver2grid(cellId);
23363 sensors[sensorOffset + sen][gridCellId] = -1.0;
23364 sensorCellFlag[gridCellId][sensorOffset + sen] = 1;
23365 }
23366 } else {
23367 ASSERT(inList(cellId) > 0, "");
23368 MInt gridCellId = grid().tree().solver2grid(cellId);
23369 if(a_level(cellId) < maxRefinementLevel()) { // refine cell
23370 if(c_noChildren(cellId) > 0) continue;
23371 if(a_isHalo(cellId)) continue;
23372 sensors[sensorOffset + sen][gridCellId] = 1.0;
23373 sensorCellFlag[gridCellId][sensorOffset + sen] = 1;
23374 }
23375 }
23376 }
23377
23378 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
23379}
23380
23388template <MInt nDim_, class SysEqn>
23389void FvCartesianSolverXD<nDim_, SysEqn>::sensorCutOff(std::vector<std::vector<MFloat>>& sensors,
23390 std::vector<std::bitset<64>>& sensorCellFlag,
23391 std::vector<MFloat>& sensorWeight, MInt sensorOffset, MInt sen) {
23392 MIntScratchSpace cutOffCells(a_noCells(), AT_, "cutOffCells");
23393 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23394 cutOffCells(cellId) = 0;
23395 }
23396
23397 m_fvBndryCnd->markCutOff(cutOffCells);
23398
23399 MIntScratchSpace bandWidth(this->m_maxSensorRefinementLevel[sen], AT_, "bandWidth");
23400 constexpr MInt additionalLayers = 1;
23401
23402 bandWidth[this->m_maxSensorRefinementLevel[sen] - 1] =
23403 m_bandWidth[this->m_maxSensorRefinementLevel[sen] - 1] + additionalLayers;
23404
23405
23406 for(MInt i = this->m_maxSensorRefinementLevel[sen] - 2; i >= 0; i--) {
23407 bandWidth[i] = (bandWidth[i + 1] / 2) + 1;
23408 }
23409
23410 for(MInt level = minLevel(); level < this->m_maxSensorRefinementLevel[sen]; level++) {
23411 this->markSurrndCells(cutOffCells, bandWidth[level], level, m_refineDiagonals);
23412 }
23413
23414#ifdef _OPENMP
23415#pragma omp parallel for
23416#endif
23417 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23418 ASSERT(!a_isBndryGhostCell(cellId), "");
23419 ASSERT(!a_isHalo(cellId), "");
23420 ASSERT(!c_isToDelete(cellId), "");
23421 const MInt gridCellId = grid().tree().solver2grid(cellId);
23422 if(cutOffCells(cellId) > 0) {
23423 if(a_level(cellId) < this->m_maxSensorRefinementLevel[sen]) {
23424 sensors[sensorOffset + sen][gridCellId] = 1.0;
23425 sensorCellFlag[gridCellId][sensorOffset + sen] = true;
23426 MInt parent = c_parentId(cellId);
23427 if(parent > -1 && parent < a_noCells()) {
23428 MInt parentGridCellId = grid().tree().solver2grid(parent);
23429 if(parentGridCellId > -1 && parentGridCellId < grid().raw().m_noInternalCells) {
23430 sensors[sensorOffset + sen][parentGridCellId] = 1.0;
23431 sensorCellFlag[parentGridCellId][sensorOffset + sen] = true;
23432 }
23433 }
23434 }
23435 } else {
23436 sensors[sensorOffset + sen][gridCellId] = 0.0;
23437 sensorCellFlag[gridCellId][sensorOffset + sen] = false;
23438 }
23439 }
23440
23441 if(m_engineSetup) {
23442 MInt noCutOffBndryIds = Context::propertyLength("cutOffBndryIds", m_solverId);
23443
23444 MFloat xmin = -2.95;
23445 MFloat xmax = 1.65;
23446
23447 xmin = Context::getSolverProperty<MFloat>("cutOffCoordinates", m_solverId, AT_, 0);
23448
23449 if(noCutOffBndryIds > 1) {
23450 xmax = Context::getSolverProperty<MFloat>("cutOffCoordinates", m_solverId, AT_, 6);
23451 }
23452
23453 const MFloat dist1 = 0.15;
23454 const MFloat dist2 = 0.25;
23455
23456 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23457 if(a_coordinate(cellId, 0) < (xmin + dist1) && a_levelSetValuesMb(cellId, 0) > -m_maxLsValue
23458 && a_level(cellId) < this->m_maxSensorRefinementLevel[sen]) {
23459 const MInt gridCellId = grid().tree().solver2grid(cellId);
23460 sensors[sensorOffset + sen][gridCellId] = 1.0;
23461 sensorCellFlag[gridCellId][sensorOffset + sen] = 1;
23462 }
23463
23464 if(a_coordinate(cellId, 0) > (xmax - dist1) && a_levelSetValuesMb(cellId, 0) > -m_maxLsValue
23465 && a_level(cellId) < this->m_maxSensorRefinementLevel[sen]) {
23466 const MInt gridCellId = grid().tree().solver2grid(cellId);
23467 sensors[sensorOffset + sen][gridCellId] = 1.0;
23468 sensorCellFlag[gridCellId][sensorOffset + sen] = 1;
23469 }
23470 }
23471 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23472 if(a_coordinate(cellId, 0) < (xmin + dist2) && a_levelSetValuesMb(cellId, 0) > -m_maxLsValue
23473 && a_level(cellId) < this->m_maxSensorRefinementLevel[sen] - 1) {
23474 const MInt gridCellId = grid().tree().solver2grid(cellId);
23475 sensors[sensorOffset + sen][gridCellId] = 1.0;
23476 sensorCellFlag[gridCellId][sensorOffset + sen] = 1;
23477 }
23478
23479 if(a_coordinate(cellId, 0) > (xmax - dist2) && a_levelSetValuesMb(cellId, 0) > -m_maxLsValue
23480 && a_level(cellId) < this->m_maxSensorRefinementLevel[sen] - 1) {
23481 const MInt gridCellId = grid().tree().solver2grid(cellId);
23482 sensors[sensorOffset + sen][gridCellId] = 1.0;
23483 sensorCellFlag[gridCellId][sensorOffset + sen] = 1;
23484 }
23485 }
23486 }
23487
23488
23489 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
23490}
23491
23499template <MInt nDim_, class SysEqn>
23500void FvCartesianSolverXD<nDim_, SysEqn>::sensorPatch(std::vector<std::vector<MFloat>>& sensors,
23501 std::vector<std::bitset<64>>& sensorCellFlag,
23502 std::vector<MFloat>& sensorWeight, MInt sensorOffset, MInt sen) {
23503 this->patchRefinement(sensors, sensorCellFlag, sensorWeight, sensorOffset, sen);
23504}
23505
23506
23510template <MInt nDim_, class SysEqn>
23512 mDeallocate(m_activeCellIds);
23513 mAlloc(m_activeCellIds, a_noCells(), "m_activeCellIds", -1, AT_);
23514}
23515
23519template <MInt nDim_, class SysEqn>
23521 mDeallocate(m_smallCellIds);
23522 mAlloc(m_smallCellIds, a_noCells(), "m_smallCellIds", -1, AT_);
23523 mDeallocate(m_masterCellIds);
23524 mAlloc(m_masterCellIds, a_noCells(), "m_masterCellIds", -1, AT_);
23525}
23526
23531template <MInt nDim_, class SysEqn>
23533 TRACE();
23534
23535 if(globalTimeStep > 0) {
23536 m_lastAdapTS = globalTimeStep;
23537 }
23538 m_wasAdapted = true;
23539 this->m_adaptationStep = 0;
23540
23541 if(!isActive()) return;
23542
23543 if(globalTimeStep > 0) {
23544 finalizeMpiExchange();
23545 m_fvBndryCnd->resetBndryCommunication();
23546 resetBoundaryCells();
23547 m_fvBndryCnd->resetCutOffFirst();
23548 resetCutOffCells();
23549 resetSurfaces();
23550 resetSponge();
23551 } else {
23552 computeCellVolumes();
23553 }
23554
23555#ifndef NDEBUG
23556 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23557 ASSERT(!a_isBndryGhostCell(cellId), "");
23558 ASSERT(a_bndryId(cellId) == -1,
23559 "Error: bndryCellId " + std::to_string(a_bndryId(cellId)) + " for cell " + std::to_string(cellId));
23560 ASSERT(!a_hasProperty(cellId, SolverCell::IsSplitChild), "");
23561 if(!a_isHalo(cellId) && a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
23562 for(MInt v = 0; v < CV->noVariables; v++) {
23563 ASSERT(!std::isnan(a_variable(cellId, v)), "");
23564 }
23565 }
23566 if(!m_levelSetMb) {
23567 ASSERT(a_cellVolume(cellId) > 0, "");
23568 ASSERT(!a_hasProperty(cellId, SolverCell::IsInactive), "");
23569 }
23570 }
23571#endif
23572
23573 m_adaptationLevel = maxUniformRefinementLevel();
23574 m_maxLevelBeforeAdaptation = maxLevel();
23575
23576 // Azimuthal exchange needs to be reinitialized after adaptation
23577 if(grid().azimuthalPeriodicity()) {
23578 m_azimuthalRecConstSet = false;
23579 m_azimuthalNearBndryInit = false;
23580 }
23581
23582 // STG adaptation
23583 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) {
23584 if(m_zonal) {
23585 for(MInt c = (MInt)m_LESAverageCells.size() - 1; c >= 0; c--) {
23586 MInt cellId = m_LESAverageCells[c];
23587 if(a_isHalo(cellId)) {
23588 m_LESAverageCells.erase(m_LESAverageCells.begin() + c);
23589 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
23590 m_LESVarAverage[var].erase(m_LESVarAverage[var].begin() + c);
23591 }
23592 }
23593 }
23594 }
23595 }
23596}
23597
23598
23603template <MInt nDim_, class SysEqn>
23604void FvCartesianSolverXD<nDim_, SysEqn>::setSensors(std::vector<std::vector<MFloat>>& sensors,
23605 std::vector<MFloat>& sensorWeight,
23606 std::vector<std::bitset<64>>& sensorCellFlag,
23607 std::vector<MInt>& sensorSolverId) {
23608 TRACE();
23609
23610 MInt noSensors = this->m_noInitialSensors;
23611 if(globalTimeStep > 0) noSensors = this->m_noSensors;
23612
23613 const auto sensorOffset = (signed)sensors.size();
23614 ASSERT(sensorOffset == 0 || grid().raw().treeb().noSolvers() > 1, "");
23615 sensorCellFlag.resize(grid().raw().m_noInternalCells, sensorOffset + noSensors);
23616 sensors.resize(sensorOffset + noSensors, vector<MFloat>(grid().raw().m_noInternalCells, F0));
23617 sensorWeight.resize(sensorOffset + noSensors, -1);
23618 sensorSolverId.resize(sensorOffset + noSensors, solverId());
23619 ASSERT(sensorOffset + noSensors < CartesianGrid<nDim>::m_maxNoSensors, "Increase bitset size!");
23620
23621
23622 // If solver is inactive the sensor arrays need to be set to obtain the correct offsets
23623 if(!isActive()) {
23624 for(MInt sen = 0; sen < noSensors; sen++) {
23625 sensorWeight[sensorOffset + sen] = this->m_sensorWeight[sen];
23626 }
23627 return;
23628 }
23629
23630 // necessary for the outside check at the initial adaptation!
23631 if(grid().allowInterfaceRefinement() && globalTimeStep < 0) {
23632 this->identifyBoundaryCells();
23633 }
23634
23635 if(!this->m_adapts) {
23636 ASSERT(!m_levelSetMb, "Currently not possible to leave the FV-Solver adaptation!");
23637 return;
23638 }
23639
23640 // compute slopes at first adaptation loop
23641 if(globalTimeStep > 0 && m_adaptationLevel == maxUniformRefinementLevel()) {
23642 LSReconstructCellCenter();
23643 }
23644
23645 if(domainId() == 0) {
23646 cerr << "Setting " << noSensors << " sensors for fv-Solver adaptation." << endl;
23647 }
23648
23649 for(MInt sen = 0; sen < noSensors; sen++) {
23650 (this->*(this->m_sensorFnPtr[sen]))(sensors, sensorCellFlag, sensorWeight, sensorOffset, sen);
23651
23652 // labels:FV jannik: testcase hack, necessary for 2D_forced_cyl_adaptive and 2D_tandem_cylinders_adaptive
23653 // @ansgar_pls_adapt is this always required for 2D?
23654
23655 IF_CONSTEXPR(nDim == 2) {
23656 ScratchSpace<MFloat> distance(a_noCells(), AT_, "distance");
23657 getBoundaryDistance(distance);
23658
23659 ScratchSpace<MFloat> bbox(m_noDirs, AT_, "bbox");
23660 MFloat* p_bbox = bbox.getPointer();
23661 m_geometry->getBoundingBox(p_bbox);
23662
23663#ifdef _OPENMP
23664#pragma omp parallel for
23665#endif
23666 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23667 if(a_bndryId(cellId) != -1) {
23668 continue;
23669 }
23670 if(a_isBndryGhostCell(cellId)) {
23671 continue;
23672 }
23673 if(c_noChildren(cellId) > 0) {
23674 continue;
23675 }
23676 if(c_isToDelete(cellId)) {
23677 continue;
23678 }
23679
23680 const MInt gridId = this->grid().tree().solver2grid(cellId);
23681
23682 MFloat minDist = c_cellLengthAtLevel(0);
23683 for(MInt i = 0; i < nDim; i++) {
23684 minDist = mMin(minDist, fabs(a_coordinate(cellId, i) - bbox.p[i]));
23685 minDist = mMin(minDist, fabs(a_coordinate(cellId, i) - bbox.p[nDim + i]));
23686 }
23687 MFloat fac = mMin(F1, mMax(F0, (minDist - 5.0) / (10.0 - 5.0)));
23688
23689 const MFloat R0 = 3.0 * m_adaptationDampingDistance;
23690 const MFloat R1 = F1B2 * c_cellLengthAtLevel(0);
23691 const MFloat r = mMax(F0, distance[cellId] - R0) / (R1 - R0);
23692 fac = F1 / (F1 + POW2(F4 * r));
23693
23694 sensors[sensorOffset + sen][gridId] *= fac;
23695 }
23696 }
23697 }
23698
23699 ASSERT(m_freeIndices.empty(), "");
23700 m_freeIndices.clear();
23701
23702 if(!g_multiSolverGrid) {
23703 ASSERT(a_noCells() == c_noCells() && c_noCells() == grid().raw().treeb().size(), "");
23704 }
23705
23706 this->m_adaptationStep++;
23707}
23708
23709
23714template <MInt nDim_, class SysEqn>
23716 TRACE();
23717
23718#ifdef _OPENMP
23719#pragma omp parallel for
23720#endif
23721 for(MInt i = 0; i < grid().raw().noNeighborDomains(); i++) {
23722 for(MInt j = 0; j < grid().raw().noHaloCells(i); j++) {
23723 MInt gridId = grid().raw().m_haloCells[i][j];
23724 MInt l_solverId = this->grid().tree().grid2solver(gridId);
23725 if(l_solverId < 0) {
23726 continue;
23727 }
23728
23729 if(!grid().raw().treeb().solver(gridId, m_solverId)) {
23730 // cerr << "removing a Halo-cell " << endl;
23731 this->removeCellId(l_solverId);
23732 }
23733 }
23734 }
23735
23736 this->compactCells();
23737
23738 if(!g_multiSolverGrid) {
23739 for(MInt gridCellId = 0; gridCellId < grid().raw().treeb().size(); gridCellId++) {
23740 ASSERT(grid().tree().solver2grid(gridCellId) == gridCellId, "");
23741 ASSERT(grid().tree().grid2solver(gridCellId) == gridCellId, "");
23742 }
23743 }
23744
23745 grid().updateOther();
23746 updateDomainInfo(grid().domainId(), grid().noDomains(), grid().mpiComm(), AT_);
23747 this->checkNoHaloLayers();
23748
23749 m_cells.size(c_noCells());
23750 m_totalnosplitchilds = 0;
23751 m_totalnoghostcells = 0;
23752
23753 // updates Halo-Information!
23754 copyGridProperties();
23755
23756 // Nothing further to be done if inactive
23757 if(!isActive()) return;
23758
23759 if(!g_multiSolverGrid) {
23760 ASSERT(a_noCells() == c_noCells() && c_noCells() == grid().raw().treeb().size(), "");
23761 }
23762
23763 m_bndryGhostCellsOffset = a_noCells();
23764
23765 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23766 ASSERT(!a_isBndryGhostCell(cellId), "");
23767 ASSERT(a_bndryId(cellId) >= -1, to_string(a_bndryId(cellId)));
23768 }
23769
23770 // create exchange functions:
23771 if(globalTimeStep < 0) {
23772 setCellProperties();
23773 updateMultiSolverInformation(true);
23774 // initializeMaxLevelExchange();
23775 exchangeDataFV(&a_pvariable(0, 0), PV->noVariables, false, m_rotIndVarsPV);
23776 computeConservativeVariables();
23777 } else {
23778 // correct values on halo cells
23779 exchangeDataFV(&a_variable(0, 0), CV->noVariables, false, m_rotIndVarsCV);
23780 exchangeDataFV(&a_oldVariable(0, 0), CV->noVariables, false, m_rotIndVarsCV);
23781 exchangeProperties();
23782 IF_CONSTEXPR(isDetChem<SysEqn>) correctMajorSpeciesMassFraction();
23783 IF_CONSTEXPR(isDetChem<SysEqn>) computeMeanMolarWeights_CV();
23784 computePrimitiveVariables();
23785 }
23786
23787 if(m_closeGaps) {
23788 exchangeGapInfo();
23789 }
23790
23791 if(m_sensorParticle) {
23792 exchangeData(&a_noPart(
23793 0)); // Since azimuthal window/halos cells do not overlap an meaningful way to exchange this needs to be found!
23794 }
23795
23796 if(m_zonal) {
23797 resetZonalSolverData();
23798 }
23799
23800#if defined _MB_DEBUG_ || !defined NDEBUG
23801 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23802 for(MInt v = 0; v < PV->noVariables; v++) {
23803 if(std::isnan(a_pvariable(cellId, v)) && a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
23804 cerr << "Cell with invalid value 1" << cellId << " " << a_isHalo(cellId) << " "
23805 << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
23806 }
23807 }
23808 }
23809#endif
23810
23811 m_freeIndices.clear();
23812 m_adaptationLevel++;
23813}
23814
23819template <MInt nDim_, class SysEqn>
23821 TRACE();
23822
23823 m_forceAdaptation = false;
23824 m_adaptationSinceLastRestart = true;
23825 m_adaptationSinceLastRestartBackup = true;
23826
23827 // // Nothing further to be done if inactive
23828 if(!isActive()) return;
23829
23830 // Reallocate memory to small and master cell id arrays
23831 reInitSmallCellIdsMemory();
23832
23833 if(globalTimeStep > 0) {
23834 updateMultiSolverInformation(true);
23835
23836 // set isInactive based on levelSet value!
23837 initSolutionStep(0);
23838
23839 // Reallocate solver memory to arrays depending on a_noCells()
23840 reInitActiveCellIdsMemory();
23841
23842 writeListOfActiveFlowCells();
23843
23844 if(!m_levelSetMb) initializeMaxLevelExchange();
23845
23846 updateMaterialNo();
23847
23848 IF_CONSTEXPR(isDetChem<SysEqn>) {
23849 computeMeanMolarWeights_CV();
23850 cutOffBoundaryCondition();
23851 applyBoundaryCondition();
23852 computeConservativeVariables();
23853 scalarLimiter();
23854 }
23855
23856 computePV();
23857
23858 if(grid().azimuthalPeriodicity()) {
23859 cutOffBoundaryCondition(); // Cut-off cells are used for azimuthal reconstruction
23860 setConservativeVarsOnAzimuthalRecCells();
23861 }
23862
23863 exchange();
23864
23865 if(m_zonal) exchangeZonalAverageCells();
23866
23867 cutOffBoundaryCondition();
23868
23869 applyBoundaryCondition();
23870
23871 IF_CONSTEXPR(isDetChem<SysEqn>) { computeConservativeVariables(); }
23872
23873 scalarLimiter();
23874
23875 exchange();
23876
23877 if(m_hasExternalSource) {
23878 resetExternalSources();
23879 }
23880
23881 IF_CONSTEXPR(isDetChem<SysEqn>) { computeMeanMolarWeights_PV(); }
23882
23883#if defined(WITH_CANTERA)
23884 IF_CONSTEXPR(isDetChem<SysEqn>) {
23885 computeGamma();
23886 setTimeStep();
23887 }
23888#endif
23889 }
23890
23891 m_wasAdapted = false;
23892
23893#if defined _MB_DEBUG_ || !defined NDEBUG
23894 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
23895 for(MInt v = 0; v < PV->noVariables; v++) {
23896 if(std::isnan(a_pvariable(cellId, v)) && a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
23897 cerr << "Cell with invalid value 2 " << cellId << " " << a_isHalo(cellId) << " "
23898 << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
23899 }
23900 }
23901 }
23902#endif
23903}
23904
23905
23910template <MInt nDim_, class SysEqn>
23912 TRACE();
23913 ASSERT(isActive(), "solver is not active");
23914
23915 MBool weightOnlyLeafCells = false;
23916 weightOnlyLeafCells =
23917 Context::getSolverProperty<MBool>("weightOnlyLeafCellsFv", m_solverId, AT_, &weightOnlyLeafCells);
23918
23919 const MInt noCellsGrid = grid().raw().treeb().size();
23920 const MInt offset = noCellsGrid * solverId();
23921
23922#ifdef _OPENMP
23923#pragma omp parallel for
23924#endif
23925 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
23926 assertValidGridCellId(cellId);
23927 const MInt gridCellId = grid().tree().solver2grid(cellId);
23928 const MInt id = gridCellId + offset;
23929
23930 solverCellWeight[id] = (c_isLeafCell(cellId) || !weightOnlyLeafCells) ? 1.0 : 0.0;
23931 }
23932}
23933
23938template <MInt nDim_, class SysEqn>
23940 TRACE();
23941
23942 if(m_limitWeights) {
23943 ASSERT(m_weightInactiveCell, "");
23944 MInt count = 1 + m_weightBndryCells + m_weightCutOffCells + m_weightBc1601;
23945 weights[count] = mMax(weights[count], 0.01 * weights[0]);
23946 }
23947}
23948
23949
23950//-----------------------------------------------------------------------------------
23951
23952
23953template <MInt nDim_, class SysEqn>
23955 TRACE();
23956
23957 MInt noFvLoadTypes = 1; // active leaf cells
23958 if(m_weightBndryCells) {
23959 noFvLoadTypes += 1; // boundary cells
23960 }
23961 if(m_weightCutOffCells) {
23962 noFvLoadTypes += 1; // cut-off cells
23963 }
23964 if(m_weightBc1601) {
23965 noFvLoadTypes += 1; // bc1601 cells
23966 }
23967 if(m_weightInactiveCell) {
23968 noFvLoadTypes += 1; // memory weight
23969 }
23970 if(m_weightNearBndryCells) {
23971 noFvLoadTypes += 1; // near boundary cells
23972 }
23973 if(m_weightLvlJumps) {
23974 noFvLoadTypes += 1; // cells at lvl-jump
23975 }
23976 if(m_weightSmallCells) {
23977 noFvLoadTypes += 1; // small cells
23978 }
23979
23980 return noFvLoadTypes;
23981}
23982
23983
23985template <MInt nDim_, class SysEqn>
23986void FvCartesianSolverXD<nDim_, SysEqn>::getDefaultWeights(MFloat* weights, std::vector<MString>& names) const {
23987 TRACE();
23988
23989 weights[0] = 1.0;
23990 names[0] = "fv_leaf_cell";
23991 MInt count = 1;
23992
23993 if(m_weightBndryCells) {
23994 weights[count] = 5.0;
23995 names[count] = "fv_bndry_cell";
23996 count++;
23997 }
23998
23999 if(m_weightCutOffCells) {
24000 weights[count] = 5.0;
24001 names[count] = "fv_cutoff_cell";
24002 count++;
24003 }
24004
24005 if(m_weightBc1601) {
24006 weights[count] = 10.0;
24007 names[count] = "fv_bc1601";
24008 count++;
24009 }
24010
24011 if(m_weightInactiveCell) {
24012 weights[count] = 0.1;
24013 names[count] = "fv_inactive_cell";
24014 count++;
24015 }
24016
24017 if(m_weightNearBndryCells) {
24018 weights[count] = 2.0;
24019 names[count] = "fv_nearBndry_cell";
24020 count++;
24021 }
24022 if(m_weightLvlJumps) {
24023 weights[count] = 1.5;
24024 names[count] = "fv_lvlJump_cell";
24025 count++;
24026 }
24027 if(m_weightSmallCells) {
24028 weights[count] = 1.0;
24029 names[count] = "fv_smallCell";
24030 count++;
24031 }
24032
24033 if(noLoadTypes() != count) {
24034 mTerm(1, "Count does not match noLoadTypes.");
24035 }
24036}
24037
24038
24044template <MInt nDim_, class SysEqn>
24046 TRACE();
24047
24048 // reset
24049 std::fill_n(&loadQuantities[0], noLoadTypes(), 0);
24050
24051 // Nothing to do if solver is not active
24052 if(!grid().isActive()) {
24053 return;
24054 }
24055
24056 // Count the number of leaf cells/boundary cells and store as load quantities
24057 MInt noLeafCells = 0;
24058 MInt noBndryCells = 0;
24059 MInt noNearBndryCells = 0;
24060 MInt totalNoCutOffCells = 0;
24061 MInt noBc1601Cells = 0;
24062 MInt noLvlJumpCells = 0;
24063
24064 for(MInt cellId = 0; cellId < grid().noInternalCells(); cellId++) {
24065 if(c_isLeafCell(cellId) && !a_hasProperty(cellId, SolverCell::IsInactive)) {
24066 noLeafCells++;
24067 }
24068 if(c_isLeafCell(cellId)) {
24069 MBool atLvlJump = false;
24070 for(MInt dir = 0; dir < m_noDirs; dir++) {
24071 if(c_neighborId(cellId, dir, false) < 0 && c_parentId(cellId) > -1
24072 && c_neighborId(c_parentId(cellId), dir, false) > -1) {
24073 atLvlJump = true;
24074 break;
24075 }
24076 if(c_neighborId(cellId, dir, false) > -1 && !c_isLeafCell(c_neighborId(cellId, dir, false))) {
24077 atLvlJump = true;
24078 break;
24079 }
24080 }
24081 if(atLvlJump) {
24082 noLvlJumpCells++;
24083 }
24084 }
24085
24086 const MInt bndryId = a_bndryId(cellId);
24087 if(bndryId > -1 && c_isLeafCell(cellId)) {
24088 noBndryCells++;
24089 }
24090 if(a_hasProperty(cellId, SolverCell::NearWall)) {
24091 noNearBndryCells++;
24092 }
24093 }
24094
24095 for(MInt bc = 0; bc < m_fvBndryCnd->m_noCutOffBndryCndIds; bc++) {
24096 MInt noCutOffCells = 0;
24097
24098 const MInt bcSize = m_fvBndryCnd->m_sortedCutOffCells[bc]->size();
24099 for(MInt i = 0; i < bcSize; i++) {
24100 const MInt cellId = m_fvBndryCnd->m_sortedCutOffCells[bc]->a[i];
24101 if(!a_isHalo(cellId)) {
24102 noCutOffCells++;
24103 }
24104 }
24105
24106 if(m_weightBc1601 && bc == m_fvBndryCnd->m_bc1601_bcId) {
24107 // If enabled, treat random eddy inflow bc cells separately
24108 noBc1601Cells = noCutOffCells;
24109 } else {
24110 // Sum up all other cut-off cells
24111 totalNoCutOffCells += noCutOffCells;
24112 }
24113 }
24114
24115 loadQuantities[0] = noLeafCells;
24116 MInt count = 1;
24117
24118 // Number of boundary cells if enabled
24119 if(m_weightBndryCells) {
24120 loadQuantities[count] = noBndryCells;
24121 count += 1;
24122 }
24123 if(m_weightCutOffCells) {
24124 loadQuantities[count] = totalNoCutOffCells;
24125 count += 1;
24126 }
24127 if(m_weightBc1601) {
24128 loadQuantities[count] = noBc1601Cells;
24129 count += 1;
24130 }
24131 if(m_weightInactiveCell) {
24132 loadQuantities[count] = grid().noInternalCells();
24133 count += 1;
24134 }
24135 if(m_weightNearBndryCells) {
24136 loadQuantities[count] = noNearBndryCells;
24137 count += 1;
24138 }
24139 if(m_weightLvlJumps) {
24140 loadQuantities[count] = noLvlJumpCells;
24141 count += 1;
24142 }
24143 if(m_weightSmallCells) {
24144 loadQuantities[count] = m_fvBndryCnd->m_smallCutCells.size();
24145 count += 1;
24146 }
24147}
24148
24149
24157template <MInt nDim_, class SysEqn>
24158MFloat FvCartesianSolverXD<nDim_, SysEqn>::getCellLoad(const MInt gridCellId, const MFloat* const weights) const {
24159 TRACE();
24160 ASSERT(isActive(), "solver is not active");
24161
24162 // Convert to solver cell id and check
24163 const MInt cellId = grid().tree().grid2solver(gridCellId);
24164 if(cellId < 0) {
24165 return 0;
24166 }
24167
24168 if(cellId < 0 || cellId >= grid().noInternalCells()) {
24169 mTerm(1, "The given cell id is invalid.");
24170 }
24171
24172 // Default cell load
24173 MFloat cellLoad = 0.0;
24174
24175
24176 if(c_isLeafCell(cellId) && !a_hasProperty(cellId, SolverCell::IsInactive)) {
24177 cellLoad = weights[0];
24178 }
24179 MInt count = 1;
24180
24181 // Add load for boundary/cut-off cells
24182 if(m_weightBndryCells) {
24183 const MInt bndryId = a_bndryId(cellId);
24184 if(bndryId > -1 && c_isLeafCell(cellId)) {
24185 cellLoad += weights[count];
24186 }
24187 count += 1;
24188 }
24189
24190 if(m_weightCutOffCells) {
24191 for(MInt bc = 0; bc < m_fvBndryCnd->m_noCutOffBndryCndIds; bc++) {
24192 if(m_weightBc1601 && bc == m_fvBndryCnd->m_bc1601_bcId) continue; // skip bc1601 if cells are weighted separately
24193
24194 const MInt bcSize = m_fvBndryCnd->m_sortedCutOffCells[bc]->size();
24195 for(MInt i = 0; i < bcSize; i++) {
24196 if(cellId == m_fvBndryCnd->m_sortedCutOffCells[bc]->a[i]) {
24197 cellLoad += weights[count + 1];
24198 }
24199 }
24200 }
24201 count += 1;
24202 }
24203
24204 // Add load for bc1601 cells (random eddy inflow)
24205 if(m_weightBc1601) {
24206 const MInt bc = m_fvBndryCnd->m_bc1601_bcId; // -1 if non-existent
24207 const MInt bcSize = (bc < 0) ? 0 : m_fvBndryCnd->m_sortedCutOffCells[bc]->size();
24208 for(MInt i = 0; i < bcSize; i++) {
24209 if(cellId == m_fvBndryCnd->m_sortedCutOffCells[bc]->a[i]) {
24210 cellLoad += weights[count];
24211 }
24212 }
24213 count += 1;
24214 }
24215 if(m_weightInactiveCell) {
24216 if(cellLoad < MFloatEps) {
24217 cellLoad = weights[count];
24218 }
24219 count += 1;
24220 }
24221
24222 if(m_weightNearBndryCells) {
24223 if(a_hasProperty(cellId, SolverCell::NearWall)) {
24224 cellLoad += weights[count];
24225 }
24226 }
24227
24228 if(m_weightLvlJumps) {
24229 MBool atLvlJump = false;
24230 if(c_isLeafCell(cellId)) {
24231 for(MInt dir = 0; dir < m_noDirs; dir++) {
24232 if(c_neighborId(cellId, dir, false) < 0 && c_parentId(cellId) > -1
24233 && c_neighborId(c_parentId(cellId), dir, false) > -1) {
24234 atLvlJump = true;
24235 break;
24236 }
24237 if(c_neighborId(cellId, dir, false) > -1 && !c_isLeafCell(c_neighborId(cellId, dir, false))) {
24238 atLvlJump = true;
24239 break;
24240 }
24241 }
24242 }
24243 if(atLvlJump) {
24244 cellLoad += weights[count];
24245 }
24246 }
24247
24248 if(m_weightSmallCells) {
24249 if(a_cellVolume(cellId) / grid().gridCellVolume(maxLevel()) < m_fvBndryCnd->m_volumeLimitWall) {
24250 cellLoad += weights[count];
24251 }
24252 count += 1;
24253 }
24254
24255 return cellLoad;
24256}
24257
24258
24263template <MInt nDim_, class SysEqn>
24265 finalizeMpiExchange();
24266
24267 // apply and reset, as external sources are not exchanged during balance!
24268 /*
24269 if(m_hasExternalSource && m_levelSetMb) {
24270 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
24271 if(!a_hasProperty(cellId, SolverCell::IsActive)) continue;
24272 for(MInt var = 0; var < CV->noVariables; var++) {
24273 a_rightHandSide(cellId, var) -= a_externalSource(cellId, var);
24274 }
24275 }
24276 }
24277 */
24278 if(m_hasExternalSource) {
24279 resetExternalSources();
24280 advanceExternalSource();
24281 }
24282}
24283
24284
24289template <MInt nDim_, class SysEqn>
24291 TRACE();
24292
24293 for(MInt c = 0; c < m_noCellsInsideSpongeLayer; c++) {
24294 // const MInt cellId = m_cellsInsideSpongeLayer[ c ];
24295 // a_hasProperty(cellId, SolverCell::IsInSpongeLayer) = false;
24296 // a_spongeFactor(cellId) = F0;
24297 m_cellsInsideSpongeLayer[c] = -1;
24298 }
24299 m_noCellsInsideSpongeLayer = 0;
24300}
24301
24302//-----------------------------------------------------------------------------------
24303
24304
24309template <MInt nDim_, class SysEqn>
24310ATTRIBUTES1(ATTRIBUTE_NO_AUTOVEC)
24312 TRACE();
24313
24314 if(m_fvBndryCnd->m_cellCoordinatesCorrected) {
24315 m_fvBndryCnd->recorrectCellCoordinates();
24316 }
24317
24318 for(MInt cellId = 0; cellId < maxNoGridCells(); cellId++) {
24319 a_bndryId(cellId) = -1;
24320 for(MInt v = 0; v < FV->noVariables; v++) {
24321 a_rightHandSide(cellId, v) = F0;
24322 }
24323 for(MInt v = 0; v < PV->noVariables; v++) {
24324 a_pvariable(cellId, v) = sqrt(-F1);
24325 }
24326 a_cellVolume(cellId) = F0;
24327 a_FcellVolume(cellId) = sqrt(-F1);
24328 }
24329
24330 if(grid().azimuthalPeriodicity()) {
24331 m_noAzimuthalReconstNghbrs.clear();
24332 m_azimuthalReconstNghbrIds.clear();
24333 m_azimuthalRecConsts.clear();
24334 // m_azimuthalCutRecCoord.clear();
24335 // m_azimuthalBndrySide.clear();
24336 // m_azimuthalWindowMap.clear();
24337 // m_azimuthalCartRecCoord.clear();
24338 }
24339
24340 resetSurfaces();
24341
24342 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
24343 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
24344 a_bndryId(cellId) = -1;
24345 a_hasProperty(cellId, SolverCell::IsSplitCell) = false;
24346 a_hasProperty(cellId, SolverCell::IsSplitChild) = false;
24347 a_hasProperty(cellId, SolverCell::HasSplitFace) = false;
24348 a_hasProperty(cellId, SolverCell::IsTempLinked) = false;
24349 a_hasProperty(cellId, SolverCell::IsMovingBnd) = false;
24350 }
24351 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_maxNoBndryCells; bndryId++) {
24352 std::vector<MInt>().swap(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds);
24353 std::vector<MFloat>().swap(m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst);
24354 std::vector<MFloat>().swap(m_fvBndryCnd->m_bndryCell[bndryId].m_cellDerivRecConst);
24355 std::vector<MFloat>().swap(m_fvBndryCnd->m_bndryCell[bndryId].m_faceVertices);
24356 for(MUint i = 0; i < m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream.size(); i++) {
24357 m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream[i].resize(0);
24358 }
24359 m_fvBndryCnd->m_bndryCell[bndryId].m_faceStream.resize(0);
24360 for(MInt srfc = 0; srfc < FvBndryCell<nDim, SysEqn>::m_maxNoSurfaces; srfc++) {
24361 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_noCutPoints = 0;
24362 std::vector<MFloat>().swap(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst);
24363 for(MInt v = 0; v < PV->noVariables; v++) {
24364 m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[v] = BC_UNSET;
24365 }
24366 for(MInt i = 0; i < nDim; i++) {
24367 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_srfcId[i] = -1;
24368 }
24369 }
24370 m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId = -1;
24371 // m_fvBndryCnd->deleteBndryCell( bndryId );
24372 }
24373
24374 m_fvBndryCnd->m_bndryCells->resetSize(0);
24375 std::vector<MInt>().swap(m_fvBndryCnd->m_smallCutCells);
24376
24377 resetCutOffCells();
24378 m_fvBndryCnd->resetCutOffFirst();
24379
24380 m_fvBndryCnd->resetBndryCommunication();
24381
24382 m_bndryGhostCellsOffset = 0;
24383 m_bndrySurfacesOffset = 0;
24384 m_totalnosplitchilds = 0;
24385 m_totalnoghostcells = 0;
24386
24387 // Reset all cells (Note: this invalidates the collector internal data structures)
24388 m_cells.clear();
24389 ASSERT(m_cells.size() == 0, "");
24390 m_reconstructionDataSize = 0;
24391
24392 IF_CONSTEXPR(isDetChem<SysEqn>) m_dampFactor.clear();
24393
24394 // Note: dont use noNeighborDomains() since it might contain a different value after load balancing the grid.
24395 if(!m_fvBndryCnd->m_cellMerging && m_fvBndryCnd->m_nearBoundaryHaloCells != nullptr) {
24396 for(MUint i = 0; i < m_fvBndryCnd->m_nearBoundaryHaloCells->size(); i++) {
24397 std::vector<MInt>().swap(m_fvBndryCnd->m_nearBoundaryHaloCells[i]);
24398 std::vector<MInt>().swap(m_fvBndryCnd->m_nearBoundaryWindowCells[i]);
24399 }
24400 }
24401}
24402
24403
24404// --------------------------------------------------------------------------------------
24405
24406
24411template <MInt nDim_, class SysEqn>
24412void FvCartesianSolverXD<nDim_, SysEqn>::balance(const MInt* const noCellsToReceiveByDomain,
24413 const MInt* const noCellsToSendByDomain,
24414 const MInt* const sortedCellId, const MInt oldNoCells) {
24415 // TODO labels:FV,DLB balance is still needed for FV-MB DLB!
24416 /* mTerm(1, "balance() is deprecated, use split balancing balancePre/Post instead!"); */
24417 TRACE();
24418 NEW_TIMER_GROUP(t_initTimer, "balance solver");
24419 NEW_TIMER(t_timertotal, "balance solver", t_initTimer);
24420 NEW_SUB_TIMER(t_variables, "variables", t_timertotal);
24421 NEW_SUB_TIMER(t_communicator, "communicator", t_timertotal);
24422 NEW_SUB_TIMER(t_reinit, "reinit", t_timertotal);
24423
24424 RECORD_TIMER_START(t_timertotal);
24425 RECORD_TIMER_START(t_variables);
24426
24427 // write solver-data into grid-structure arrays for the load-balancing
24428 MFloatScratchSpace variablesBalance(oldNoCells, CV->noVariables, FUN_, "variablesBalance");
24429 MFloatScratchSpace volumeBalance(oldNoCells, FUN_, "volumeBalance");
24430
24431 variablesBalance.fill(-1);
24432 volumeBalance.fill(-1);
24433
24434
24435 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
24436 MInt gridCellId = grid().tree().solver2grid(cellId);
24437 for(MInt variable = 0; variable < CV->noVariables; variable++) {
24438 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
24439 ASSERT(!std::isnan(a_variable(cellId, variable)), "");
24440 }
24441 variablesBalance(gridCellId, variable) = a_variable(cellId, variable);
24442 }
24443 volumeBalance(gridCellId) = a_cellVolume(cellId);
24444 }
24445
24446
24447 // update of the proxy
24448 grid().update();
24449
24450 // Just reset parallelization information if solver is not active
24451 // NOTE: inactive ranks not supported here since the data sizes etc are not determined for the
24452 // solver but for the whole grid -> use balancePre/Post instead!
24453 if(!grid().isActive()) {
24454 updateDomainInfo(-1, -1, MPI_COMM_NULL, AT_);
24455 mTerm(1, "fixme: inactive ranks not supported in balance(); use balancePre/Post instead!");
24456 return;
24457 }
24458
24459 // Set new domain info for solver
24460 updateDomainInfo(grid().domainId(), grid().noDomains(), grid().mpiComm(), AT_);
24461
24462 // This is only working of the same domains as in the grid are used!
24463 ASSERT(domainId() == grid().raw().domainId(), "");
24464 ASSERT(noDomains() == grid().raw().noDomains(), "");
24465
24466 // data-to be saved during the balancing:
24467 //-a_variables
24468 // a_cellVolume
24469
24470 MFloatScratchSpace variables(noCellsToReceiveByDomain[noDomains()], CV->noVariables, FUN_, "variables");
24471 MFloatScratchSpace cellVolumes(noCellsToReceiveByDomain[noDomains()], FUN_, "cellVolumes");
24472
24473 variables.fill(-1.0);
24474 cellVolumes.fill(-1.0);
24475
24476 maia::mpi::communicateData(&variablesBalance[0], oldNoCells, sortedCellId, noDomains(), domainId(), mpiComm(),
24477 noCellsToSendByDomain, noCellsToReceiveByDomain, CV->noVariables, &variables[0]);
24478 maia::mpi::communicateData(&volumeBalance[0], oldNoCells, sortedCellId, noDomains(), domainId(), mpiComm(),
24479 noCellsToSendByDomain, noCellsToReceiveByDomain, 1, &cellVolumes[0]);
24480
24481 // Reset cell, surface, boundary cell data and deallocate halo/window cell arrays, and reset cell
24482 // collector
24483 resetSolverFull();
24484
24485 // Reallocate communication data structures
24486 updateMultiSolverInformation(true);
24487
24488 ASSERT(m_cells.size() == 0, "");
24489
24490 // Iterate over all received grid cells
24491 for(MInt gridCellId = 0; gridCellId < noCellsToReceiveByDomain[noDomains()]; gridCellId++) {
24492 const MInt cellId = m_cells.size();
24493
24494 if(!grid().raw().treeb().solver(gridCellId, m_solverId)) continue;
24495
24496 // this needs to be appended before performing any checks
24497 m_cells.append();
24498
24499 if(!grid().raw().bitOffset()) {
24500 ASSERT(grid().tree().solver2grid(cellId) == gridCellId, to_string(cellId) + " " + to_string(gridCellId));
24501 }
24502
24503 if(grid().domainOffset(domainId()) + (MLong)cellId != c_globalId(cellId)) {
24504 mTerm(1, "Global id mismatch: o" + std::to_string(grid().domainOffset(domainId())) + " + c"
24505 + std::to_string(cellId) + " != g" + std::to_string(c_globalId(cellId)));
24506 }
24507
24508 a_resetPropertiesSolver(cellId);
24509
24510 // Set solver data
24511 for(MInt v = 0; v < CV->noVariables; v++) {
24512 a_variable(cellId, v) = variables(gridCellId, v);
24513 a_oldVariable(cellId, v) = a_variable(cellId, v);
24514 }
24515 setPrimitiveVariables(cellId);
24516 a_cellVolume(cellId) = cellVolumes(gridCellId);
24517 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
24518 }
24519
24520
24521 // append the halo-cells;
24522 m_cells.append(c_noCells() - m_cells.size());
24523
24524 m_totalnoghostcells = 0;
24525 m_totalnosplitchilds = 0;
24526
24527 ASSERT(m_cells.size() == c_noCells() && c_noCells() == a_noCells(), "");
24528
24529 m_bndryGhostCellsOffset = a_noCells();
24530 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
24531 a_bndryId(cellId) = -1;
24532 a_isBndryGhostCell(cellId) = false;
24533 a_hasProperty(cellId, SolverCell::IsSplitChild) = false;
24534 }
24535
24536 copyGridProperties();
24537
24538 // this can only be done, after the halo-cells have been added above!
24539 this->checkNoHaloLayers();
24540
24541 RECORD_TIMER_STOP(t_variables);
24542 RECORD_TIMER_START(t_communicator);
24543
24544 mDeallocate(m_maxLevelHaloCells);
24545 mDeallocate(m_maxLevelWindowCells);
24546 mDeallocate(m_noMaxLevelHaloCells);
24547 mDeallocate(m_noMaxLevelWindowCells);
24548 mDeallocate(m_sendBuffers);
24549 mDeallocate(m_receiveBuffers);
24550 mDeallocate(m_mpi_request);
24551 if(m_nonBlockingComm) {
24552 mDeallocate(m_sendBuffersNoBlocking);
24553 mDeallocate(m_receiveBuffersNoBlocking);
24554 mDeallocate(m_mpi_receiveRequest);
24555 mDeallocate(m_mpi_sendRequest);
24556 }
24557
24558 allocateCommunicationMemory();
24559
24560 if(!m_fvBndryCnd->m_cellMerging) {
24561 mDeallocate(m_fvBndryCnd->m_nearBoundaryWindowCells);
24562 mDeallocate(m_fvBndryCnd->m_nearBoundaryHaloCells);
24563 mAlloc(m_fvBndryCnd->m_nearBoundaryWindowCells, noNeighborDomains(), "m_nearBoundaryWindowCells", AT_);
24564 mAlloc(m_fvBndryCnd->m_nearBoundaryHaloCells, noNeighborDomains(), "m_nearBoundaryHaloCells", AT_);
24565 }
24566
24567 std::vector<MInt>().swap(m_splitCells);
24568 std::vector<std::vector<MInt>>().swap(m_splitChilds);
24569 std::map<MInt, MInt>().swap(m_splitChildToSplitCell);
24570 m_totalnosplitchilds = 0;
24571
24572 if(this->m_adaptation) {
24573 for(MInt i = 0; i < maxNoGridCells(); i++)
24574 m_recalcIds[i] = i;
24575 }
24576
24577 // set variables for halo cells:
24578 exchangeData(&a_variable(0, 0), CV->noVariables);
24579 exchangeData(&a_cellVolume(0), 1);
24580 if(grid().azimuthalPeriodicity()) {
24581 mTerm(1, AT_, "Add azimuthal periodicity, c.f. fvMb!");
24582 }
24583
24584 for(MInt cellId = noInternalCells(); cellId < a_noCells(); cellId++) {
24585 setPrimitiveVariables(cellId);
24586 for(MInt v = 0; v < CV->noVariables; v++) {
24587 a_oldVariable(cellId, v) = a_variable(cellId, v);
24588 }
24589 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
24590 }
24591
24592 copyGridProperties();
24593
24594 IF_CONSTEXPR(isDetChem<SysEqn>) if(m_heatReleaseDamp) initHeatReleaseDamp();
24595
24596 RECORD_TIMER_STOP(t_communicator);
24597 RECORD_TIMER_START(t_reinit);
24598
24599 // If grid adaptation is used make sure that a grid file is written with the next restart file
24600 // since the cells will be sorted during balacing, while the old grid after adaptation will
24601 // contain the unsorted grid cells
24602 if(this->m_adaptation) {
24603 m_adaptationSinceLastRestart = true;
24604 m_adaptationSinceLastRestartBackup = true;
24605 }
24606
24607 RECORD_TIMER_STOP(t_reinit);
24608 RECORD_TIMER_STOP(t_timertotal);
24609 DISPLAY_TIMER(t_timertotal);
24610}
24611
24612//-------------------------------------------------------------------------------------------
24613
24614
24618template <MInt nDim_, class SysEqn>
24620 TRACE();
24621
24622 // Note: every function that allocates persistent memory should first deallocate that memory, for
24623 // this to work initialize all pointers with nullptr in the class definition
24624
24625 // Set reinitialization stage
24626 m_loadBalancingReinitStage = 0;
24627
24628 // Store currently used memory
24629 /* const MLong previouslyAllocated = allocatedBytes(); */
24630
24631 // Update the grid proxy for this solver
24632 grid().update();
24633
24634 if(!grid().isActive()) {
24635 // Reset parallelization information if solver is not active
24636 updateDomainInfo(-1, -1, MPI_COMM_NULL, AT_);
24637 } else {
24638 // Set new domain info for solver
24639 updateDomainInfo(grid().domainId(), grid().noDomains(), grid().mpiComm(), AT_);
24640 }
24641
24642 if(m_zonal) {
24643 m_wasBalancedZonal = true;
24644 }
24645
24646 // Reset cell, surface, boundary cell data and deallocate halo/window cell arrays
24647 resetSolverFull();
24648
24649 // Reallocate communication data structures
24650 // only requires noNeighborDomains information, which is set in the proxy
24651 updateMultiSolverInformation(true);
24652
24653 // Return if solver is not active
24654 if(!grid().isActive()) {
24655 return;
24656 }
24657
24658 // check for empty cell collector
24659 ASSERT(m_cells.size() == 0, "");
24660
24661 // Resize cell collector to internal cells
24662 m_cells.append(grid().noInternalCells());
24663
24664 // Check that global ids are sorted
24665 for(MInt cellId = 0; cellId < grid().noInternalCells(); cellId++) {
24666 if(grid().domainOffset(domainId()) + (MLong)cellId != c_globalId(cellId)) {
24667 mTerm(1, "Global id mismatch.");
24668 }
24669 // TODO labels:FV,DLB communicate cell volumes necessary? (see balance())
24670 /* a_cellVolume(cellId) = cellVolumes(gridCellId); */
24671 /* a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(gridCellId)); */
24672 }
24673
24674 // TODO labels:FV,DLB reinit postprocessing?
24675
24676 // allocate general FvCartesianSolver memory
24677 // TODO labels:FV,DLB most memory sizes are constant, but some are dependent on m_noCells/m_noInternalCells
24678 // allocateAndInitSolverMemory();
24679}
24680
24681
24685template <MInt nDim_, class SysEqn>
24687 TRACE();
24688
24689 if(grid().azimuthalPeriodicity()) {
24690 mTerm(1, AT_,
24691 "This type of balance is not supported for azimuthal periodicity. Add periodic exchange of conservative "
24692 "variables");
24693 }
24694
24695 m_loadBalancingReinitStage = 1;
24696
24697 // append the halo-cells
24698 m_cells.append(c_noCells() - m_cells.size());
24699
24700 copyGridProperties();
24701
24702 m_totalnoghostcells = 0;
24703 m_totalnosplitchilds = 0;
24704 ASSERT(m_cells.size() == c_noCells() && c_noCells() == a_noCells(), "");
24705
24706 // Nothing to do if solver is not active
24707 if(!grid().isActive()) {
24708 return;
24709 }
24710
24711 m_bndryGhostCellsOffset = a_noCells();
24712 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
24713 a_bndryId(cellId) = -1;
24714 a_isBndryGhostCell(cellId) = false;
24715 a_hasProperty(cellId, SolverCell::IsSplitChild) = false;
24716 }
24717
24718 // this can only be done, after the halo property has been set above
24719 this->checkNoHaloLayers();
24720
24721 // ### from c'tor ###
24722 // compute min and max coordinates in the grid
24723 computeDomainAndSpongeDimensions();
24724 // ###
24725
24726 allocateCommunicationMemory();
24727
24728 if(!m_fvBndryCnd->m_cellMerging) {
24729 mDeallocate(m_fvBndryCnd->m_nearBoundaryWindowCells);
24730 mDeallocate(m_fvBndryCnd->m_nearBoundaryHaloCells);
24731 mAlloc(m_fvBndryCnd->m_nearBoundaryWindowCells, noNeighborDomains(), "m_nearBoundaryWindowCells", AT_);
24732 mAlloc(m_fvBndryCnd->m_nearBoundaryHaloCells, noNeighborDomains(), "m_nearBoundaryHaloCells", AT_);
24733 }
24734
24735 m_splitCells.clear();
24736 m_splitChilds.clear();
24737 m_splitChildToSplitCell.clear();
24738 m_totalnosplitchilds = 0;
24739
24740 // during the balance cells are sorted again
24741 if(this->m_adaptation) {
24742 for(MInt i = 0; i < maxNoGridCells(); i++)
24743 m_recalcIds[i] = i;
24744 }
24745
24746 exchangeData(&a_variable(0, 0), CV->noVariables);
24747 if constexpr(hasAV) exchangeData(&a_avariable(0, 0), AV->noVariables);
24748 exchangeData(&a_cellVolume(0), 1);
24749 if(grid().azimuthalPeriodicity()) {
24750 mTerm(1, AT_, "Add azimuthal periodicity, c.f. fvMb!");
24751 }
24752
24753 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
24754 setPrimitiveVariables(cellId);
24755 for(MInt v = 0; v < CV->noVariables; v++) {
24756 a_oldVariable(cellId, v) = a_variable(cellId, v);
24757 }
24758 a_FcellVolume(cellId) = F1 / mMax(m_volumeThreshold, a_cellVolume(cellId));
24759 }
24760
24761 copyGridProperties();
24762
24763 if(m_zonal) {
24764 determineLESAverageCells();
24765 resetZonalLESAverage();
24766 resetZonalSolverData();
24767 }
24768
24769 // If grid adaptation is used make sure that a grid file is written with the next restart file
24770 // since the cells will be sorted during balacing, while the old grid after adaptation will
24771 // contain the unsorted grid cells
24772 if(this->m_adaptation) {
24773 m_adaptationSinceLastRestart = true;
24774 m_adaptationSinceLastRestartBackup = true;
24775 }
24776
24777 m_loadBalancingReinitStage = 2;
24778
24779 // check finalizeBalance for any of this cases!
24780 if(m_combustion && !m_LSSolver) {
24781 mTerm(1, "balancePost untested case with combustion");
24782 }
24783 if constexpr(isEEGas<SysEqn>) {
24784 if(m_EEGas.gasSource != 0) {
24785 m_EEGas.gasSourceCells.clear();
24786 initSourceCells();
24787 }
24788 }
24789}
24790
24791
24794template <MInt nDim_, class SysEqn>
24796 TRACE();
24797
24798 ASSERT(m_cells.size() == c_noCells(), "");
24799
24800 // Nothing to do if solver is not active
24801 if(!grid().isActive()) {
24802 return;
24803 }
24804
24805 if(m_closeGaps) {
24806 exchangeGapInfo();
24807 }
24808
24809 // nothing to be done in the initial adaptation
24810 if(globalTimeStep < 0) return;
24811
24812 // Reallocate memory to small and master cell id arrays
24813 reInitSmallCellIdsMemory();
24814
24815 // TODO labels:FV,DLB move the following into a separate function to be called at initialization and after DLB
24816 initSolutionStep(1);
24817 // Reallocate solver memory to arrays depending on a_noCells()
24818 reInitActiveCellIdsMemory();
24819 writeListOfActiveFlowCells();
24820
24821 if(!m_levelSetMb) initializeMaxLevelExchange();
24822
24823 // TODO labels:DLB already performed in initSolutionStep() TEST!
24824 updateMaterialNo();
24825
24826 // To reset communicators in BndryCnd
24827 initCutOffBoundaryCondition();
24828
24829 IF_CONSTEXPR(isDetChem<SysEqn>) {
24830 cutOffBoundaryCondition();
24831 applyBoundaryCondition();
24832 computeMeanMolarWeights_CV();
24833 computeConservativeVariables();
24834 computeMeanMolarWeights_CV();
24835 }
24836
24837 computePV();
24838
24839 // initialize the runge kutta integration scheme
24840 // TODO labels:FV,DLB fix this for levelSetMb, initializeRungeKutta is overloaded
24841 // and some incorrect stuff is done there!
24842 if(!m_levelSetMb) {
24843 initializeRungeKutta();
24844 }
24845
24846 // Note: time step is communicated to previously inactive ranks
24847
24848 // periodic exchange (azimuthal periodicity concept)
24849 if(m_periodicCells == 3) {
24850 mTerm(1, "balancePost untested case with azimuthal periodicity");
24851 exchange();
24852 exchangePeriodic();
24853 }
24854
24855 // exchange(); // Not required since already done via exchangeData() above?
24856 /*
24857 IF_CONSTEXPR(!isDetChem<SysEqn>) {
24858 cutOffBoundaryCondition();
24859 applyBoundaryCondition();
24860 }*/
24861
24862 if(m_zonal) {
24863 m_wasBalancedZonal = false;
24864 }
24865
24866 if(grid().azimuthalPeriodicity()) {
24867 exchange();
24868 }
24869
24870 cutOffBoundaryCondition();
24871 applyBoundaryCondition();
24872
24873 // After balance set conservative variables of the cells used for azimuthal (Relevant at cut-off)
24874 if(grid().azimuthalPeriodicity()) {
24875 setConservativeVarsOnAzimuthalRecCells();
24876 }
24877
24878 // computeConservativeVariables();
24879
24880 scalarLimiter();
24881
24882 if(calcSlopesAfterStep()) {
24883 LSReconstructCellCenter();
24884 m_fvBndryCnd->copySlopesToSmallCells();
24885 m_fvBndryCnd->updateGhostCellSlopesInviscid();
24886 m_fvBndryCnd->updateCutOffSlopesInviscid();
24887 }
24888
24889 // Note: from initSolver()
24890 if(m_combustion && !m_LSSolver) {
24891 setCellProperties();
24892 computePrimitiveVariablesCoarseGrid();
24893 computeConservativeVariables();
24894 }
24895
24896 // Note: from initSolver()
24897 if(m_levelSet && !m_combustion && !m_LSSolver) {
24898 setCellProperties();
24899 }
24900
24901 m_loadBalancingReinitStage = -1;
24902}
24903
24904
24909template <MInt nDim_, class SysEqn>
24911 std::vector<std::pair<MString, MInt>>& domainInfo) {
24912 TRACE();
24913
24914 const MString namePrefix = "b" + std::to_string(solverId()) + "_";
24915
24916 const MInt noCells = (isActive()) ? grid().noInternalCells() : 0;
24917 MInt noLeafCells = 0;
24918 MInt noActiveLeafCells = 0;
24919 MInt noCutOffCells = 0;
24920 MInt noBc1601Cells = 0;
24921 MInt noNearBndryCells = 0;
24922 MInt noBndrycells = 0;
24923 MInt noLvlJumpCells = 0;
24924
24925 if(isActive()) {
24926 for(MInt cellId = 0; cellId < grid().noInternalCells(); cellId++) {
24927 if(c_isLeafCell(cellId)) noLeafCells++;
24928 if(c_isLeafCell(cellId) && !a_hasProperty(cellId, SolverCell::IsInactive)) noActiveLeafCells++;
24929 if(a_hasProperty(cellId, SolverCell::NearWall)) {
24930 noNearBndryCells++;
24931 }
24932 if(a_bndryId(cellId) > -1 && c_isLeafCell(cellId)) {
24933 noBndrycells++;
24934 }
24935 if(c_isLeafCell(cellId)) {
24936 MBool atLvlJump = false;
24937 for(MInt dir = 0; dir < m_noDirs; dir++) {
24938 if(c_neighborId(cellId, dir, false) < 0 && c_parentId(cellId) > -1
24939 && c_neighborId(c_parentId(cellId), dir, false) > -1) {
24940 atLvlJump = true;
24941 break;
24942 }
24943 if(c_neighborId(cellId, dir, false) > -1 && !c_isLeafCell(c_neighborId(cellId, dir, false))) {
24944 atLvlJump = true;
24945 break;
24946 }
24947 }
24948 if(atLvlJump) {
24949 noLvlJumpCells++;
24950 }
24951 }
24952 }
24953 }
24954
24955 for(MInt bc = 0; bc < m_fvBndryCnd->m_noCutOffBndryCndIds; bc++) {
24956 // Note: this also counts halo-cells
24957 const MInt cutOffSize = m_fvBndryCnd->m_sortedCutOffCells[bc]->size();
24958 if(bc == m_fvBndryCnd->m_bc1601_bcId) {
24959 noBc1601Cells = cutOffSize;
24960 } else {
24961 noCutOffCells += cutOffSize;
24962 }
24963 }
24964
24965
24966 domainInfo.emplace_back(namePrefix + "noFvCells", noCells);
24967 domainInfo.emplace_back(namePrefix + "noFvLeafCells", noLeafCells);
24968 domainInfo.emplace_back(namePrefix + "noFvActiveLeafCells", noActiveLeafCells);
24969
24970 // Number of Bndry-Cells
24971 if(m_weightBndryCells) {
24972 domainInfo.emplace_back(namePrefix + "noFvBndryCells", noBndrycells);
24973 }
24974
24975 // Number of cut-off cells
24976 if(m_weightCutOffCells) {
24977 domainInfo.emplace_back(namePrefix + "noCutOffCells", noCutOffCells);
24978 }
24979 // Number of bc1601 cells (random eddy inflow)
24980 if(m_weightBc1601) {
24981 domainInfo.emplace_back(namePrefix + "noBc1601Cells", noBc1601Cells);
24982 }
24983
24984 // Number of near Bndry-Cells
24985 if(m_weightNearBndryCells) {
24986 domainInfo.emplace_back(namePrefix + "noNearBndryCells", noNearBndryCells);
24987 }
24988
24989 // number of inactive cells
24990 if(m_weightInactiveCell) {
24991 domainInfo.emplace_back(namePrefix + "noFvInacticeCells", grid().noInternalCells());
24992 }
24993
24994 // number of cells at lvl-jumps
24995 if(m_weightLvlJumps) {
24996 domainInfo.emplace_back(namePrefix + "noFvLvlJumpCells", noLvlJumpCells);
24997 }
24998
24999 // number of small-cells
25000 if(m_weightSmallCells) {
25001 domainInfo.emplace_back(namePrefix + "noFvSmallCells", m_fvBndryCnd->m_smallCutCells.size());
25002 }
25003}
25004
25009template <MInt nDim_, class SysEqn>
25011 TRACE();
25012
25013 MIntScratchSpace Gap(a_noCells(), 2, AT_, "Gap");
25014
25015 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
25016 Gap(cellId, 0) = (MInt)a_isGapCell(cellId);
25017 Gap(cellId, 1) = (MInt)a_wasGapCell(cellId);
25018 }
25019
25020 exchangeDataFV(&Gap(0, 0), 2);
25021
25022 for(MInt cellId = noInternalCells(); cellId < a_noCells(); cellId++) {
25023 a_isGapCell(cellId) = (MBool)Gap(cellId, 0);
25024 a_wasGapCell(cellId) = (MBool)Gap(cellId, 1);
25025 }
25026}
25027
25032template <MInt nDim_, class SysEqn>
25034 TRACE();
25035
25036 if(noNeighborDomains() == 0) return;
25037
25038 ScratchSpace<maia::fv::cell::BitsetType> propsBak(a_noCells(), FUN_, "propsBak");
25039
25040 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
25041 propsBak[0] = a_properties(cellId);
25042 }
25043
25044 maia::mpi::exchangeBitset(grid().neighborDomains(), grid().haloCells(), grid().windowCells(), mpiComm(), &propsBak[0],
25045 m_cells.size());
25046
25047 for(MInt cellId = noInternalCells(); cellId < a_noCells(); cellId++) {
25048 a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) =
25049 propsBak[cellId][maia::fv::cell::p(SolverCell::IsOnCurrentMGLevel)];
25050 a_hasProperty(cellId, SolverCell::IsInactive) = propsBak[cellId][maia::fv::cell::p(SolverCell::IsInactive)];
25051 }
25052}
25053
25054
25061template <MInt nDim_, class SysEqn>
25063 TRACE();
25064
25065 // Note: reset only for existing cells and not for maxNoGridCell(), clearing the collector or
25066 // adding new cells will invalidate the properties anyways
25067 for(MInt c = 0; c < m_cells.size(); c++) {
25068 a_hasProperty(c, SolverCell::IsCutOff) = false;
25069 }
25070
25071 m_fvBndryCnd->resetCutOff();
25072}
25073
25074// ----------------------------------------------------------------------------
25075
25076template <MInt nDim_, class SysEqn>
25078 TRACE();
25079
25080 MInt nghbr0, nghbr1;
25081 const MInt noPVarIds = PV->noVariables;
25082 const MInt noSrfcs = a_noSurfaces();
25083 MInt va0, va1, sl0, sl1, i;
25084 const MInt surfaceVarMemory = m_surfaceVarMemory;
25085 const MInt slopeMemory = m_slopeMemory;
25086 MFloat* surfaceVar = (MFloat*)(&(a_surfaceVariable(0, 0, 0)));
25087 MFloat* cellSlopes = (MFloat*)(&(a_slope(0, 0, 0)));
25088 MFloat* dx = (MFloat*)(&(a_surfaceDeltaX(0, 0)));
25089 //---end of initialization
25090
25091 va0 = 0;
25092 va1 = noPVarIds;
25093 i = 0;
25094
25095 for(MInt srfcId = 0; srfcId < noSrfcs; srfcId++) {
25096 // interpolate the primitive variables onto the surface from both sides
25097 nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
25098 nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
25099
25100 sl0 = nghbr0 * slopeMemory;
25101 sl1 = nghbr1 * slopeMemory;
25102
25103 // limiting: bounds are MAX(v0,v1) and MIN(v0,v1)
25104 for(MInt varId = 0; varId < noPVarIds; varId++) {
25105 surfaceVar[va0 + varId] = a_pvariable(nghbr0, varId) + cellSlopes[sl0] * dx[i] + cellSlopes[sl0 + 1] * dx[i + 1];
25106 IF_CONSTEXPR(nDim == 3) surfaceVar[va0 + varId] += cellSlopes[sl0 + 2] * dx[i + 2];
25107
25108 surfaceVar[va0 + varId] =
25109 mMin(surfaceVar[va0 + varId], mMax(a_pvariable(nghbr0, varId), a_pvariable(nghbr1, varId)));
25110 surfaceVar[va0 + varId] =
25111 mMax(surfaceVar[va0 + varId], mMin(a_pvariable(nghbr0, varId), a_pvariable(nghbr1, varId)));
25112
25113 surfaceVar[va1 + varId] =
25114 a_pvariable(nghbr1, varId) + cellSlopes[sl1] * dx[i + nDim] + cellSlopes[sl1 + 1] * dx[i + nDim + 1];
25115 IF_CONSTEXPR(nDim == 3) surfaceVar[va1 + varId] += cellSlopes[sl1 + 2] * dx[i + nDim + 2];
25116
25117 surfaceVar[va1 + varId] =
25118 mMin(surfaceVar[va1 + varId], mMax(a_pvariable(nghbr0, varId), a_pvariable(nghbr1, varId)));
25119 surfaceVar[va1 + varId] =
25120 mMax(surfaceVar[va1 + varId], mMin(a_pvariable(nghbr0, varId), a_pvariable(nghbr1, varId)));
25121 sl0 += nDim;
25122 sl1 += nDim;
25123 }
25124 va0 += surfaceVarMemory;
25125 va1 += surfaceVarMemory;
25126 i += 2 * nDim;
25127 }
25128
25129 // correct the boundary surface values
25130 m_fvBndryCnd->correctBoundarySurfaceVariables();
25131
25132 // update the ghost cell slopes for the viscous flux computation
25133 m_fvBndryCnd->updateGhostCellSlopesViscous();
25134 m_fvBndryCnd->updateCutOffSlopesViscous();
25135}
25136
25137
25138template <MInt nDim_, class SysEqn>
25140 TRACE();
25141
25142 MInt nghbr0, nghbr1;
25143 const MInt noPVarIds = PV->noVariables;
25144 const MInt noSrfcs = a_noSurfaces();
25145 MInt /* cc0, cc1, sc, */ va0, va1, sl0, sl1, i;
25146 const MInt surfaceVarMemory = m_surfaceVarMemory;
25147 const MInt slopeMemory = m_slopeMemory;
25148 MFloat* surfaceVar = (MFloat*)(&(a_surfaceVariable(0, 0, 0)));
25149 MFloat* cellSlopes = (MFloat*)(&(a_slope(0, 0, 0)));
25150 MFloat* dx = (MFloat*)(&(a_surfaceDeltaX(0, 0)));
25151 //---end of initialization
25152
25153 va0 = 0;
25154 va1 = noPVarIds;
25155 // sc = 0;
25156 i = 0;
25157
25158 for(MInt srfcId = 0; srfcId < noSrfcs; srfcId++) {
25159 // interpolate the primitive variables onto the surface from both sides
25160 nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
25161 nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
25162
25163 sl0 = nghbr0 * slopeMemory;
25164 sl1 = nghbr1 * slopeMemory;
25165 // cc0 = nghbr0 * nDim;
25166 // cc1 = nghbr1 * nDim;
25167
25168 /* MFloat dx0[nDim], dx1[nDim];
25169 dx0[0] = surfaceCoord[sc] - cellCoord[cc0];
25170 dx0[1] = surfaceCoord[sc + 1] - cellCoord[cc0 + 1];
25171 IF_CONSTEXPR(nDim == 3) {
25172 dx0[2] = surfaceCoord[sc + 2] - cellCoord[cc0 + 2];
25173 }
25174 dx1[0] = surfaceCoord[sc] - cellCoord[cc1];
25175 dx1[1] = surfaceCoord[sc + 1] - cellCoord[cc1 + 1];
25176 IF_CONSTEXPR(nDim == 3) {
25177 dx1[2] = surfaceCoord[sc + 2] - cellCoord[cc1 + 2];
25178 }
25179 */
25180
25181 for(MInt varId = 0; varId < noPVarIds; varId++) {
25182 surfaceVar[va0 + varId] = a_pvariable(nghbr0, varId) + cellSlopes[sl0] * dx[i] // dx0[0]
25183 + cellSlopes[sl0 + 1] * dx[i + 1]; // dx0[1]
25184 IF_CONSTEXPR(nDim == 3) surfaceVar[va0 + varId] += cellSlopes[sl0 + 2] * dx[i + 2]; // dx0[2];
25185
25186 surfaceVar[va1 + varId] = a_pvariable(nghbr1, varId) + cellSlopes[sl1] * dx[i + nDim] // dx1[0]
25187 + cellSlopes[sl1 + 1] * dx[i + nDim + 1]; // dx1[1]
25188 IF_CONSTEXPR(nDim == 3) surfaceVar[va1 + varId] += cellSlopes[sl1 + 2] * dx[i + nDim + 2]; // dx1[2];
25189
25190 // limiter
25191 if(surfaceVar[va0 + varId] > mMax(a_pvariable(nghbr0, varId), a_pvariable(nghbr1, varId))
25192 || surfaceVar[va0 + varId] < mMin(a_pvariable(nghbr0, varId), a_pvariable(nghbr1, varId))) {
25193 surfaceVar[va0 + varId] = a_pvariable(nghbr0, varId);
25194 }
25195 if(surfaceVar[va1 + varId] > mMax(a_pvariable(nghbr0, varId), a_pvariable(nghbr1, varId))
25196 || surfaceVar[va1 + varId] < mMin(a_pvariable(nghbr0, varId), a_pvariable(nghbr1, varId))) {
25197 surfaceVar[va1 + varId] = a_pvariable(nghbr1, varId);
25198 }
25199 sl0 += nDim;
25200 sl1 += nDim;
25201 i += 2 * nDim; // TODO labels:FV @ansgar this seems not correct! compare computeLimitedSurfaceValues! -> unify?
25202 }
25203
25204 va0 += surfaceVarMemory;
25205 va1 += surfaceVarMemory;
25206 // sc += nDim;
25207 }
25208
25209 // correct the boundary surface values
25210 m_fvBndryCnd->correctBoundarySurfaceVariables();
25211
25212 // update the ghost cell slopes for viscous flux balance
25213 m_fvBndryCnd->updateGhostCellSlopesViscous();
25214 m_fvBndryCnd->updateCutOffSlopesViscous();
25215}
25216
25217
25218template <MInt nDim_, class SysEqn>
25220 TRACE();
25221
25222 MInt nghbr0, nghbr1;
25223 const MInt noPVarIds = PV->noVariables;
25224 const MInt noSrfcs = a_noSurfaces();
25225 // MInt va0, va1;//, sl0, sl1, i;
25226 const MInt surfaceVarMemory = m_surfaceVarMemory;
25227 MFloat* surfaceVar = (MFloat*)(&(a_surfaceVariable(0, 0, 0)));
25228 //---end of initialization
25229
25230 MInt va0 = 0;
25231 MInt va1 = noPVarIds;
25232 // i = 0;
25233
25234 for(MInt srfcId = 0; srfcId < noSrfcs; srfcId++) {
25235 // interpolate the primitive variables onto the surface from both sides
25236 nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
25237 nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
25238
25239 // sl0 = nghbr0 * slopeMemory;
25240 // sl1 = nghbr1 * slopeMemory;
25241
25242 for(MInt varId = 0; varId < PV->P; varId++) {
25243 surfaceVar[va0 + varId] = a_pvariable(nghbr0, varId); //
25244 // + cellSlopes[sl0] * dx[i]
25245 // + cellSlopes[sl0 + 1] * dx[i + 1]
25246 // IF_CONSTEXPR(nDim == 2) {
25247 // ;
25248 //} else {
25249 // + cellSlopes[sl0 + 2] * dx[i + 2];
25250 //}
25251 surfaceVar[va1 + varId] = a_pvariable(nghbr1, varId); //
25252 // + cellSlopes[sl1] * dx[i + nDim]
25253 // + cellSlopes[sl1 + 1] * dx[i + nDim + 1]
25254 // IF_CONSTEXPR(nDim == 2) {
25255 // ;
25256 //} else {
25257 // + cellSlopes[sl1 + 2] * dx[i + nDim + 2];
25258 //}
25259 // sl0 += nDim;
25260 // sl1 += nDim;
25261 }
25262 surfaceVar[va0 + PV->P] = a_pvariable(nghbr0, PV->P);
25263 surfaceVar[va1 + PV->P] = a_pvariable(nghbr1, PV->P);
25264 // sl0 += nDim;
25265 // sl1 += nDim;
25266 for(MInt varId = PV->P + 1; varId < noPVarIds; varId++) {
25267 surfaceVar[va0 + varId] = a_pvariable(nghbr0, varId); //
25268 // + cellSlopes[sl0] * dx[i]
25269 // + cellSlopes[sl0 + 1] * dx[i + 1]
25270 // IF_CONSTEXPR(nDim == 2) {
25271 // ;
25272 //} else {
25273 // + cellSlopes[sl0 + 2] * dx[i + 2];
25274 //}
25275 surfaceVar[va1 + varId] = a_pvariable(nghbr1, varId); //
25276 // + cellSlopes[sl1] * dx[i + nDim]
25277 // + cellSlopes[sl1 + 1] * dx[i + nDim + 1]
25278 // IF_CONSTEXPR(nDim == 2) {
25279 // ;
25280 //} else {
25281 // + cellSlopes[sl1 + 2] * dx[i + nDim + 2]
25282 //}
25283 // sl0 += nDim;
25284 // sl1 += nDim;
25285 }
25286
25287 va0 += surfaceVarMemory;
25288 va1 += surfaceVarMemory;
25289 // i += 2 * nDim;
25290 }
25291
25292 // correct the boundary surface values
25293 m_fvBndryCnd->correctBoundarySurfaceVariables();
25294
25295 // update the ghost cell slopes for the viscous flux computation
25296 m_fvBndryCnd->updateGhostCellSlopesViscous();
25297 m_fvBndryCnd->updateCutOffSlopesViscous();
25298}
25299
25300// ----------------------------------------------------------------------------
25301
25302template <MInt nDim_, class SysEqn>
25304 TRACE();
25305
25306 MInt counter;
25307 const MInt noCells = a_noCells();
25308 MInt noNghbrIds, nghbrId;
25309 MInt noUnknowns = 0;
25310 if(m_orderOfReconstruction == 1) {
25311 noUnknowns = nDim;
25312 }
25313 if(m_orderOfReconstruction == 2) {
25314 noUnknowns = (nDim == 2) ? 5 : 9;
25315 }
25316 MFloat norm, tmp, normi, avg;
25317 //---
25318
25319 // (p)reset the reconstruction constants
25320 for(MInt n = 0; n < nDim * (maxNoGridCells() * m_cells.noRecNghbrs()); n++) {
25321 // m_reconstructionConstants[n] = -999;
25322 }
25323
25324 // cell-center reconstruction
25325 counter = 0;
25326 m_reconstructionDataSize = 0;
25327 avg = F0;
25328 for(MInt cellId = 0; cellId < noCells; cellId++) {
25329 a_reconstructionData(cellId) = m_reconstructionDataSize;
25330 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
25331 continue;
25332 }
25333 if(!a_hasProperty(cellId, SolverCell::IsFlux)) {
25334 continue;
25335 }
25336 if(a_isBndryGhostCell(cellId)) {
25337 continue;
25338 }
25339 // if( a_hasProperty( cellId , SolverCell::IsCutOff) )
25340 // continue;
25341 if(a_hasProperty(cellId, SolverCell::IsNotGradient)) {
25342 continue;
25343 }
25344 if(a_hasProperty(cellId, SolverCell::IsInvalid)) {
25345 continue;
25346 }
25347
25348 if(a_bndryId(cellId) > -1) {
25349 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_linkedCellId > -1) {
25350 continue;
25351 }
25352 }
25353
25354 // loop over least-squares cell cluster
25355 noNghbrIds = a_noReconstructionNeighbors(cellId);
25356
25357 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
25358 nghbrId = a_reconstructionNeighborId(cellId, nghbr);
25359 for(MInt i = 0; i < nDim; i++) {
25360 m_A[nghbr][i] = a_coordinate(nghbrId, i) - a_coordinate(cellId, i);
25361 }
25362 // additional terms for a higher-order reconstruction
25363 if(m_orderOfReconstruction == 2) {
25364 for(MInt i = 0; i < nDim; i++) {
25365 m_A[nghbr][nDim + i] = POW2(a_coordinate(nghbrId, i) - a_coordinate(cellId, i));
25366 }
25367 m_A[nghbr][2 * nDim] =
25368 (a_coordinate(nghbrId, 0) - a_coordinate(cellId, 0)) * (a_coordinate(nghbrId, 1) - a_coordinate(cellId, 1));
25369 IF_CONSTEXPR(nDim == 3) {
25370 m_A[nghbr][2 * nDim + 1] = (a_coordinate(nghbrId, 0) - a_coordinate(cellId, 0))
25371 * (a_coordinate(nghbrId, 2) - a_coordinate(cellId, 2));
25372 m_A[nghbr][2 * nDim + 2] = (a_coordinate(nghbrId, 1) - a_coordinate(cellId, 1))
25373 * (a_coordinate(nghbrId, 2) - a_coordinate(cellId, 2));
25374 }
25375 }
25376 }
25377
25378 // compute ATA
25379 for(MInt i = 0; i < noUnknowns; i++) {
25380 for(MInt j = 0; j < noUnknowns; j++) {
25381 m_ATA[i][j] = F0;
25382 for(MInt k = 0; k < noNghbrIds; k++) {
25383 m_ATA[i][j] += m_A[k][i] * m_A[k][j];
25384 }
25385 }
25386 }
25387
25388 // invert ATA
25389 const MFloat epsilon = POW3(c_cellLengthAtLevel(maxRefinementLevel()) / (1000.0));
25390 if(maia::math::inverse(m_ATA, m_ATAi, noUnknowns, epsilon) == 0) {
25391 // cerr << domainId() << ": " << cellId << " " << noNghbrIds << endl;
25392 mTerm(1, AT_, "error recon");
25393 }
25394
25395 // compute the 1-norms of ATA and ATAi
25396 norm = F0;
25397 normi = F0;
25398 for(MInt j = 0; j < noUnknowns; j++) {
25399 tmp = F0;
25400 for(MInt i = 0; i < noUnknowns; i++) {
25401 tmp += ABS(m_ATA[i][j]);
25402 }
25403 norm = mMax(norm, tmp);
25404 normi = mMax(normi, tmp);
25405 }
25406
25407 // compute the condition number of ATA
25408 avg += norm * normi;
25409 counter++;
25410
25411 // compute (m_ATA)^(-1) * AT
25412 for(MInt i = 0; i < noUnknowns; i++) {
25413 for(MInt j = 0; j < noNghbrIds; j++) {
25414 m_ATA[i][j] = F0;
25415 for(MInt k = 0; k < noUnknowns; k++) {
25416 m_ATA[i][j] += m_ATAi[i][k] * m_A[j][k];
25417 }
25418 }
25419 }
25420
25421 m_reconstructionConstants.resize(nDim * (m_reconstructionDataSize + noNghbrIds));
25422 m_reconstructionCellIds.resize(m_reconstructionDataSize + noNghbrIds);
25423 m_reconstructionNghbrIds.resize(m_reconstructionDataSize + noNghbrIds);
25424
25425 // loop over least-squares cell cluster
25426 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
25427 nghbrId = a_reconstructionNeighborId(cellId, nghbr);
25428
25429 // set cell Ids
25430 m_reconstructionCellIds[m_reconstructionDataSize] = cellId;
25431 m_reconstructionNghbrIds[m_reconstructionDataSize] = nghbrId;
25432
25433 // compute the constants
25434 for(MInt d = 0; d < nDim; d++) {
25435 m_reconstructionConstants[nDim * m_reconstructionDataSize + d] = m_ATA[d][nghbr];
25436 }
25437
25438 m_reconstructionDataSize++;
25439 }
25440 }
25441 a_reconstructionData(noCells) = m_reconstructionDataSize;
25442 m_log << " -> Least-squares: average condition number of A^T A: " << avg / (MFloat)counter << endl;
25443}
25444
25445
25454template <MInt nDim_, class SysEqn>
25456 TRACE();
25457
25458 const MInt noCells = m_fvBndryCnd->m_bndryCells->size();
25459 const MInt noPVars = PV->noVariables;
25460 const MInt noSlopes = nDim * noPVars;
25461 const MInt slopeMemory = m_slopeMemory;
25462 MInt j, cellId, linkedCell;
25463 MFloat* slope = (MFloat*)(&(a_slope(0, 0, 0)));
25464 MInt reconstructionDataLocation, nghbrId;
25465 MInt recCellId;
25466 //---
25467
25468 // reset the slopes on the boundary cells
25469 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
25470 cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25471 j = slopeMemory * cellId;
25472 for(MInt i = 0; i < noSlopes; i++) {
25473 slope[j + i] = F0;
25474 }
25475 }
25476
25477 // compute the slopes on all boundary cells on the respective computing level
25478 for(MInt bndryId = 0; bndryId < noCells; bndryId++) {
25479 cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
25480 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
25481 continue;
25482 }
25483 linkedCell = m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId;
25484 recCellId = cellId;
25485 if(linkedCell > -1) { // use master cell reconstruction neighbors and constants!
25486 recCellId = linkedCell;
25487 }
25488 reconstructionDataLocation = a_reconstructionData(recCellId);
25489 for(MInt nghbr = 0; nghbr < a_noReconstructionNeighbors(recCellId); nghbr++) {
25490 nghbrId = a_reconstructionNeighborId(recCellId, nghbr);
25491 for(MInt var = 0; var < noPVars; var++) {
25492 for(MInt i = 0; i < nDim; i++) {
25493 a_slope(cellId, var, i) += m_reconstructionConstants[nDim * reconstructionDataLocation + i]
25494 * (a_pvariable(nghbrId, var) - a_pvariable(recCellId, var));
25495 }
25496 }
25497 reconstructionDataLocation++;
25498 }
25499 }
25500}
25501
25502// ----------------------------------------------------------------------------
25503
25504/*
25505 * \brief generates finite-volume boundary cells and their member variables
25506 *
25507 * @author Daniel Hartmann, 22.12.2006, Merry Christmas!
25508 */
25509template <MInt nDim_, class SysEqn>
25511 TRACE();
25512
25513 m_log << "Generating FV boundary cells..." << endl;
25514
25515 // TODO labels:FV,DLB skip setting isInterface flag or just perform for halo cells if properties are communicated
25516 // during DLB
25517 createBoundaryCells();
25518
25519 // TODO labels:FV,DLB speed this up for DLB reinitialization!
25520 m_fvBndryCnd->generateBndryCells();
25521
25522 m_log << m_fvBndryCnd->m_bndryCells->size() << " boundary cells created" << endl;
25523}
25524
25525
25535template <MInt nDim_, class SysEqn>
25537 TRACE();
25538
25539 // TODO labels:FV replace with cartesiangridproxy version!
25540
25541 MBool nghbrsFound = false;
25542 MBool nghbrExist = false;
25543 const MInt noCellIds = a_noCells();
25544 const MInt maxNoCells = maxNoGridCells();
25545 MInt nghbrChildId;
25546 MInt currentCellId;
25547 MInt sideId, nghbrSideId;
25548 MInt bndryId = 0;
25549 MInt nghbrId = 0;
25550 MInt smallCell;
25551 MInt k = 0;
25552 MInt maxIndex = 0;
25553 MInt pos = 0;
25554 MInt tempNghbrs[16];
25555 MInt tempNghbrs1[16];
25556 ScratchSpace<MFloat> coordinates(noCellIds * nDim, AT_, "coordinates");
25557 //---
25558
25559 if(!m_storeNghbrIds) {
25560 mAlloc(m_storeNghbrIds, m_noDirs * IPOW2(nDim) * maxNoCells, "m_storeNghbrIds", -1, AT_);
25561 }
25562 if(!m_identNghbrIds) {
25563 mAlloc(m_identNghbrIds, m_noDirs * maxNoCells + 1, "m_identNghbrIds", -1, AT_);
25564 }
25565
25566
25567 // ------------------------------------------------------------------------
25568 // ------------- determine coordinates of grid cell cogs ------------------
25569 // ------------------------------------------------------------------------
25570
25571 // for the determination of neighbor relations, the coordinates of the cog
25572 // of the GRID CELLS must be known
25573 // the cog of boundary cells is moved to the cog of the fluid part of the
25574 // respective cells and therefore differs from the cog of the corresponding
25575 // grid cell
25576
25577 // loop over all cartesian cells including ghost cells
25578
25579 // check bndryCellIds...
25580
25581
25582 for(MInt cellId = 0; cellId < noCellIds; cellId++) {
25583 // proceed if cell is not a ghost cell
25584 if(!a_isBndryGhostCell(cellId)) {
25585 // loop over space dimensions
25586 for(MInt d = 0; d < nDim; d++) {
25587 // copy coordinates of cog
25588 coordinates[cellId * nDim + d] = a_coordinate(cellId, d);
25589
25590 // correct cog of boundary cells
25591 if(a_bndryId(cellId) > -1) {
25592 bndryId = a_bndryId(cellId);
25593
25594 // correct coordinates in the scratch array
25595 coordinates[cellId * nDim + d] -= m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[d];
25596 }
25597 }
25598 }
25599 }
25600
25601 // correct coordinates of internal cells which are masters of a small cell
25602 for(MInt smallId = 0; smallId < m_fvBndryCnd->m_smallBndryCells->size(); smallId++) {
25603 smallCell = m_fvBndryCnd->m_smallBndryCells->a[smallId];
25604 if(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId != -1) {
25605 if(a_bndryId(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId) == -1) {
25606 for(MInt d = 0; d < nDim; d++) {
25607 coordinates[(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId) * nDim + d] =
25608 m_fvBndryCnd->m_bndryCells->a[smallCell].m_masterCoordinates[d];
25609 }
25610 }
25611 }
25612 }
25613
25614 // ------------------------------------------------------------------------
25615 // ------------- coordinates of grid cell cogs determined -----------------
25616 // ------------------------------------------------------------------------
25617
25618 // ------------------------------------------------------------------------
25619 // ------------- determine neighbor cell IDs of all cells -----------------
25620 // ------------------------------------------------------------------------
25621
25622 // --------- loop over all cartesian cells including ghost cells ----------
25623 for(MInt cellId = 0; cellId < noCellIds; cellId++) {
25624 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
25625 m_identNghbrIds[cellId * m_noDirs + dirId] = pos;
25626 }
25627
25628 // proceed if cell is not a ghost cell
25629 if(!a_isBndryGhostCell(cellId)) {
25630 // multilevel
25631 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
25632 // --------------- loop over directions -----------------------------
25633 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
25634 MInt spaceId = dirId / 2;
25635 sideId = dirId % 2;
25636 nghbrSideId = (sideId + 1) % 2;
25637
25638 nghbrExist = false;
25639
25640 // set the location in m_storeNghbrIds, where neighbors of cellId are
25641 // stored
25642 m_identNghbrIds[cellId * m_noDirs + dirId] = pos;
25643
25644 // ----------------------------------------------------------------
25645 // --- identify neighbor in considered direction ------------------
25646 // *-> this can be a neighbor of the cell itself or a neighbor of *
25647 // * its parent, grandparent, and so forth *
25648 // ----------------------------------------------------------------
25649
25650 // check if cell has a neighbor in the investigated
25651 // direction
25652 if(a_hasNeighbor(cellId, dirId) > 0) {
25653 if(a_level(c_neighborId(cellId, dirId)) <= maxRefinementLevel()) {
25654 // -> cell has a neighbor
25655 // this neighbor:
25656 nghbrId = c_neighborId(cellId, dirId);
25657
25658 // --------------------------------------------------------------
25659 // --- investigate neighbor -------------------------------------
25660 // *-> check if neighbor has children, grandchildren, and so *
25661 // * forth, which are direct neighbors of the considered cell *
25662 // --------------------------------------------------------------
25663 // multilevel
25664 if(a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) {
25665 // neighbor is not a parent and can be stored as neighbor of
25666 // the cell cellId
25667 m_storeNghbrIds[pos] = nghbrId;
25668 pos++;
25669
25670 } else {
25671 // neighbor is a parent
25672 // investigate all children and grandchildren
25673
25674 // temporary array that holds all parent cells to be
25675 // investigated
25676 tempNghbrs[0] = nghbrId;
25677 nghbrsFound = false;
25678
25679 // ----------------------------------------------------------
25680 // --- investigate all neighbors that are parents -----------
25681 // ----------------------------------------------------------
25682
25683 maxIndex = 1;
25684 while(nghbrsFound == false) {
25685 // initialize counter for the number of investigated
25686 // neighboring children that are parents themselves and
25687 // thus added to a temporary array
25688 k = 0;
25689
25690 // ------ loop over all neighbor parents ------------------
25691 for(MInt index = 0; index < maxIndex; index++) {
25692 // investigated neighbor parent cell
25693 ASSERT(index > -1 && index < 16, "");
25694 nghbrId = tempNghbrs[index];
25695
25696 // check the location of the children within the parent cell
25697 // by means of comparison of the grid cell cogs of the
25698 // parent cell and the children in considered space direction
25699
25700 // in case none of the children is identified
25701 // as a direct neighbor, do nothing, since then
25702 // the considered cell side is a non-fluid side
25703
25704 // --------- loop over neighbor children ----------------
25705 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
25706 if(c_childId(nghbrId, childId) == -1) {
25707 continue;
25708 }
25709
25710 if((coordinates[c_childId(nghbrId, childId) * nDim + spaceId]
25711 - coordinates[nghbrId * nDim + spaceId])
25712 * ((float)nghbrSideId - 0.5)
25713 > 0) {
25714 nghbrChildId = c_childId(nghbrId, childId);
25715 // multilevel
25716 if((c_noChildren(nghbrChildId) == 0 && a_level(nghbrChildId) <= maxRefinementLevel())
25717 || (c_noChildren(nghbrChildId) > 0 && a_level(nghbrChildId) == maxRefinementLevel())) {
25718 // child cell is not a parent and stored
25719 // as a neighbor
25720 m_storeNghbrIds[pos] = nghbrChildId;
25721 pos++;
25722
25723 } else {
25724 // add child cell to temporary array for
25725 // further investigation
25726 ASSERT(k > -1 && k < 16,
25727 "Too many local child neighbors. Something might be wrong with "
25728 "your mesh!");
25729 tempNghbrs1[k] = nghbrChildId;
25730 k++;
25731 }
25732 }
25733 }
25734 }
25735
25736 maxIndex = k;
25737 if(k == 0) {
25738 nghbrsFound = true;
25739 } else {
25740 // transfer the cells collected in tempNghbrs1 to
25741 // tempNghbrs
25742 for(MInt l = 0; l < k; l++) {
25743 ASSERT(l > -1 && l < 16, "");
25744 tempNghbrs[l] = tempNghbrs1[l];
25745 }
25746 }
25747 }
25748 }
25749 }
25750 } else {
25751 // -> cell does not have a neighbor of equivalent level
25752 currentCellId = cellId;
25753
25754 // loop until a parent is found that has a neighbor in considered
25755 // direction
25756 // break when the parent ID becomes -1 (boundary in direction)
25757 while(nghbrExist == false) {
25758 // if parent does not exist, break
25759 if(c_parentId(currentCellId) == -1) {
25760 break;
25761 }
25762
25763 // break if currentCell does not lie at the parent cell face
25764 // whose normal points to considered direction
25765 if((coordinates[currentCellId * nDim + spaceId] - coordinates[c_parentId(currentCellId) * nDim + spaceId])
25766 * ((float)sideId - 0.5)
25767 < 0) {
25768 break;
25769 }
25770
25771 // identify parentId of current cell and store it
25772 // as current cell
25773 currentCellId = c_parentId(currentCellId);
25774
25775 // check if current cell has a neighbor in regarded direction
25776 if(a_hasNeighbor(currentCellId, dirId) > 0) {
25777 nghbrExist = true;
25778 nghbrId = c_neighborId(currentCellId, dirId);
25779 // store this neighbor if it is regarded - multilevel
25780 if(a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) {
25781 m_storeNghbrIds[pos] = nghbrId;
25782 pos++;
25783 }
25784 }
25785 }
25786 }
25787 }
25788 }
25789 }
25790 }
25791 m_identNghbrIds[noCellIds * m_noDirs] = pos;
25792}
25793
25794/*
25795template <MInt nDim_, class SysEqn>void FvCartesianSolverXD<nDim,SysEqn>::findNghbrIdsMGC() {
25796 mTerm(1, "Only available in 3D. MGC not yet implemented in 2D");
25797}
25798*/
25811template <MInt nDim_, class SysEqn>
25813 IF_CONSTEXPR(nDim == 2) mTerm(1, "Only available in 3D. MGC not yet implemented in 2D");
25814 TRACE();
25815
25816 MBool nghbrsFound = false;
25817 MBool nghbrExist = false;
25818 const MInt noCellIds = a_noCells();
25819 const MInt maxNoCells = maxNoGridCells();
25820 MInt nghbrChildId;
25821 MInt currentCellId;
25822 MInt bndryId = 0;
25823 MInt nghbrBndryId;
25824 MInt nghbrId = 0;
25825 MInt k = 0;
25826 MInt maxIndex = 0;
25827 MInt pos = 0;
25828 MIntScratchSpace tempNghbrs_scratch(16, AT_, "tempNghbrs_scratch");
25829 MIntScratchSpace tempNghbrs1_scratch(16, AT_, "tempNghbrs1_scratch");
25830 MInt* tempNghbrs = tempNghbrs_scratch.getPointer();
25831 MInt* tempNghbrs1 = tempNghbrs1_scratch.getPointer();
25832
25833 const MInt sideToChildren[6][4] = {{0, 2, 4, 6}, {1, 3, 5, 7}, {0, 1, 4, 5},
25834 {2, 3, 6, 7}, {0, 1, 2, 3}, {4, 5, 6, 7}};
25835 const MInt otherDir[6] = {1, 0, 3, 2, 5, 4};
25836 const MInt noChildrenPerSide = IPOW2(nDim - 1);
25837 MBool isNonFluidSide[m_noDirs];
25838 MBool nonFluidSide = false;
25839
25840 if(!m_storeNghbrIds) {
25841 mAlloc(m_storeNghbrIds, m_noDirs * IPOW2(nDim) * maxNoCells, "m_storeNghbrIds", -1, AT_);
25842 }
25843 if(!m_identNghbrIds) {
25844 mAlloc(m_identNghbrIds, m_noDirs * maxNoCells + 1, "m_identNghbrIds", -1, AT_);
25845 }
25846
25847 //---
25848
25849 // ------------------------------------------------------------------------
25850 // ------------- determine coordinates of grid cell cogs ------------------
25851 // ------------------------------------------------------------------------
25852
25853 // for the determination of neighbor relations, the coordinates of the cog
25854 // of the GRID CELLS is required -> new version has to be called before the
25855 // cell centroids are moved, or they have to be shifted back before this
25856 // function is called.
25857
25858 // loop over all cartesian cells including ghost cells
25859
25860 // ------------------------------------------------------------------------
25861 // ------------- determine neighbor cell IDs of all cells -----------------
25862 // ------------------------------------------------------------------------
25863
25864 for(MInt cellId = 0; cellId < noCellIds; cellId++) {
25865 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
25866 m_identNghbrIds[cellId * m_noDirs + dirId] = pos;
25867 isNonFluidSide[dirId] = false;
25868 }
25869
25870 bndryId = a_bndryId(cellId);
25871
25872 if(a_hasProperty(cellId, SolverCell::IsInvalid)) {
25873 continue;
25874 }
25875
25876 if(bndryId > -2) {
25877 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
25878 // initialize nonFluidSide array to delete wrong connections
25879 if(bndryId > -1) {
25880 for(MInt face = 0; face < m_noDirs; face++) {
25881 isNonFluidSide[face] = m_fvBndryCnd->m_bndryCells->a[bndryId].m_externalFaces[face];
25882 }
25883 }
25884
25885
25886 // 1st step: identify potential neighbors -> OK
25887 // 2nd step: delete neighbor if non fluid side in between -> OK
25888 // 3rd step: correct split cells
25889 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
25890 nghbrExist = false;
25891
25892 // set the location in storeNghbrIds, where neighbors of cellId are
25893 // stored
25894 m_identNghbrIds[cellId * m_noDirs + dirId] = pos;
25895
25896 if(isNonFluidSide[dirId]) {
25897 continue;
25898 }
25899
25900 // ----------------------------------------------------------------
25901 // --- identify neighbor in considered direction ------------------
25902 // *-> this can be a neighbor of the cell itself or a neighbor of *
25903 // * its parent, grandparent, and so forth *
25904 // ----------------------------------------------------------------
25905
25906 // Timw: use Spliparent for neighbor-search for SplitClones
25907 MInt gridcellId = cellId;
25908 if(a_hasProperty(cellId, SolverCell::IsSplitClone)) {
25909 gridcellId = m_splitChildToSplitCell.find(cellId)->second;
25910 }
25911 // check if cell has a neighbor in the investigated
25912 // direction -> nghbr on the same level (stored in m_nghbrIds)
25913 if(a_hasNeighbor(gridcellId, dirId) > 0
25914 && (a_level(c_neighborId(gridcellId, dirId)) <= maxRefinementLevel())) {
25915 // -> cell has a neighbor
25916 // this neighbor:
25917 nghbrId = c_neighborId(gridcellId, dirId);
25918
25919 // --------------------------------------------------------------
25920 // --- investigate neighbor -------------------------------------
25921 // *-> check if neighbor has children, grandchildren, and so *
25922 // * forth, which are direct neighbors of the considered cell *
25923 // --------------------------------------------------------------
25924 // multilevel
25925 if(a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) {
25926 // neighbor is not a parent and can be stored as neighbor of
25927 // the cell cellId
25928
25929 // here, special situations for bndry cells can occur! -> nghbr is on same level, so
25930 // no special treatment concerning levels needed
25931 if(bndryId > -1) {
25932 if(m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2 + 1] > -1) {
25933 // split surface with different neighbors. special treatment.
25934 // check if first neighbor is also valid
25935 if(m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2] > -1) {
25936 m_storeNghbrIds[pos] = m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2];
25937 pos++;
25938 if(m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2]
25939 != m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2 + 1]) {
25940 m_storeNghbrIds[pos] = m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2];
25941 pos++;
25942 } else {
25943 cerr << " warning in findNghbrIdsMGC - assumed split face with two different "
25944 "neighbors. But neighbors are identical... "
25945 << endl;
25946 cerr << " cell: " << cellId << " bndryId: " << bndryId << " dir: " << dirId
25947 << " nghbrId: " << nghbrId << " nghbr1 in m_bndryNghbrs: "
25948 << m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2]
25949 << " nghbr2 in m_bndryNghbrs: "
25950 << m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2 + 1] << endl;
25951 }
25952 } else {
25953 cerr << " cell: " << cellId << " bndryId: " << bndryId << " dir: " << dirId
25954 << " nghbrId: " << nghbrId << " nghbr1 in m_bndryNghbrs: "
25955 << m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2]
25956 << " nghbr2 in m_bndryNghbrs: "
25957 << m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2 + 1] << endl;
25958
25959 stringstream errorMessage;
25960 errorMessage << " error in findNghbrIdsMGC - assumed fluid side to split "
25961 "relative, but -1 neighbor stored in m_bndryNghbrs... ";
25962 mTerm(1, AT_, errorMessage.str());
25963 }
25964 } else if(nghbrId != m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2]) {
25965 // split neighbor. special treatment
25966 // both on same level, not a non fuid side, so neighbor should be ok!
25967 // double check nevertheless...
25968 if(m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2] > -1) {
25969 m_storeNghbrIds[pos] = m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2];
25970 pos++;
25971 } else {
25972 stringstream errorMessage;
25973 errorMessage << " error in findNghbrIdsMGC - assumed fluid side to split "
25974 "relative, but -1 neighbor stored in m_bndryNghbrs... "
25975 << endl
25976 << " cell: " << cellId << " bndryId: " << bndryId << " dir: " << dirId
25977 << " nghbrId: " << nghbrId << " nghbr in m_bndryNghbrs: "
25978 << m_fvBndryCnd->m_bndryNghbrs[bndryId * 2 * m_noDirs + dirId * 2];
25979 mTerm(1, AT_, errorMessage.str());
25980 }
25981 } else {
25982 // regular boundary cell
25983 // both on the same level, not a non fluid side, so neighbor is ok!
25984 m_storeNghbrIds[pos] = nghbrId;
25985 pos++;
25986 }
25987 } else {
25988 m_storeNghbrIds[pos] = nghbrId;
25989 pos++;
25990 }
25991
25992 } else { // here, bndry cell treatment not included, so be careful with level changes on
25993 // bndry cells!
25994
25995 // neighbor is a parent
25996 // investigate all children and grandchildren
25997
25998 // temporary array that holds all parent cells to be
25999 // investigated
26000 tempNghbrs[0] = nghbrId;
26001 nghbrsFound = false;
26002
26003 // ----------------------------------------------------------
26004 // --- investigate all neighbors that are parents -----------
26005 // ----------------------------------------------------------
26006
26007 maxIndex = 1;
26008 while(nghbrsFound == false) {
26009 // initialize counter for the number of investigated
26010 // neighboring children that are parents themselves and
26011 // thus added to a temporary array
26012 k = 0;
26013
26014 // ------ loop over all neighbor parents ------------------
26015 for(MInt index = 0; index < maxIndex; index++) {
26016 // investigated neighbor parent cell
26017 nghbrId = tempNghbrs[index];
26018
26019 if(c_noChildren(nghbrId)) {
26020 // in case none of the children is identified
26021 // as a direct neighbor, do nothing, since then
26022 // the considered cell side is a non-fluid side
26023
26024 for(MInt c = 0; c < noChildrenPerSide; c++) {
26025 nghbrChildId = c_childId(nghbrId, sideToChildren[otherDir[dirId]][c]);
26026
26027 if(nghbrChildId > -1) {
26028 // multilevel
26029 if((c_noChildren(nghbrChildId) == 0 && a_level(nghbrChildId) <= maxRefinementLevel())
26030 || (c_noChildren(nghbrChildId) > 0 && a_level(nghbrChildId) == maxRefinementLevel())) {
26031 // child cell is not a parent and stored
26032 // as a neighbor
26033
26034 // check if a fluid connection exists
26035 nghbrBndryId = a_bndryId(nghbrChildId);
26036 nonFluidSide = false;
26037 if(nghbrBndryId > -1) {
26038 if(m_fvBndryCnd->m_bndryCells->a[nghbrBndryId].m_externalFaces[dirId]) {
26039 nonFluidSide = true;
26040 break;
26041 }
26042 }
26043 if(!nonFluidSide) {
26044 m_storeNghbrIds[pos] = nghbrChildId;
26045 pos++;
26046 }
26047 } else {
26048 // add child cell to temporary array for
26049 // further investigation
26050 tempNghbrs1[k] = nghbrChildId;
26051 k++;
26052 }
26053 }
26054 }
26055 }
26056 }
26057
26058 maxIndex = k;
26059 if(k == 0) {
26060 nghbrsFound = true;
26061 } else {
26062 // transfer the cells collected in tempNghbrs1 to
26063 // tempNghbrs
26064 for(MInt l = 0; l < k; l++) {
26065 tempNghbrs[l] = tempNghbrs1[l];
26066 }
26067 }
26068 }
26069 }
26070
26071 } else { // no nghbr on equal level -> nghbr has lower level!
26072
26073 // -> cell does not have a neighbor of equivalent level
26074 currentCellId = cellId;
26075 // Timw: use Spliparent for neighbor-search for SplitClones
26076 if(a_hasProperty(currentCellId, SolverCell::IsSplitClone)) {
26077 currentCellId = m_splitChildToSplitCell.find(currentCellId)->second;
26078 }
26079
26080 // loop until a parent is found that has a neighbor in considered
26081 // direction
26082 // break when the parent ID becomes -1 (boundary in direction)
26083 while(nghbrExist == false) {
26084 // if parent does not exist, break
26085 if(c_parentId(currentCellId) == -1) {
26086 break;
26087 }
26088
26089 // break if currentCell does not lie at the parent cell face
26090 // whose normal points to considered direction
26091 for(MInt c = 0; c < noChildrenPerSide; c++) {
26092 if(currentCellId == c_childId(c_parentId(currentCellId), sideToChildren[dirId][c])) {
26093 // identify parentId of current cell and store it
26094 // as current cell
26095 currentCellId = c_parentId(currentCellId);
26096
26097 // check if current cell has a neighbor in regarded direction
26098 if(a_hasNeighbor(currentCellId, dirId) > 0) {
26099 nghbrExist = true;
26100 nghbrId = c_neighborId(currentCellId, dirId);
26101 // store this neighbor if it is regarded - multilevel
26102 if(a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) {
26103 // check if a fluid connection exists
26104 nghbrBndryId = a_bndryId(nghbrId);
26105 nonFluidSide = false;
26106 if(nghbrBndryId > -1) {
26107 if(m_fvBndryCnd->m_bndryCells->a[nghbrBndryId].m_externalFaces[dirId]) {
26108 nonFluidSide = true;
26109 break;
26110 }
26111 }
26112 if(!nonFluidSide) {
26113 m_storeNghbrIds[pos] = nghbrId;
26114 pos++;
26115 }
26116 }
26117 }
26118 break;
26119 }
26120 }
26121 break;
26122 }
26123 }
26124 }
26125 }
26126 }
26127 }
26128 m_identNghbrIds[noCellIds * m_noDirs] = pos;
26129}
26130
26131// ----------------------------------------------------------------------------
26132
26142template <MInt nDim_, class SysEqn>
26143void FvCartesianSolverXD<nDim_, SysEqn>::findDirectNghbrs(const MInt cellId, vector<MInt>& nghbrList) {
26144 // TODO labels:FV replace with cartesiangridproxy version!
26145
26146 ASSERT(cellId >= 0, "ERROR: Invalid cellId!");
26147
26148 nghbrList.push_back(cellId);
26149
26150 // this prevents neighbors to be identified multiple times
26151 auto uniqueAdd = [&](MInt newElement) {
26152 auto it = find(nghbrList.begin(), nghbrList.end(), newElement);
26153 if(it == nghbrList.end() && newElement >= 0) {
26154 nghbrList.push_back(newElement);
26155 return true;
26156 }
26157 return false;
26158 };
26159
26163 static constexpr MInt diagDirs[4]{3, 2, 0, 1};
26164 for(MInt dir = 0; dir < 2 * nDim; dir++) {
26165 // iterate overall direct neighbors
26166 for(MInt j = m_identNghbrIds[2 * cellId * nDim + dir]; j < m_identNghbrIds[2 * cellId * nDim + dir + 1]; j++) {
26167 const MInt nghbrId = m_storeNghbrIds[j];
26168 uniqueAdd(nghbrId);
26169 if(dir < 4) {
26170 // add diagonal neighbors in x-y plane
26171 for(MInt t = m_identNghbrIds[2 * nghbrId * nDim + diagDirs[dir]];
26172 t < m_identNghbrIds[2 * nghbrId * nDim + diagDirs[dir] + 1];
26173 t++) {
26174 const MInt diagNghbr = m_storeNghbrIds[t];
26175 uniqueAdd(diagNghbr);
26176 }
26177 }
26178 }
26179 }
26180
26185 IF_CONSTEXPR(nDim == 3) {
26186 for(MInt dirZ = 4; dirZ < 6; dirZ++) {
26187 for(MInt j = m_identNghbrIds[2 * cellId * nDim + dirZ]; j < m_identNghbrIds[2 * cellId * nDim + dirZ + 1]; j++) {
26188 const MInt nghbrIdZ = m_storeNghbrIds[j];
26189 for(MInt dir = 0; dir < 4; dir++) {
26190 for(MInt t = m_identNghbrIds[2 * nghbrIdZ * nDim + dir]; t < m_identNghbrIds[2 * nghbrIdZ * nDim + dir + 1];
26191 t++) {
26192 const MInt nghbrId = m_storeNghbrIds[t];
26193 uniqueAdd(nghbrId);
26194 // tridiagonal neighbors
26195 for(MInt v = m_identNghbrIds[2 * nghbrId * nDim + diagDirs[dir]];
26196 v < m_identNghbrIds[2 * nghbrId * nDim + diagDirs[dir] + 1];
26197 v++) {
26198 const MInt triDiagNghbrId = m_storeNghbrIds[v];
26199 uniqueAdd(triDiagNghbrId);
26200 }
26201 }
26202 }
26203 }
26204 }
26205 }
26206}
26207
26218template <MInt nDim_, class SysEqn>
26220 vector<MInt>& nghbrList) {
26221 ASSERT(layer > 0, "ERROR: Invalid layer!");
26222 ASSERT(cellId >= 0, "ERROR: Invalid cellId!");
26223
26224 // TODO labels:FV replace with cartesiangridproxy version!
26225
26226 // this prevents neighbors to be identified multiple times
26227 auto uniqueAdd = [&](MInt newElement) {
26228 auto it = find(nghbrList.begin(), nghbrList.end(), newElement);
26229 if(it == nghbrList.end() && newElement >= 0) {
26230 nghbrList.push_back(newElement);
26231 return true;
26232 }
26233 return false;
26234 };
26235
26236 vector<MInt> tempNghbrCollection{};
26237
26241 findDirectNghbrs(cellId, nghbrList);
26242
26246 for(MInt currEx = 1; currEx < layer; currEx++) {
26247 // for each newly found neighbor find all neighbors
26248 for(auto& nghbr : nghbrList) {
26249 findDirectNghbrs(nghbr, tempNghbrCollection);
26250 }
26251 nghbrList.clear();
26252 // add all new unique neighbor ids to vector
26253 for(auto& nghbr : tempNghbrCollection) {
26254 if(uniqueAdd(nghbr) && currEx + 1 < layer) {
26255 // optimisation
26256 nghbrList.push_back(nghbr);
26257 }
26258 }
26259 }
26260}
26261
26262
26263template <MInt nDim_, class SysEqn>
26265 TRACE();
26266 IF_CONSTEXPR(!hasE<SysEqn>)
26267 mTerm(1, AT_, "Not compatible with SysEqn without RHO_E!");
26268
26269 switch(m_writeOutData) {
26270 case 1: {
26271 // dynamic pressure
26272 MFloat rhoU2 = 0;
26273 for(MInt dimId = 0; dimId < nDim; dimId++)
26274 rhoU2 += POW2(m_VVInfinity[dimId]);
26275 rhoU2 *= F1B2 * m_rhoInfinity;
26276
26277 // write center line data
26278 ofstream ofl;
26279 ofl.open("CenterlineData");
26280
26281 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
26282 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
26283 if(fabs(a_coordinate(cellId, 1) - c_cellLengthAtLevel(a_level(cellId) + 1)) < 0.001
26284 && fabs(a_coordinate(cellId, nDim - 1) - c_cellLengthAtLevel(a_level(cellId) + 1)) < 0.001) {
26285 for(MInt dimId = 0; dimId < nDim; dimId++)
26286 ofl << a_coordinate(cellId, dimId) << " ";
26287 for(MInt dimId = 0; dimId < nDim; dimId++)
26288 ofl << a_variable(cellId, CV->RHO_VV[dimId]) / a_variable(cellId, CV->RHO) << " ";
26289 ofl << a_variable(cellId, CV->RHO) << " ";
26290 ofl << endl;
26291 }
26292 }
26293 }
26294
26295 // write boundary cell data
26296 ofstream ofl2;
26297 MFloat angle;
26298 const MFloat yOffset = 30.0;
26299 const MFloat xOffset = 15.028;
26300 const MFloat radToDeg = 360.0 / (2.0 * PI);
26301 ofl2.open("BoundaryData");
26302
26303 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
26304 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
26305 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId >= 3000
26306 && m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[0]->m_bndryCndId <= 3003) {
26307 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
26308 // determine angle
26309 if(a_coordinate(cellId, 1) - yOffset > 0 && a_coordinate(cellId, 0) - xOffset > 0) {
26310 angle = 180 - radToDeg * atan((a_coordinate(cellId, 1) - yOffset) / (a_coordinate(cellId, 0) - xOffset));
26311 } else {
26312 if(a_coordinate(cellId, 1) - yOffset > 0 && a_coordinate(cellId, 0) - xOffset < 0) {
26313 angle = -radToDeg * atan((a_coordinate(cellId, 1) - yOffset) / (a_coordinate(cellId, 0) - xOffset));
26314 } else {
26315 if(a_coordinate(cellId, 1) - yOffset < 0 && a_coordinate(cellId, 0) - xOffset > 0) {
26316 angle = 180.0
26317 - radToDeg * atan((a_coordinate(cellId, 1) - yOffset) / (a_coordinate(cellId, 0) - xOffset));
26318 } else {
26319 angle = 360.0
26320 - radToDeg * atan((a_coordinate(cellId, 1) - yOffset) / (a_coordinate(cellId, 0) - xOffset));
26321 }
26322 }
26323 }
26324
26325 // calculate velocities
26326 MFloat vv[nDim];
26327 MFloat vv2 = 0;
26328 for(MInt dimId = 0; dimId < nDim; dimId++) {
26329 vv[dimId] = a_variable(cellId, CV->RHO_VV[dimId]) / a_variable(cellId, CV->RHO);
26330 vv2 += POW2(vv[dimId]);
26331 }
26332
26333 // pressure
26334 const MFloat p = sysEqn().pressure(a_variable(cellId, CV->RHO), vv2, a_variable(cellId, CV->RHO_E));
26335 const MFloat cp = (p - m_PInfinity) / rhoU2;
26336
26337 // Mach number
26338 const MFloat ma = sqrt(vv2) / sysEqn().speedOfSound(a_variable(cellId, CV->RHO), p);
26339
26340 ofl2 << angle << " ";
26341 for(MInt dimId = 0; dimId < nDim; dimId++)
26342 ofl << vv[dimId] << " ";
26343 ofl2 << cp << " ";
26344 ofl2 << ma << " ";
26345 for(MInt dimId = 0; dimId < nDim; dimId++)
26346 ofl << a_coordinate(cellId, dimId) << " ";
26347 ofl2 << m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId << " ";
26348 ofl2 << endl;
26349 }
26350 }
26351 }
26352 break;
26353 }
26354 case 2: {
26355 const MInt direction = 1;
26356 IF_CONSTEXPR(direction >= nDim) mTerm(1, AT_, "direction>=nDim");
26357 const MFloat coordinate = 100.0;
26358
26359 fstream ofl;
26360 stringstream file;
26361 file << "PlaneData" << domainId();
26362 ofl.open((file.str()).c_str(), ios::out);
26363
26364 for(MInt c = 0; c < noInternalCells(); c++) {
26365 if(c_noChildren(c) > 0) continue;
26366
26367 if(a_level(c) < 0) continue;
26368
26369 if(a_coordinate(c, direction) < coordinate) continue;
26370
26371 if(a_hasNeighbor(c, 2 * direction) > 0) {
26372 if(a_coordinate(c_neighborId(c, 2 * direction), direction) > coordinate) continue;
26373 } else {
26374 continue;
26375 }
26376
26377 // Write Ascii file
26378 for(MInt i = 0; i < nDim; i++)
26379 ofl << a_coordinate(c, i) << " ";
26380
26381 for(MInt v = 0; v < CV->noVariables; v++)
26382 ofl << a_variable(c, v) << " ";
26383
26384 ofl << endl;
26385 }
26386 ofl.close();
26387
26388 break;
26389 }
26390 default: {
26391 stringstream errorMessage;
26392 errorMessage << "FvCartesianSolverXD::writeCenterLineVel() switch variable 'm_writeOutData' with value "
26393 << m_writeOutData << " not matching any case." << endl;
26394 mTerm(1, AT_, errorMessage.str());
26395 }
26396 }
26397}
26398
26399
26406template <MInt nDim_, class SysEqn>
26408 TRACE();
26409
26410 const MInt noCVars = CV->noVariables;
26411 const MInt noPVars = PV->noVariables;
26412
26413 const MFloat gammaMinusOne = m_gamma - 1.0;
26414 const MFloat gammaPlusOne = m_gamma + 1.0;
26415
26417 m_TInfinity = sysEqn().temperature_IR(m_Ma);
26418 MFloat UT = m_Ma * sqrt(m_TInfinity);
26419 m_timeRef = UT;
26420 // quiescent flow field as infinity state i.e. inifity state is not a function of Ma!
26421 // => change in infinity primitive variables necessary!
26422 if(m_initialCondition == 465 || m_initialCondition == 9465) {
26423 m_TInfinity = 1.0;
26424 UT = 0;
26425 m_timeRef = m_Ma;
26426 }
26427
26428 m_UInfinity = UT * cos(m_angle[0]) * cos(m_angle[1]);
26429 m_VInfinity = UT * sin(m_angle[0]) * cos(m_angle[1]);
26430 IF_CONSTEXPR(nDim == 3) m_WInfinity = UT * sin(m_angle[1]);
26431 m_VVInfinity[0] = m_UInfinity;
26432 m_VVInfinity[1] = m_VInfinity;
26433 IF_CONSTEXPR(nDim == 3) m_VVInfinity[2] = m_WInfinity;
26434 m_PInfinity = sysEqn().pressure_IR(m_TInfinity);
26435
26436 m_rhoInfinity = sysEqn().density_IR(m_TInfinity);
26437 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
26438 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
26439 IF_CONSTEXPR(nDim == 3) m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
26440 m_rhoVVInfinity[0] = m_rhoUInfinity;
26441 m_rhoVVInfinity[1] = m_rhoVInfinity;
26442 IF_CONSTEXPR(nDim == 3) m_rhoVVInfinity[2] = m_rhoWInfinity;
26443 // timw: internal energy
26444 m_rhoEInfinity = m_PInfinity / gammaMinusOne + F1B2 * m_rhoInfinity * POW2(UT);
26445
26446 // reference enthalpies (needed for combustion computations)
26447 // timw-enthalpy
26448 m_hInfinity = m_PInfinity / m_rhoInfinity * m_gamma / gammaMinusOne;
26449
26450 sysEqn().m_muInfinity = SUTHERLANDLAW(m_TInfinity);
26451 // heat release model (progress variable) assumption of unity Lewis number Le=1 -> lambda(T)=D(T),
26452 // see Dissertation D.Hartmann page 13
26453 m_DInfinity = sysEqn().m_muInfinity;
26454 // - - assuming m_TInfinity is the temperature of the unburnt gas
26455 // - - Dth = mue^u / ( rho^u *Pr )
26456 m_DthInfinity = sysEqn().m_muInfinity / (m_rhoInfinity * m_Pr);
26457 m_SInfinity = F1 / m_gamma;
26458
26459 m_deltaP = F0;
26460
26461 sysEqn().m_Re0 = m_Re * sysEqn().m_muInfinity / (m_rhoInfinity * m_Ma * sqrt(m_TInfinity));
26462 m_rRe0 = 1. / sysEqn().m_Re0;
26463
26464 // necessary for FvZonalRTV
26465 const MFloat lamVisc = SUTHERLANDLAW(m_TInfinity);
26466 const MFloat chi = 0.1;
26467 const MFloat nuTilde = chi * (lamVisc / m_rhoInfinity);
26468 m_nuTildeInfinity = nuTilde;
26469 //--------------------------------------------------------------------------
26470 m_kInfinity = F3B2 * POW2(m_turbulenceDegree * m_UInfinity);
26471 m_omegaInfinity = sqrt(m_kInfinity) / (pow(0.09, 0.25) * m_referenceLength);
26472
26473 if(m_combustion) {
26474 setCombustionGequPvVariables();
26475 }
26476
26477 MInt SA = nDim;
26478 // NOTE: set custom values for member variables here to allow enabling ranks during DLB which
26479 // did not initialize these variables at solver start
26480 // i.e. update infinity state to special initial-condition treatment!
26481 switch(m_initialCondition) {
26482 case 77: {
26483 // set special properties/setting for this oblique shock initialCondition!
26484
26485 // TODO labels:FV IC=77 has been adopted from fvsolver2d and it currently works in 3D for the case
26486 // angle[1]=0
26487 if(abs(m_angle[1]) > 1e-10) {
26488 mTerm(1, AT_, "Flow component in z-diection currently not allowed for this IC!");
26489 }
26490
26503 SA = Context::getSolverProperty<MInt>("shockAlignment", m_solverId, AT_, &SA);
26504 if(SA == 2) {
26505 mTerm(1, AT_, "shockAlignment with z-axis not implemented yet. Feel free to do this.");
26506 }
26507
26508 if(m_VVInfinity[PV->VV[SA]] / sysEqn().speedOfSound(m_rhoInfinity, m_PInfinity) <= F1) {
26509 mTerm(1, AT_, "shock normal Mach number to small");
26510 }
26511
26512 MFloat sigma = (MFloat)(2 * SA - 1) * m_angle[0] + (MFloat)(!SA) * PI / F2;
26513 MFloat strength = POW2(m_Ma * sin(sigma));
26514 // compute postshock values
26515 mAlloc(m_postShockPV, noPVars, "m_postShockPV", F0, AT_);
26516 mAlloc(m_postShockCV, noCVars, "m_postShockCV", F0, AT_);
26517 // shock density
26518 m_postShockPV[PV->RHO] = m_rhoInfinity * (gammaPlusOne * strength) / (gammaMinusOne * strength + F2);
26519 m_postShockCV[CV->RHO] = m_postShockPV[PV->RHO];
26520 // shock parallel velovity
26521 m_postShockPV[PV->VV[!SA]] = m_VVInfinity[PV->VV[!SA]];
26522 m_postShockCV[CV->RHO_VV[!SA]] = m_postShockPV[PV->VV[!SA]] * m_postShockPV[PV->RHO];
26523 // shock normal velocity
26524 m_postShockPV[PV->VV[SA]] = m_rhoVVInfinity[CV->RHO_VV[SA]] / m_postShockPV[PV->RHO];
26525 m_postShockCV[CV->RHO_VV[SA]] = m_rhoVVInfinity[CV->RHO_VV[SA]];
26526 // spanwise velocity
26527 IF_CONSTEXPR(nDim == 3) {
26528 m_postShockPV[PV->VV[2]] = 0.0;
26529 m_postShockCV[CV->RHO_VV[2]] = 0.0;
26530 }
26531 // pressure/energie
26532 m_postShockPV[PV->P] = m_PInfinity * (F1 - m_gamma + F2 * m_gamma * strength) / gammaPlusOne;
26533 IF_CONSTEXPR(hasE<SysEqn>)
26534 m_postShockCV[CV->RHO_E] =
26535 m_postShockPV[PV->P] / gammaMinusOne
26536 + F1B2 * m_postShockPV[PV->RHO] * (POW2(m_postShockPV[PV->U]) + POW2(m_postShockPV[PV->V]));
26537
26538 // branch points
26539 MInt numBranchPoints = 4;
26540 MFloatScratchSpace BranchPoints(2, 2, numBranchPoints, AT_, "BranchPoints");
26541 MFloatScratchSpace kfp_2(nDim, AT_, "kfp_2");
26542 MFloatScratchSpace kfm_2(nDim, AT_, "kfm_2");
26543 MFloatScratchSpace ksp_2(nDim, AT_, "ksp_2");
26544 MFloatScratchSpace ksm_2(nDim, AT_, "ksm_2");
26545 MFloat beta =
26546 atan(F2 * (cos(sigma) / sin(sigma)) * (strength - F1) / (POW2(m_Ma) * (m_gamma + cos(F2 * sigma)) + F2));
26547 // Mach number downstream of the shock wave
26548 MFloat Ma1_n = m_Ma * sin(sigma);
26549 MFloat Ma1_t = m_Ma * cos(sigma);
26550 MFloat Ma2 = sqrt(POW2(m_postShockPV[PV->U]) + POW2(m_postShockPV[PV->V]))
26551 / sysEqn().speedOfSound(m_postShockPV[PV->RHO], m_postShockPV[PV->P]);
26552 if(Ma2 <= F1) mTerm(1, AT_, "postshock Mach number to small");
26553
26554 MFloat Ma2_n = Ma2 * sin(sigma - beta);
26555 MFloat Ma2_t = Ma2 * cos(sigma - beta);
26556 // extrema
26557 MFloat a = POW2(Ma2) - F1;
26558 MFloat b = -F2 * Ma2_t;
26559 MFloat c = F1;
26560 MFloat d = POW2((b / (F2 * a))) - c / a;
26561
26562 MFloat ktfm_2 = -b / (F2 * a) - sqrt(d);
26563 MFloat ktsm_2 = -b / (F2 * a) + sqrt(d);
26564
26565 kfp_2(0) = sin(sigma - beta) / (Ma2 + F1);
26566 kfp_2(1) = cos(sigma - beta) / (Ma2 + F1);
26567 kfm_2(0) = -(Ma2_n - ktfm_2 * Ma2_n * Ma2_t) / (F1 - POW2(Ma2_n));
26568 kfm_2(1) = ktfm_2;
26569 ksm_2(0) = -(Ma2_n - ktsm_2 * Ma2_n * Ma2_t) / (F1 - POW2(Ma2_n));
26570 ksm_2(1) = ktsm_2;
26571 ksp_2(0) = sin(sigma - beta) / (Ma2 - F1);
26572 ksp_2(1) = cos(sigma - beta) / (Ma2 - F1);
26573
26574 MFloatScratchSpace kt_1(4 + 2, AT_, "kt_1");
26575 kt_1(0) = kfp_2(1) * sqrt(m_TInfinity / (sysEqn().temperature_ES(m_postShockPV[PV->RHO], m_postShockPV[PV->P])));
26576 kt_1(1) = kfm_2(1) * sqrt(m_TInfinity / (sysEqn().temperature_ES(m_postShockPV[PV->RHO], m_postShockPV[PV->P])));
26577 kt_1(2) = ksm_2(1) * sqrt(m_TInfinity / (sysEqn().temperature_ES(m_postShockPV[PV->RHO], m_postShockPV[PV->P])));
26578 kt_1(3) = ksp_2(1) * sqrt(m_TInfinity / (sysEqn().temperature_ES(m_postShockPV[PV->RHO], m_postShockPV[PV->P])));
26579 kt_1(4) =
26580 (F1 / Ma2_t) * sqrt(m_TInfinity / (sysEqn().temperature_ES(m_postShockPV[PV->RHO], m_postShockPV[PV->P])));
26581 kt_1(5) =
26582 (Ma2_t / (POW2(Ma2) - F1)) * sqrt(sysEqn().temperature_ES(m_postShockPV[PV->RHO], m_postShockPV[PV->P]));
26583 // BranchPoints
26584 MInt length_kt_1 = kt_1.size();
26585 MFloatScratchSpace kn(length_kt_1, 3, AT_, "kn");
26586 for(MInt i = 0; i < length_kt_1; i++) {
26587 MFloat kt = kt_1(i);
26588 MFloat p = F2 * Ma1_n * (F1 - Ma1_t * kt) / (F1 - POW2(Ma1_n));
26589 // MFloat q = (2*Ma1_t*kt+POW2(kt*(1-POW2(Ma1_t))))/(1-POW2(Ma1_n));
26590 MFloat q = (POW2(kt) - POW2(kt * Ma1_t - F1)) / (F1 - POW2(Ma1_n));
26591 // slow
26592 kn(i, 0) = (-p / F2) + sqrt(POW2(p / F2) - q);
26593 // entropy
26594 kn(i, 1) = (F1 - Ma1_t * kt) / Ma1_n;
26595 // fast
26596 kn(i, 2) = (-p / F2) - sqrt(POW2(p / F2) - q);
26597 }
26598
26599 m_log << "**************************" << endl;
26600 m_log << "Postshock Conditions summary" << endl;
26601 m_log << "**************************" << endl;
26602 m_log << "TInfinity = " << sysEqn().temperature_ES(m_postShockPV[PV->RHO], m_postShockPV[PV->P]) << endl;
26603 m_log << "UInfinity = " << m_postShockPV[PV->U] << endl;
26604 m_log << "VInfinity = " << m_postShockPV[PV->V] << endl;
26605 IF_CONSTEXPR(nDim == 3) m_log << "WInfinity = " << m_postShockPV[PV->W] << endl;
26606 m_log << "PInfinity = " << m_postShockPV[PV->P] << endl;
26607 m_log << "rhoInfinity(PV) = " << m_postShockPV[PV->RHO] << endl;
26608 m_log << "AInfinity = " << sysEqn().speedOfSound(m_postShockPV[PV->RHO], m_postShockPV[PV->P]) << endl;
26609 m_log << "Ma = " << Ma2 << endl;
26610 m_log << "Ma_x = " << m_postShockPV[PV->U] / sysEqn().speedOfSound(m_postShockPV[PV->RHO], m_postShockPV[PV->P])
26611 << endl;
26612 m_log << "Ma_y = " << m_postShockPV[PV->V] / sysEqn().speedOfSound(m_postShockPV[PV->RHO], m_postShockPV[PV->P])
26613 << endl;
26614 m_log << "rhoInfinity(CV) = " << m_postShockCV[CV->RHO] << endl;
26615 IF_CONSTEXPR(hasE<SysEqn>)
26616 m_log << "rhoEInfinity = " << m_postShockCV[CV->RHO_E] << endl;
26617 m_log << "rhoUInfinity = " << m_postShockCV[CV->RHO_U] << endl;
26618 m_log << "rhoVInfinity = " << m_postShockCV[CV->RHO_V] << endl;
26619 IF_CONSTEXPR(nDim == 3) m_log << "rhoWInfinity = " << m_postShockCV[CV->RHO_W] << endl;
26620 m_log << "******* shock wave *******" << endl;
26621 m_log << "Ma2 = " << Ma2 << endl;
26622 m_log << "Ma2_n = " << Ma2_n << endl;
26623 m_log << "Ma2_t = " << Ma2_t << endl;
26624 m_log << "sigma = " << 180.0 * sigma / PI << endl;
26625 m_log << "beta = " << 180.0 * beta / PI << endl;
26626 m_log << "***** branch points ******" << endl;
26627 m_log << "canonical form" << endl;
26628 m_log << " fast: " << kfp_2(0) << ", " << kfp_2(1) << endl;
26629 for(MInt us = 0; us < 3; us++) {
26630 MFloat modeAngle = atan2(kt_1(0), kn(0, us)); // with respect to the shock normal
26631 m_log << " upstream mode type " << us - 1
26632 << ": "
26633 //<< kn(0,us) << ", " << kt_1(0) << ", "
26634 << 180.0 * modeAngle / PI << ", " << 180.0 * (modeAngle - (PI / F2 - sigma)) / PI
26635 << ", " // with repect to flow
26636 << 180.0 * (SA * PI / F2 + (F1 - SA * F2) * modeAngle) / PI
26637 << endl; // with respect to x axis (property file)
26638 }
26639 m_log << " slow: " << ksp_2(0) << ", " << ksp_2(1) << endl;
26640 for(MInt us = 0; us < 3; us++) {
26641 MFloat modeAngle = atan2(kt_1(3), kn(3, us)); // with respect to the shock normal
26642 m_log << " upstream mode type " << us - 1
26643 << ": "
26644 //<< kn(3,us) << ", " << kt_1(3) << ", "
26645 << 180.0 * modeAngle / PI << ", " << 180.0 * (modeAngle - (PI / F2 - sigma)) / PI << ", "
26646 << 180.0 * (SA * PI / F2 + (F1 - SA * F2) * modeAngle) / PI << endl;
26647 }
26648 m_log << "shock aligned form" << endl;
26649 m_log << " fast: " << kfm_2(0) << ", " << kfm_2(1) << endl;
26650 for(MInt us = 0; us < 3; us++) {
26651 MFloat modeAngle = atan2(kt_1(1), kn(1, us)); // with respect to the shock normal
26652 m_log << " upstream mode type " << us - 1
26653 << ": "
26654 //<< kn(1,us) << ", " << kt_1(1) << ", "
26655 << 180.0 * modeAngle / PI << ", " << 180.0 * (modeAngle - (PI / F2 - sigma)) / PI << ", "
26656 << 180.0 * (SA * PI / F2 + (F1 - SA * F2) * modeAngle) / PI << endl;
26657 }
26658 m_log << " slow: " << ksm_2(0) << ", " << ksm_2(1) << endl;
26659 for(MInt us = 0; us < 3; us++) {
26660 MFloat modeAngle = atan2(kt_1(2), kn(2, us)); // with respect to the shock normal
26661 m_log << " upstream mode type " << us - 1
26662 << ": "
26663 //<< kn(2,us) << ", " << kt_1(2) << ", "
26664 << 180.0 * modeAngle / PI << ", " << 180.0 * (modeAngle - (PI / F2 - sigma)) / PI << ", "
26665 << 180.0 * (SA * PI / F2 + (F1 - SA * F2) * modeAngle) / PI << endl;
26666 }
26667 m_log << "evanescent cases" << endl;
26668 m_log << " zero real number of kn and real(k_ac)==k_en:" << endl;
26669 for(MInt us = 0; us < 3; us++) {
26670 MFloat modeAngle = atan2(kt_1(4), kn(4, us)); // with respect to the shock normal
26671 m_log << " upstream mode type " << us - 1
26672 << ": "
26673 //<< kn(2,us) << ", " << kt_1(2) << ", "
26674 << 180.0 * modeAngle / PI << ", " << 180.0 * (modeAngle - (PI / F2 - sigma)) / PI << ", "
26675 << 180.0 * (SA * PI / F2 + (F1 - SA * F2) * modeAngle) / PI << endl;
26676 }
26677 m_log << " real(k_ac)||u and max(imag(kt))" << endl;
26678 for(MInt us = 0; us < 3; us++) {
26679 MFloat modeAngle = atan2(kt_1(5), kn(5, us)); // with respect to the shock normal
26680 m_log << " upstream mode type " << us - 1
26681 << ": "
26682 //<< kn(2,us) << ", " << kt_1(2) << ", "
26683 << 180.0 * modeAngle / PI << ", " << 180.0 * (modeAngle - (PI / F2 - sigma)) / PI << ", "
26684 << 180.0 * (SA * PI / F2 + (F1 - SA * F2) * modeAngle) / PI << endl;
26685 }
26686 break;
26687 }
26688
26689 case 11213:
26690 case 112123:
26691 case 112122:
26692 case 112121:
26693 case 11212: {
26694 ASSERT(isDetChem<SysEqn>, "IC not compatible with chosen sysEqn.");
26695
26696 // set inifinity values
26697 m_TInfinity = m_detChem.infTemperature;
26698
26699 // gives velocity as a factor of laminar flame speed
26700 UT = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[0];
26701
26702 MFloat recvVel = UT;
26703 MPI_Bcast(&recvVel, 1, MPI_DOUBLE, 0, mpiComm(), AT_, "recvVel"); // ensures same value across all ranks
26704
26705 m_log << "Reconstructed infinity velocity:" << recvVel << endl;
26706
26707 m_UInfinity = recvVel * cos(m_angle[0]) * cos(m_angle[1]);
26708 m_VInfinity = recvVel * sin(m_angle[0]) * cos(m_angle[1]);
26709 IF_CONSTEXPR(nDim == 3) m_WInfinity = recvVel * sin(m_angle[1]);
26710
26711 m_VVInfinity[0] = m_UInfinity;
26712 m_VVInfinity[1] = m_VInfinity;
26713 IF_CONSTEXPR(nDim == 3) m_VVInfinity[2] = m_WInfinity;
26714
26715 m_PInfinity = m_detChem.infPressure;
26716
26717#if defined(WITH_CANTERA)
26718 m_canteraThermo->setState_TPY(m_TInfinity, m_PInfinity, &m_YInfinity[0]);
26719 sysEqn().m_muInfinity = m_canteraTransport->viscosity();
26720#endif
26721
26722 MFloat FmeanMolarWeightInfinity = F0;
26723 for(MInt s = 0; s < m_noSpecies; s++) {
26724 FmeanMolarWeightInfinity += m_YInfinity[s] * m_fMolarMass[s];
26725 }
26726
26727 MFloat meanMolarWeightInfinity = F1 / FmeanMolarWeightInfinity;
26728
26729 m_rhoInfinity = m_PInfinity * meanMolarWeightInfinity / m_gasConstant / m_detChem.infTemperature;
26730
26731 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
26732 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
26733 IF_CONSTEXPR(nDim == 3) m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
26734
26735 m_rhoVVInfinity[0] = m_rhoUInfinity;
26736 m_rhoVVInfinity[1] = m_rhoVInfinity;
26737 IF_CONSTEXPR(nDim == 3) m_rhoVVInfinity[2] = m_rhoWInfinity;
26738
26739 const MInt maxLineLength = 256;
26740 MChar b[maxLineLength];
26741 snprintf(b, maxLineLength, "rhoInfinity: %.6e | muInfinity: %.6e | uInfinity: %.6e | vInfinity: %.6e |",
26742 m_rhoInfinity, sysEqn().m_muInfinity, m_UInfinity, m_VInfinity);
26743
26744 m_log << b << std::endl;
26745
26746 break;
26747 }
26748
26749 case 15: {
26750 if(!m_levelSetMb) {
26751 m_rhoInfinity = F1;
26752 m_PInfinity = sysEqn().p_Ref();
26753 m_UInfinity = m_Ma;
26754 m_TInfinity = F1;
26755 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
26756 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
26757 m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
26758 m_rhoEInfinity = m_PInfinity / gammaMinusOne + F1B2 * m_rhoInfinity * POW2(m_Ma);
26759 m_hInfinity = m_PInfinity / m_rhoInfinity * m_gamma / gammaMinusOne;
26760 sysEqn().m_Re0 = m_Re * SUTHERLANDLAW(m_TInfinity) / (m_rhoInfinity * m_UInfinity);
26761 m_timeRef = m_Ma;
26762 }
26763 break;
26764 }
26765 case 1164: {
26766 // Jet from (chevron) nozzle
26767 m_log << "Invalidating infinity variables to prevent/detect their usage for jet "
26768 "computations with a nozzle ..."
26769 << std::endl;
26770
26771 // Case specific constants (see Xia et al 2009)
26772 // TODO labels:FV @ansgar_mb specify via properties?
26773 const MFloat T_0 = 286.4;
26774 const MFloat T_inf = 280.2;
26775 const MFloat p_0 = 1.78e5;
26776 const MFloat p_inf = 0.97e5;
26777
26778 const MFloat temperature_j = m_normJetTemperature * T_inf / T_0;
26779 m_nozzleExitTemp = temperature_j;
26780
26781 const MFloat pressure_j = p_inf / (m_gamma * p_0);
26782 /* m_nozzleExitP = pressure_j; */
26783
26784 const MFloat rho_j = sysEqn().density_ES(pressure_j, temperature_j);
26785 m_nozzleExitRho = rho_j;
26786
26787 const MFloat Ma_j = m_maNozzleExit * sqrt(1.0 / m_normJetTemperature);
26788 m_nozzleExitMaJet = Ma_j;
26789
26790 const MFloat u_j = Ma_j * sqrt(temperature_j);
26791 m_nozzleExitU = u_j;
26792
26793 const MFloat mu_j = SUTHERLANDLAW(temperature_j);
26794
26795 m_log << "Ma_j = " << Ma_j << std::endl;
26796 m_log << "T_j = " << temperature_j << std::endl;
26797 m_log << "p_j = " << pressure_j << std::endl;
26798 m_log << "rho_j = " << rho_j << std::endl;
26799 m_log << "u_j = " << u_j << std::endl;
26800 m_log << "mu_j = " << mu_j << std::endl;
26801
26802 sysEqn().m_Re0 = m_Re * mu_j / (rho_j * u_j);
26803 m_rRe0 = 1. / sysEqn().m_Re0;
26804
26805 m_log << "Re_0 = " << sysEqn().m_Re0 << std::endl;
26806 m_log << "Re_j = " << m_Re << " " << (rho_j * u_j) / mu_j << std::endl;
26807
26808 // Ambient conditions
26809 const MFloat pressureAmbient = pressure_j;
26810 const MFloat temperatureAmbient = temperature_j / m_normJetTemperature;
26811 const MFloat densityAmbient = sysEqn().density_ES(pressureAmbient, temperatureAmbient);
26812
26813 m_PInfinity = pressureAmbient;
26814 m_rhoInfinity = densityAmbient;
26815 m_TInfinity = temperatureAmbient;
26816
26817 m_log << "T_inf = " << m_TInfinity << std::endl;
26818 m_log << "p_inf = " << m_PInfinity << std::endl;
26819 m_log << "rho_inf = " << m_rhoInfinity << std::endl;
26820
26821 // set m_timeRef = u_j/a0 instead of UT;
26822 m_timeRef = u_j;
26823 m_log << "timeRef = " << m_timeRef << std::endl;
26824
26825 // Determine nozzle inlet Mach number
26826 MFloat Ma_i = 0.2; // initial guess
26827 for(MInt n = 0; n < 10; n++) {
26828 const MFloat tmp = (1.0 + 0.5 * (m_gamma - 1) * POW2(Ma_i));
26829 const MFloat exponent = -(m_gamma + 1) / (2 * (m_gamma - 1));
26830 const MFloat fkt_g = POW2(m_outletRadius / m_inletRadius) * m_gamma * pressure_j * Ma_j / sqrt(temperature_j)
26831 - Ma_i * pow(tmp, exponent);
26832
26833 const MFloat diff_g = pow(tmp, exponent) * (-1 + POW2(Ma_i) * 0.5 * (m_gamma + 1.0) / tmp);
26834
26835 Ma_i = Ma_i - fkt_g / diff_g;
26836 }
26837
26838 m_maNozzleInlet = Ma_i;
26839
26840 const MFloat temperature_i = sysEqn().temperature_IR(Ma_i);
26841 const MFloat pressure_i = sysEqn().pressure_IR(temperature_i);
26842 const MFloat density_i = sysEqn().density_ES(pressure_i, temperature_i);
26843 const MFloat u_i = Ma_i * sqrt(temperature_i);
26844
26845 m_nozzleInletTemp = temperature_i;
26846 m_nozzleInletP = pressure_i;
26847 m_nozzleInletRho = density_i; // = rho_i/rho_0
26848 m_nozzleInletU = u_i; // = u_i/a_0
26849
26850 m_log << " Ma_i = " << Ma_i << std::endl;
26851 m_log << " T_i = " << temperature_i << std::endl;
26852 m_log << " p_i = " << pressure_i << std::endl;
26853 m_log << " rho_i = " << density_i << std::endl;
26854 m_log << " u_i = " << u_i << std::endl;
26855
26856 // Reset all infinity variables (3D) that should not be used anywhere in the computation
26857 m_UInfinity = u_j;
26858 m_VInfinity = 0.0;
26859 m_WInfinity = 0.0;
26860 m_VVInfinity[0] = m_UInfinity;
26861 m_VVInfinity[1] = m_VInfinity;
26862 m_VVInfinity[2] = m_WInfinity;
26863
26864 m_rhoUInfinity = NAN;
26865 m_rhoVInfinity = NAN;
26866 m_rhoWInfinity = NAN;
26867 m_rhoVVInfinity[0] = m_rhoUInfinity;
26868 m_rhoVVInfinity[1] = m_rhoVInfinity;
26869 m_rhoVVInfinity[2] = m_rhoWInfinity;
26870
26871 m_rhoEInfinity = NAN;
26872
26873 m_hInfinity = NAN;
26874 sysEqn().m_muInfinity = NAN;
26875 m_DInfinity = sysEqn().m_muInfinity;
26876 m_DthInfinity = NAN;
26877 m_SInfinity = NAN;
26878 break;
26879 }
26880 case 30: {
26881 // pressure loss per unit length dp = rho_00 u_tau^2 L / D ) here: D=1.0, L=1;
26882 // channel: dp = rho_00 u_tau^2 L / D )
26883 // m_deltaP = POW2( m_Ma * ReTau * sqrt(m_TInfinity) / m_Re ) * m_rhoInfinity /
26884 // m_referenceLength;
26885 // pipe: dp = lambda * L/D * rho/2 * u^2, lambda = 0.3164 Re^(-1/4) (Blasius)
26886 // see test cases
26887 if(m_restart) {
26888 // careful, special setting for TINA testcase triggered with TINA_TC keyword!
26889 IF_CONSTEXPR(nDim == 2) mTerm(-1, "This is a 3D IC!");
26890 if((string2enum(m_testCaseName) == SUZI_TC) || (string2enum(m_testCaseName) == TINA_TC)) {
26891 m_deltaP = 64 / sysEqn().m_Re0 * F1 / m_referenceLength * F1B2 * m_rhoInfinity * POW2(UT) / 10.0;
26892 } else {
26893 m_deltaP = 64 / sysEqn().m_Re0 * F1 / m_referenceLength * F1B2 * m_rhoInfinity * POW2(UT) / 5.0;
26894 }
26895 m_fvBndryCnd->m_deltaP = m_deltaP;
26896 }
26897 break;
26898 }
26899 case 45300: {
26900 if(!m_restart) {
26901 m_rhoInfinity = F1;
26902 m_PInfinity = sysEqn().p_Ref();
26903 m_UInfinity = m_Ma;
26904 m_TInfinity = F1;
26905 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
26906 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
26907 m_rhoEInfinity = m_PInfinity / gammaMinusOne + F1B2 * m_rhoInfinity * POW2(UT);
26908 m_hInfinity = m_PInfinity / m_rhoInfinity * m_gamma / gammaMinusOne;
26909 }
26910 break;
26911 }
26912 default:
26913 break;
26914 }
26915}
26916
26923template <MInt nDim_, class SysEqn>
26925 TRACE();
26926
26927 const MInt noPVars = PV->noVariables;
26928 const MInt noCVars = CV->noVariables;
26929 const MFloat gammaMinusOne = m_gamma - 1.0;
26930 const MFloat FgammaMinusOne = F1 / gammaMinusOne;
26931
26945 MBool interpolateSolutionFromStructured = false;
26946 interpolateSolutionFromStructured = Context::getSolverProperty<MBool>("interpolateSolutionFromStructured", m_solverId,
26947 AT_, &interpolateSolutionFromStructured);
26948 if(interpolateSolutionFromStructured) {
26949 if(m_restart) mTerm(1, AT_, "'restart' and 'interpolateSolutionFromStructured' activated at the same time!");
26950 readRANSProfile(this);
26951 computeConservativeVariables();
26952 if(m_initialCondition != 999) {
26953 if(domainId() == 0)
26954 cout << "\033[0;31m#### WARNING:\033[0m 'interpolateSolutionFromStructured' is set and 'initialCondition!=999'!"
26955 << endl;
26956 m_log << "WARNING: 'interpolateSolutionFromStructured' is set and 'initialCondition!=999'!" << endl;
26957 }
26958 }
26959
26960 // initialize the flow field i.e. the variables in all cells
26961 // at this point no properties should be set anymore!
26962 // TODO labels:FV,DOC cleanup the initialConditions and move properties-setting to the case statement above!
26963 if((!m_restart && !m_resetInitialCondition)) {
26964 // inflow condition
26965 // ----------------
26966 switch(m_initialCondition) {
26967 case 999: {
26968 break;
26969 }
26970
26971 // zero velocity, temperature driven flow for detailed chemistry
26972 case 11213: {
26973 ASSERT(isDetChem<SysEqn>, "Only compatible with detailed chemistry equation system");
26974 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
26975 std::vector<MFloat> PVars(nDim + 2 + m_noSpecies, F0);
26976
26977 PVars[PV->P] = m_detChem.infPressure;
26978
26979 for(MInt s = 0; s < m_noSpecies; s++) {
26980 PVars[PV->Y[s]] = m_oneDimFlame->m_profile.massFractions[s];
26981 }
26982
26983 MFloat T = m_oneDimFlame->m_profile.temperature[0];
26984
26985 for(MInt i = 0; i < nDim; i++) {
26986 PVars[PV->VV[i]] = F0;
26987 }
26988
26989 MFloat FmeanMolarWeight = F0, meanMolarWeight = F0;
26990
26991 for(MInt s = 0; s < m_noSpecies; s++) {
26992 FmeanMolarWeight += PVars[PV->Y[s]] * m_fMolarMass[s];
26993 }
26994 meanMolarWeight = F1 / FmeanMolarWeight;
26995
26996 PVars[PV->RHO] = PVars[PV->P] / T * meanMolarWeight / m_gasConstant;
26997
26998 a_variable(cellId, CV->RHO) = PVars[PV->RHO];
26999
27000 for(MInt i = 0; i < nDim; i++) {
27001 a_variable(cellId, CV->RHO_VV[i]) = F0;
27002 }
27003
27004 IF_CONSTEXPR(isDetChem<SysEqn> && hasE<SysEqn>) {
27005 MFloat sensibleEnergy = F0;
27006 sysEqn().evaluateSensibleEnergy(sensibleEnergy, &PVars[0], meanMolarWeight);
27007 a_variable(cellId, CV->RHO_E) = PVars[PV->RHO] * sensibleEnergy;
27008 }
27009
27010 for(MInt s = 0; s < m_noSpecies; ++s) {
27011 a_variable(cellId, CV->RHO_Y[s]) = PVars[PV->RHO] * PVars[PV->Y[s]];
27012 }
27013 }
27014
27015 break;
27016 }
27017 case 11212: {
27018 const MInt mainAxis = 0;
27019 const MFloat gasConstant = m_gasConstant;
27020 const MFloat fixedTemperatureLocation = m_oneDimFlame->m_fixedTemperatureLocation;
27021 const MInt oneDGridSize = m_oneDimFlame->m_grid.size();
27022
27023 // Change such that fixedTemperatureLocation has the local coordinate 0
27024 // Then move to the local 2D/3D coordinate system (main axis conforming)
27025 std::vector<MFloat> transformedGrid(oneDGridSize, F0);
27026
27027 MInt numberPerturbations = 0;
27028 MBool perturbedFlameFront = false;
27029
27030 if(Context::propertyExists("perturbedFlameFront", m_solverId))
27031 perturbedFlameFront = Context::getSolverProperty<MBool>("perturbedFlameFront", m_solverId, AT_);
27032
27033 // Allows perturbation of flame front
27034 if(perturbedFlameFront)
27035 numberPerturbations = Context::propertyLength("flameFrontPerturbationAmplitude", m_solverId);
27036
27037 std::vector<MFloat> flameFrontPerturbationAmplitude(numberPerturbations, F0);
27038 std::vector<MFloat> flameFrontPerturbationWaveLength(numberPerturbations, F0);
27039
27040 for(MInt i = 0; i < numberPerturbations; ++i) {
27041 flameFrontPerturbationAmplitude[i] =
27042 Context::getSolverProperty<MFloat>("flameFrontPerturbationAmplitude", m_solverId, AT_, i);
27043 flameFrontPerturbationWaveLength[i] =
27044 Context::getSolverProperty<MFloat>("flameFrontPerturbationWaveLength", m_solverId, AT_, i);
27045 }
27046
27047 for(MInt i = 0; i < oneDGridSize; ++i) {
27048 transformedGrid[i] = m_oneDimFlame->m_grid[i] - fixedTemperatureLocation;
27049 }
27050
27051 const MFloat oneDGridMin = m_oneDimFlame->m_grid[0] - fixedTemperatureLocation;
27052 const MFloat oneDGridMax = transformedGrid[oneDGridSize - 1];
27053
27054 // set inifinity values
27055 m_TInfinity = m_detChem.infTemperature;
27056
27057 MFloat UT = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[0];
27058 m_UInfinity = UT * cos(m_angle[0]) * cos(m_angle[1]);
27059 m_VInfinity = UT * sin(m_angle[0]) * cos(m_angle[1]);
27060 IF_CONSTEXPR(nDim == 3) m_WInfinity = UT * sin(m_angle[1]);
27061
27062 m_VVInfinity[0] = m_UInfinity;
27063 m_VVInfinity[1] = m_VInfinity;
27064 IF_CONSTEXPR(nDim == 3) m_VVInfinity[2] = m_WInfinity;
27065
27066 m_PInfinity = m_detChem.infPressure;
27067
27068 MFloat fMeanMolarWeightInfinity = F0;
27069 for(MInt s = 0; s < m_noSpecies; s++) {
27070 fMeanMolarWeightInfinity += m_YInfinity[s] * m_fMolarMass[s];
27071 }
27072
27073 MFloat meanMolarWeightInfinity = F1 / fMeanMolarWeightInfinity;
27074
27075 m_rhoInfinity = m_PInfinity * meanMolarWeightInfinity / gasConstant / m_detChem.infTemperature;
27076
27077 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
27078 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
27079 IF_CONSTEXPR(nDim == 3) m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
27080
27081 m_rhoVVInfinity[0] = m_rhoUInfinity;
27082 m_rhoVVInfinity[1] = m_rhoVInfinity;
27083 IF_CONSTEXPR(nDim == 3) m_rhoVVInfinity[2] = m_rhoWInfinity;
27084
27085 std::vector<MFloat> PVars(nDim + 2 + m_noSpecies, F0);
27086 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27087 // Coordinate in main axis direction
27088 MFloat coord = a_coordinate(cellId, mainAxis);
27089 MFloat tCoord = a_coordinate(cellId, 1);
27090
27091 for(MInt i = 0; i < numberPerturbations; i++) {
27092 MFloat wavenumber = F2 * PI / (flameFrontPerturbationWaveLength[i]);
27093 coord +=
27094 flameFrontPerturbationAmplitude[i] * m_oneDimFlame->m_laminarFlameThickness * sin(wavenumber * tCoord);
27095 }
27096
27097 MFloat FmeanMolarWeight = F0;
27098 MFloat meanMolarWeight = F0;
27099 MFloat T, VV;
27100
27101 PVars[PV->P] = m_detChem.infPressure;
27102
27103 // cell is in unburnt state (index 0)
27104 if(coord < oneDGridMin) {
27105 for(MInt s = 0; s < m_noSpecies; s++) {
27106 PVars[PV->Y[s]] = m_oneDimFlame->m_profile.massFractions[s];
27107 }
27108 T = m_oneDimFlame->m_profile.temperature[0];
27109 VV = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[0];
27110
27111 // cell is in completely burnt state (index oneDGridSize - 1)
27112 } else if(coord > oneDGridMax) {
27113 for(MInt s = 0; s < m_noSpecies; s++) {
27114 PVars[PV->Y[s]] = m_oneDimFlame->m_profile.massFractions[(oneDGridSize - 1) * m_noSpecies + s];
27115 }
27116 T = m_oneDimFlame->m_profile.temperature[oneDGridSize - 1];
27117 VV = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[oneDGridSize - 1];
27118
27119 // cell is inside flame front
27120 } else {
27121 // binary search
27122 auto lowerBound = std::lower_bound(transformedGrid.begin(), transformedGrid.end(), coord);
27123 auto upperBound = std::upper_bound(transformedGrid.begin(), transformedGrid.end(), coord);
27124
27125 MInt n0 = lowerBound - transformedGrid.begin() - 1;
27126 MInt n1 = upperBound - transformedGrid.begin();
27127
27128 MFloat x0 = transformedGrid[n0];
27129 MFloat x1 = transformedGrid[n1];
27130
27131 MInt offset0 = m_noSpecies * n0;
27132 MInt offset1 = m_noSpecies * n1;
27133
27134 for(MInt s = 0; s < m_noSpecies; s++) {
27135 MFloat Y_k_0 = m_oneDimFlame->m_profile.massFractions[offset0 + s];
27136 MFloat Y_k_1 = m_oneDimFlame->m_profile.massFractions[offset1 + s];
27137 PVars[PV->Y[s]] = Y_k_0 + (coord - x0) / (x1 - x0) * (Y_k_1 - Y_k_0);
27138 }
27139
27140 // interpolate 1D Solution of variables on the 2D Grid based on the main axis
27141 MFloat T0 = m_oneDimFlame->m_profile.temperature[n0];
27142 MFloat T1 = m_oneDimFlame->m_profile.temperature[n1];
27143
27144 T = T0 + (coord - x0) / (x1 - x0) * (T1 - T0);
27145
27146 MFloat VV_0 = m_oneDimFlame->m_profile.velocity[n0];
27147 MFloat VV_1 = m_oneDimFlame->m_profile.velocity[n1];
27148
27149 VV = VV_0 + (coord - x0) / (x1 - x0) * (VV_1 - VV_0);
27150 VV *= m_detChem.laminarFlameSpeedFactor;
27151 }
27152
27153 for(MInt s = 0; s < m_noSpecies; s++) {
27154 FmeanMolarWeight += PVars[PV->Y[s]] * m_fMolarMass[s];
27155 }
27156 meanMolarWeight = F1 / FmeanMolarWeight;
27157
27158 PVars[PV->RHO] = PVars[PV->P] / T * meanMolarWeight / gasConstant;
27159
27160 a_variable(cellId, CV->RHO) = PVars[PV->RHO];
27161
27162 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
27163 if(spaceId == mainAxis) {
27164 PVars[CV->RHO_VV[spaceId]] = VV;
27165 a_variable(cellId, CV->RHO_VV[spaceId]) = PVars[PV->RHO] * VV;
27166 } else {
27167 PVars[CV->RHO_VV[spaceId]] = F0;
27168 a_variable(cellId, CV->RHO_VV[spaceId]) = F0;
27169 }
27170 }
27171
27172 IF_CONSTEXPR(isDetChem<SysEqn> && hasE<SysEqn>) {
27173 MFloat sensibleEnergy = F0;
27174 sysEqn().evaluateSensibleEnergy(sensibleEnergy, &PVars[0], meanMolarWeight);
27175 a_variable(cellId, CV->RHO_E) = PVars[PV->RHO] * sensibleEnergy + 0.5 * PVars[PV->RHO] * POW2(VV);
27176 }
27177
27178 for(MInt s = 0; s < m_noSpecies; ++s) {
27179 a_variable(cellId, CV->RHO_Y[s]) = PVars[PV->RHO] * PVars[PV->Y[s]];
27180 }
27181 }
27182
27183 break;
27184 }
27185
27186 /*
27187 Initial condition for real burner geometry, 2D. Gas sinside the tube is initialized from the 1D-solution of a
27188 precomputed flame, and outside it is initialized as burnt gas with 0 velocity in all space directions.
27189 */
27190 case 112121: {
27191 const MInt mainAxis = 1;
27192 const MFloat gasConstant = m_gasConstant;
27193 const MFloat fixedTemperatureLocation = m_oneDimFlame->m_fixedTemperatureLocation;
27194 const MInt oneDGridSize = m_oneDimFlame->m_grid.size();
27195
27196 // Geometry of the burner, corner positions
27197 // MFloat corner_minus = {0.05, -0.05};
27198 // MFloat corner_plus = {0.05, 0.05};
27199
27200 // MFloat cornerY = 0.00095214849;
27201 MFloat tubeDiameter = 0.0050048822 * 2.001; // slightly bigger
27202 MFloat flamePosition = 0.00115;
27203
27204 // Change such that fixedTemperatureLocation has the local coordinate 0
27205 // Then move to the local 2D/3D coordinate system (main axis conforming)
27206 std::vector<MFloat> transformedGrid(oneDGridSize, F0);
27207
27208
27209 for(MInt i = 0; i < oneDGridSize; ++i) {
27210 transformedGrid[i] = m_oneDimFlame->m_grid[i] - fixedTemperatureLocation;
27211 }
27212
27213 const MFloat oneDGridMin = m_oneDimFlame->m_grid[0] - fixedTemperatureLocation;
27214 const MFloat oneDGridMax = transformedGrid[oneDGridSize - 1];
27215
27216 // set inifinity values
27217 m_TInfinity = m_detChem.infTemperature;
27218
27219 MFloat UT = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[0];
27220
27221 MFloat recvVel = UT;
27222 MPI_Bcast(&recvVel, 1, MPI_DOUBLE, 0, mpiComm(), AT_, "recvVel"); // ensures same value across all ranks
27223
27224 m_UInfinity = recvVel * cos(m_angle[0]) * cos(m_angle[1]);
27225 m_VInfinity = recvVel * sin(m_angle[0]) * cos(m_angle[1]);
27226 IF_CONSTEXPR(nDim == 3) m_WInfinity = recvVel * sin(m_angle[1]);
27227
27228 m_VVInfinity[0] = m_UInfinity;
27229 m_VVInfinity[1] = m_VInfinity;
27230 IF_CONSTEXPR(nDim == 3) m_VVInfinity[2] = m_WInfinity;
27231
27232 m_PInfinity = m_detChem.infPressure;
27233
27234 MFloat fMeanMolarWeightInfinity = F0;
27235 for(MInt s = 0; s < m_noSpecies; s++) {
27236 fMeanMolarWeightInfinity += m_YInfinity[s] * m_fMolarMass[s];
27237 }
27238
27239 MFloat meanMolarWeightInfinity = F1 / fMeanMolarWeightInfinity;
27240
27241 m_rhoInfinity = m_PInfinity * meanMolarWeightInfinity / gasConstant / m_detChem.infTemperature;
27242
27243 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
27244 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
27245 IF_CONSTEXPR(nDim == 3) m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
27246
27247 m_rhoVVInfinity[0] = m_rhoUInfinity;
27248 m_rhoVVInfinity[1] = m_rhoVInfinity;
27249 IF_CONSTEXPR(nDim == 3) m_rhoVVInfinity[2] = m_rhoWInfinity;
27250
27251 std::vector<MFloat> PVars(nDim + 2 + m_noSpecies, F0);
27252 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27253 // Coordinate in main axis direction
27254 MFloat coord = a_coordinate(cellId, mainAxis);
27255 MFloat tCoord = a_coordinate(cellId, 0);
27256
27257 MFloat FmeanMolarWeight = F0;
27258 MFloat meanMolarWeight = F0;
27259 MFloat T, VV;
27260
27261 PVars[PV->P] = m_detChem.infPressure;
27262
27263 // cell is in unburnt state (index 0)
27264 if(coord - flamePosition < oneDGridMin) {
27265 for(MInt s = 0; s < m_noSpecies; s++) {
27266 PVars[PV->Y[s]] = m_oneDimFlame->m_profile.massFractions[s];
27267 }
27268 T = m_oneDimFlame->m_profile.temperature[0];
27269 VV = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[0];
27270
27271 // cell is in completely burnt state (index oneDGridSize - 1)
27272 } else if(coord - flamePosition > oneDGridMax) {
27273 for(MInt s = 0; s < m_noSpecies; s++) {
27274 PVars[PV->Y[s]] = m_oneDimFlame->m_profile.massFractions[(oneDGridSize - 1) * m_noSpecies + s];
27275 }
27276 T = m_oneDimFlame->m_profile.temperature[oneDGridSize - 1];
27277 VV = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[oneDGridSize - 1];
27278
27279 // cell is inside flame front
27280 } else {
27281 const MFloat transformedCoord = coord - flamePosition;
27282 // binary search
27283 auto lowerBound = std::lower_bound(transformedGrid.begin(), transformedGrid.end(), transformedCoord);
27284 auto upperBound = std::upper_bound(transformedGrid.begin(), transformedGrid.end(), transformedCoord);
27285
27286 MInt n0 = lowerBound - transformedGrid.begin() - 1;
27287 MInt n1 = upperBound - transformedGrid.begin();
27288
27289 MFloat x0 = transformedGrid[n0];
27290 MFloat x1 = transformedGrid[n1];
27291
27292 MInt offset0 = m_noSpecies * n0;
27293 MInt offset1 = m_noSpecies * n1;
27294
27295 for(MInt s = 0; s < m_noSpecies; s++) {
27296 MFloat Y_k_0 = m_oneDimFlame->m_profile.massFractions[offset0 + s];
27297 MFloat Y_k_1 = m_oneDimFlame->m_profile.massFractions[offset1 + s];
27298 PVars[PV->Y[s]] = Y_k_0 + (transformedCoord - x0) / (x1 - x0) * (Y_k_1 - Y_k_0);
27299 }
27300
27301 // interpolate 1D Solution of variables on the 2D Grid based on the main axis
27302 MFloat T0 = m_oneDimFlame->m_profile.temperature[n0];
27303 MFloat T1 = m_oneDimFlame->m_profile.temperature[n1];
27304
27305 T = T0 + (transformedCoord - x0) / (x1 - x0) * (T1 - T0);
27306
27307 MFloat VV_0 = m_oneDimFlame->m_profile.velocity[n0];
27308 MFloat VV_1 = m_oneDimFlame->m_profile.velocity[n1];
27309
27310 VV = VV_0 + (transformedCoord - x0) / (x1 - x0) * (VV_1 - VV_0);
27311 VV *= m_detChem.laminarFlameSpeedFactor;
27312 }
27313
27314 if(abs(tCoord) > tubeDiameter / F2) {
27315 for(MInt s = 0; s < m_noSpecies; s++) {
27316 PVars[PV->Y[s]] = m_oneDimFlame->m_profile.massFractions[(oneDGridSize - 1) * m_noSpecies + s];
27317 }
27318 T = m_oneDimFlame->m_profile.temperature[oneDGridSize - 1];
27319 // VV = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[oneDGridSize - 1];
27320 VV = F0;
27321 }
27322
27323 // override velocity component above given point
27324 if(coord > 0.001) {
27325 VV = F0;
27326 }
27327
27328 for(MInt s = 0; s < m_noSpecies; s++) {
27329 FmeanMolarWeight += PVars[PV->Y[s]] * m_fMolarMass[s];
27330 }
27331 meanMolarWeight = F1 / FmeanMolarWeight;
27332
27333 PVars[PV->RHO] = PVars[PV->P] / T * meanMolarWeight / gasConstant;
27334
27335 a_variable(cellId, CV->RHO) = PVars[PV->RHO];
27336
27337 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
27338 if(spaceId == mainAxis) {
27339 PVars[CV->RHO_VV[spaceId]] = VV;
27340 a_variable(cellId, CV->RHO_VV[spaceId]) = PVars[PV->RHO] * VV;
27341 } else {
27342 PVars[CV->RHO_VV[spaceId]] = F0;
27343 a_variable(cellId, CV->RHO_VV[spaceId]) = F0;
27344 }
27345 }
27346
27347 IF_CONSTEXPR(isDetChem<SysEqn> && hasE<SysEqn>) {
27348 MFloat sensibleEnergy = F0;
27349 sysEqn().evaluateSensibleEnergy(sensibleEnergy, &PVars[0], meanMolarWeight);
27350 a_variable(cellId, CV->RHO_E) = PVars[PV->RHO] * sensibleEnergy + 0.5 * PVars[PV->RHO] * POW2(VV);
27351 }
27352
27353 for(MInt s = 0; s < m_noSpecies; ++s) {
27354 a_variable(cellId, CV->RHO_Y[s]) = PVars[PV->RHO] * PVars[PV->Y[s]];
27355 }
27356 }
27357
27358 break;
27359 }
27360
27361 // slit flame geometry, no combustion, cold gas
27362 case 112122: {
27363 const MInt mainAxis = 1;
27364 const MFloat gasConstant = m_gasConstant;
27365
27366 MFloat tubeDiameter = 0.0050048822 * 2.001; // slightly bigger
27367
27368 // set inifinity values
27369 m_TInfinity = m_detChem.infTemperature;
27370
27371 MFloat UT = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[0];
27372 m_UInfinity = UT * cos(m_angle[0]) * cos(m_angle[1]);
27373 m_VInfinity = UT * sin(m_angle[0]) * cos(m_angle[1]);
27374 IF_CONSTEXPR(nDim == 3) m_WInfinity = UT * sin(m_angle[1]);
27375
27376 m_VVInfinity[0] = m_UInfinity;
27377 m_VVInfinity[1] = m_VInfinity;
27378 IF_CONSTEXPR(nDim == 3) m_VVInfinity[2] = m_WInfinity;
27379
27380 m_PInfinity = m_detChem.infPressure;
27381
27382 MFloat fMeanMolarWeightInfinity = F0;
27383 for(MInt s = 0; s < m_noSpecies; s++) {
27384 fMeanMolarWeightInfinity += m_YInfinity[s] * m_fMolarMass[s];
27385 }
27386
27387 MFloat meanMolarWeightInfinity = F1 / fMeanMolarWeightInfinity;
27388
27389 m_rhoInfinity = m_PInfinity * meanMolarWeightInfinity / gasConstant / m_detChem.infTemperature;
27390
27391 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
27392 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
27393 IF_CONSTEXPR(nDim == 3) m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
27394
27395 m_rhoVVInfinity[0] = m_rhoUInfinity;
27396 m_rhoVVInfinity[1] = m_rhoVInfinity;
27397 IF_CONSTEXPR(nDim == 3) m_rhoVVInfinity[2] = m_rhoWInfinity;
27398
27399 std::vector<MFloat> PVars(nDim + 2 + m_noSpecies, F0);
27400 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27401 // Coordinate in main axis direction
27402 // MFloat coord = a_coordinate(cellId, mainAxis);
27403 MFloat tCoord = a_coordinate(cellId, 0);
27404
27405
27406 MFloat FmeanMolarWeight = F0;
27407 MFloat meanMolarWeight = F0;
27408 MFloat T, VV;
27409
27410 PVars[PV->P] = m_detChem.infPressure;
27411
27412 // unburnt state (index 0)
27413 for(MInt s = 0; s < m_noSpecies; s++) {
27414 PVars[PV->Y[s]] = m_oneDimFlame->m_profile.massFractions[s];
27415 }
27416 T = m_oneDimFlame->m_profile.temperature[0];
27417 VV = m_detChem.laminarFlameSpeedFactor * m_oneDimFlame->m_profile.velocity[0];
27418
27419
27420 if(abs(tCoord) > tubeDiameter / F2) {
27421 VV = F0;
27422 }
27423
27424 for(MInt s = 0; s < m_noSpecies; s++) {
27425 FmeanMolarWeight += PVars[PV->Y[s]] * m_fMolarMass[s];
27426 }
27427 meanMolarWeight = F1 / FmeanMolarWeight;
27428
27429 PVars[PV->RHO] = PVars[PV->P] / T * meanMolarWeight / gasConstant;
27430
27431 a_variable(cellId, CV->RHO) = PVars[PV->RHO];
27432
27433 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
27434 if(spaceId == mainAxis) {
27435 PVars[CV->RHO_VV[spaceId]] = VV;
27436 a_variable(cellId, CV->RHO_VV[spaceId]) = PVars[PV->RHO] * VV;
27437 } else {
27438 PVars[CV->RHO_VV[spaceId]] = F0;
27439 a_variable(cellId, CV->RHO_VV[spaceId]) = F0;
27440 }
27441 }
27442
27443 IF_CONSTEXPR(isDetChem<SysEqn> && hasE<SysEqn>) {
27444 MFloat sensibleEnergy = F0;
27445 sysEqn().evaluateSensibleEnergy(sensibleEnergy, &PVars[0], meanMolarWeight);
27446 a_variable(cellId, CV->RHO_E) = PVars[PV->RHO] * sensibleEnergy + 0.5 * PVars[PV->RHO] * POW2(VV);
27447 }
27448
27449 for(MInt s = 0; s < m_noSpecies; ++s) {
27450 a_variable(cellId, CV->RHO_Y[s]) = PVars[PV->RHO] * PVars[PV->Y[s]];
27451 }
27452 }
27453
27454 saveDebugRestartFile();
27455
27456 break;
27457 }
27458
27459 case 0:
27460 case 465: {
27461 MFloat rho = m_rhoInfinity;
27462 if(Context::propertyExists("initialDensity", m_solverId)) {
27463 rho = Context::getSolverProperty<MFloat>("initialDensity", m_solverId, AT_);
27464 }
27465 IF_CONSTEXPR(hasE<SysEqn>) {
27466 MFloat rhoE = m_rhoEInfinity;
27467 if(Context::propertyExists("initialPressure", m_solverId)) {
27468 const MFloat p = Context::getSolverProperty<MFloat>("initialPressure", m_solverId, AT_);
27469 rhoE = sysEqn().internalEnergy(p, rho, 0);
27470 }
27471 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27472 a_variable(cellId, CV->RHO_E) = rhoE;
27473 }
27474 }
27475
27476 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27477 a_variable(cellId, CV->RHO) = rho;
27478
27479 for(MInt dir = 0; dir < nDim; dir++) {
27480 a_variable(cellId, CV->RHO_VV[dir]) = m_rhoVVInfinity[dir];
27481 }
27482
27483 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
27484 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
27485 a_variable(cellId, CV->RHO_N) = m_rhoInfinity * m_nuTildeInfinity;
27486 }
27487 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
27488 a_variable(cellId, CV->RHO_K) = m_rhoInfinity * m_kInfinity;
27489 a_variable(cellId, CV->RHO_OMEGA) = m_rhoInfinity * m_omegaInfinity;
27490 }
27491 }
27492
27493 for(MInt s = 0; s < m_noSpecies; s++) {
27494 a_variable(cellId, CV->RHO_Y[s]) = 0.0;
27495 }
27496 }
27497 break;
27498 }
27499
27500 case 9465: // initial condition 465 adapted for LB-FV-EEGas
27501 case 90: { // initial condition 0 adapted for LB-FV-EEGas
27502 IF_CONSTEXPR(!isEEGas<SysEqn>) { mTerm(1, AT_, "Initial condition for Euler-Euler Simulations!"); }
27503 else {
27504 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
27505 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
27506 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
27507 const MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
27508 a_alphaGas(ghostCellId) = a_alphaGas(cellId);
27509 }
27510 }
27511 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27512 MFloat alpha = 1.0;
27513 MFloat p = m_PInfinity;
27514 MFloat rho = m_rhoInfinity;
27515
27516 alpha = a_alphaGas(cellId);
27517 p = a_pvariable(cellId, PV->P);
27518 if(p < 1e-8 || isnan(p)) {
27519 p = m_PInfinity;
27520 }
27521 rho *= p / m_PInfinity;
27522
27523 if(hasAV) {
27524 for(MInt i = 0; i < 3; i++) {
27525 rho += a_avariable(cellId, AV->DC);
27526 }
27527 }
27528
27529 a_variable(cellId, CV->A_RHO) = rho * alpha;
27530
27531 for(MInt dir = 0; dir < nDim; dir++) {
27532 MFloat rhoV = m_rhoVVInfinity[dir] / m_rhoInfinity * rho;
27533 rhoV *= p / m_PInfinity;
27534 a_variable(cellId, CV->A_RHO_VV[dir]) = rhoV * alpha;
27535 }
27536 a_pvariable(cellId, PV->RHO) = rho;
27537 a_pvariable(cellId, PV->P) = p;
27538 }
27539 }
27540 break;
27541 }
27542 case 33: {
27543 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27544 a_variable(cellId, CV->RHO) = F1;
27545 IF_CONSTEXPR(hasE<SysEqn>)
27546 a_variable(cellId, CV->RHO_E) = sysEqn().pressureEnergy(sysEqn().p_Ref());
27547 for(MInt dir = 0; dir < nDim; dir++) {
27548 a_variable(cellId, CV->RHO_VV[dir]) = F0;
27549 }
27550 for(MInt s = 0; s < m_noSpecies; s++) {
27551 a_variable(cellId, CV->RHO_Y[s]) = 0.5;
27552 }
27553 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
27554 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
27555 a_variable(cellId, CV->RHO_N) = m_rhoInfinity * m_nuTildeInfinity;
27556 }
27557 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
27558 a_variable(cellId, CV->RHO_K) = m_rhoInfinity * m_kInfinity;
27559 a_variable(cellId, CV->RHO_OMEGA) = m_rhoInfinity * m_omegaInfinity;
27560 }
27561 }
27562 }
27563 break;
27564 }
27565 case 123: {
27566 m_MaHg = Context::getSolverProperty<MFloat>("Ma_Hg", m_solverId, AT_);
27567 m_THg = sysEqn().temperature_IR(m_MaHg);
27568 m_UHg = m_MaHg * sqrt(m_THg);
27569 m_VHg = F0;
27570 m_WHg = F0;
27571 m_PHg = sysEqn().pressure_IR(m_THg);
27572 m_rhoHg = sysEqn().density_IR(m_THg);
27573
27574 // Cavity
27575 m_MaCg = Context::getSolverProperty<MFloat>("Ma_Cg", m_solverId, AT_);
27576 m_TCg = sysEqn().temperature_IR(m_MaCg);
27577 m_UCg = m_MaCg * sqrt(m_TCg);
27578 m_VCg = F0;
27579 m_WCg = F0;
27580 m_PCg = sysEqn().pressure_IR(m_TCg);
27581 m_rhoCg = sysEqn().density_IR(m_TCg);
27582
27583 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27584 a_variable(cellId, CV->RHO) = m_rhoInfinity;
27585 IF_CONSTEXPR(hasE<SysEqn>)
27586 a_variable(cellId, CV->RHO_E) = m_rhoEInfinity;
27587
27588 for(MInt dir = 0; dir < nDim; dir++) {
27589 a_variable(cellId, CV->RHO_VV[dir]) = m_rhoVVInfinity[dir];
27590 }
27591
27592 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
27593 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
27594 a_variable(cellId, CV->RHO_N) = m_rhoInfinity * m_nuTildeInfinity;
27595 }
27596 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_KOMEGA || SysEqn::m_ransModel == RANS_SST) {
27597 a_variable(cellId, PV->K) = m_kInfinity;
27598 a_variable(cellId, PV->OMEGA) = m_omegaInfinity;
27599 }
27600 }
27601
27602 for(MInt s = 0; s < m_noSpecies; s++) {
27603 a_variable(cellId, CV->RHO_Y[s]) = 0.0;
27604 }
27605 }
27606 break;
27607 }
27608
27609 case 124: {
27610 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27611 a_pvariable(cellId, PV->RHO) = m_rhoInfinity;
27612 a_pvariable(cellId, PV->P) = m_PInfinity;
27613 for(MInt dir = 0; dir < nDim; dir++) {
27614 a_pvariable(cellId, PV->VV[dir]) = m_VVInfinity[dir];
27615 }
27616
27617 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
27618 IF_CONSTEXPR(SysEqn::m_ransModel == RANS_SA_DV || SysEqn::m_ransModel == RANS_FS) {
27619 // a_variable(cellId, PV->N) = m_nuTildeInfinity;
27620 MFloat r = sqrt(POW2(a_coordinate(cellId, 1)) + POW2(a_coordinate(cellId, 2)));
27621 a_pvariable(cellId, PV->N) = m_nuTildeInfinity + 10.0 * ((r - 114.2) * exp(-0.06 * pow(r - 114.2, F2)));
27622 a_pvariable(cellId, PV->VV[0]) = m_UInfinity * (1 - pow((r - 145.1) / 31.2, 10.0));
27623 }
27624 }
27625
27626 for(MInt s = 0; s < m_noSpecies; s++) {
27627 a_pvariable(cellId, PV->Y[s]) = 0.0;
27628 }
27629 }
27630 computeConservativeVariables();
27631 break;
27632 }
27633
27634 case 45300: {
27635 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27636 // quiescent flow field
27637 a_variable(cellId, CV->RHO) = m_rhoInfinity;
27638
27639 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
27640 a_variable(cellId, CV->RHO_VV[spaceId]) = F0;
27641 }
27642
27643 IF_CONSTEXPR(hasE<SysEqn>)
27644 a_variable(cellId, CV->RHO_E) = m_PInfinity / gammaMinusOne;
27645 }
27646 break;
27647 }
27648
27649 // strong shock aligned with y axis
27650 case 77: {
27651 MInt SA = nDim;
27652 SA = Context::getSolverProperty<MInt>("shockAlignment", m_solverId, AT_, &SA);
27653
27654 if(SA == nDim) mTerm(1, AT_, "shockAlignment not set");
27663 MFloat shockCoord = Context::getSolverProperty<MFloat>("shockCoord", m_solverId, AT_, &shockCoord);
27664
27665 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27666 if(a_coordinate(cellId, SA) < shockCoord) {
27667 // preshock
27668 a_variable(cellId, CV->RHO) = m_rhoInfinity;
27669 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
27670 a_variable(cellId, CV->RHO_VV[spaceId]) = m_rhoVVInfinity[spaceId];
27671 }
27672 IF_CONSTEXPR(hasE<SysEqn>)
27673 a_variable(cellId, CV->RHO_E) = m_rhoEInfinity;
27674 } else {
27675 // postshock
27676 for(MInt var = 0; var < noCVars; var++) {
27677 a_variable(cellId, var) = m_postShockCV[var];
27678 }
27679 }
27680 }
27681 break;
27682 }
27683
27684 // linear shear flow
27685 case 466: {
27686 // infinity state is updated here, since particles are initialised
27687 // on different infinity variables then the flow field!
27688 m_rhoInfinity = F1;
27689 m_TInfinity = F1;
27690 m_PInfinity = sysEqn().pressure_ES(m_TInfinity, m_rhoInfinity);
27691 m_UInfinity = m_Ma;
27692 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
27693 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
27694 m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
27695 m_rhoEInfinity = sysEqn().internalEnergy(m_PInfinity, m_rhoInfinity, POW2(m_UInfinity));
27696 m_hInfinity = sysEqn().enthalpy(m_PInfinity, m_rhoInfinity);
27697 sysEqn().m_Re0 = m_Re * SUTHERLANDLAW(m_TInfinity) / (m_rhoInfinity * m_UInfinity);
27698 m_timeRef = m_Ma;
27699
27700 MFloat bbox[2 * nDim];
27701 m_geometry->getBoundingBox(&bbox[0]);
27702
27703 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27704 const MFloat vel = F2 * m_UInfinity * a_coordinate(cellId, 1) / (bbox[1 + nDim] - bbox[1]);
27705 a_variable(cellId, CV->RHO) = m_rhoInfinity;
27706 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
27707 a_variable(cellId, CV->RHO_VV[spaceId]) = F0;
27708 }
27709 a_variable(cellId, CV->RHO_U) = m_rhoInfinity * vel;
27710 IF_CONSTEXPR(hasE<SysEqn>)
27711 a_variable(cellId, CV->RHO_E) = m_PInfinity / gammaMinusOne + F1B2 * m_rhoInfinity * POW2(vel);
27712 }
27713 break;
27714 }
27715
27716 // Note: never used in 2D; this IC is from fvsolver3d
27717 case 8111: {
27718 IF_CONSTEXPR(nDim == 2) {
27719 mTerm(-1, "This IC has been never used in 2D! If you are sure that it works uncomment "
27720 "this warning.");
27721 }
27722 m_log << "Initial condition 81 maps a solution off a source grid (incl. partition level "
27723 "shift) on a target grid";
27724 m_log << "using nearest neighbor data" << endl;
27725
27726 if(ParallelIo::fileExists("out/restartVariables_0.Netcdf", mpiComm())) {
27727 m_log << "get data from own grid" << endl;
27728 // File loading.
27729 stringstream variables;
27730
27731 ParallelIo parallelIo("out/restartVariables_0.Netcdf", maia::parallel_io::PIO_READ, mpiComm());
27732
27733 // This should be the same for all the variables
27734 ParallelIo::size_type dimLen = noInternalCells();
27735 ParallelIo::size_type start = domainOffset(domainId());
27736
27737 // set offset for all read operations
27738 parallelIo.setOffset(dimLen, start);
27739
27740 // Load our variables
27741
27742 { // Velocity u
27743 MFloatScratchSpace tmp_velocityU((MInt)dimLen, AT_, "tmp_velocityU");
27744 parallelIo.readArray(tmp_velocityU.getPointer(), "variables0");
27745 for(MInt i = 0; i < (MInt)dimLen; ++i) {
27746 a_pvariable(i, PV->U) = tmp_velocityU.p[i];
27747 }
27748 }
27749
27750 { // Velocity v
27751 MFloatScratchSpace tmp_velocityV((MInt)dimLen, AT_, "tmp_velocityV");
27752 parallelIo.readArray(tmp_velocityV.getPointer(), "variables1");
27753 for(MInt i = 0; i < (MInt)dimLen; ++i) {
27754 a_pvariable(i, PV->V) = tmp_velocityV.p[i];
27755 }
27756 }
27757
27758 IF_CONSTEXPR(nDim == 3) {
27759 // Velocity w
27760 MFloatScratchSpace tmp_velocityW((MInt)dimLen, AT_, "tmp_velocityW");
27761 parallelIo.readArray(tmp_velocityW.getPointer(), "variables2");
27762 for(MInt i = 0; i < (MInt)dimLen; ++i) {
27763 a_pvariable(i, PV->W) = tmp_velocityW.p[i];
27764 }
27765 }
27766
27767 { // Density rho
27768 MFloatScratchSpace tmp_rho((MInt)dimLen, AT_, "tmp_rho");
27769 parallelIo.readArray(tmp_rho.getPointer(), "variables3");
27770 for(MInt i = 0; i < (MInt)dimLen; ++i) {
27771 a_pvariable(i, PV->RHO) = tmp_rho.p[i];
27772 }
27773 }
27774
27775 { // pressure p
27776 MFloatScratchSpace tmp_p((MInt)dimLen, AT_, "tmp_p");
27777 parallelIo.readArray(tmp_p.getPointer(), "variables4");
27778 for(MInt i = 0; i < (MInt)dimLen; ++i) {
27779 a_pvariable(i, PV->P) = tmp_p.p[i];
27780 }
27781 }
27782
27783 MPI_Barrier(mpiComm(), AT_);
27784 m_log << " reading done" << endl;
27785
27786 exchangeAll();
27787
27788 MPI_Barrier(mpiComm(), AT_);
27789 m_log << "exchange done" << endl;
27790
27791 computeConservativeVariables();
27792
27793 MPI_Barrier(mpiComm(), AT_);
27794 m_log << "computeConservativeVariables done" << endl;
27795
27796 LSReconstructCellCenter();
27797
27798 break;
27799 }
27800 m_log << "get data from other grid" << endl;
27801
27802 // initialize
27803 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
27804 // parallel inflow field
27805 a_pvariable(cellId, PV->RHO) = m_rhoInfinity;
27806 for(MInt i = 0; i < nDim; i++)
27807 a_pvariable(cellId, PV->VV[i]) = m_VVInfinity[i];
27808 a_pvariable(cellId, PV->P) = m_PInfinity;
27809 }
27810
27811 // if nearest == 1, the nearest leaf is found, otherwise an inside check is performed,
27812 // which may result in an endless loop
27813 // MInt nearestLeaf = 1;
27814 MInt maxNoCellsToRead = 5 * maxNoGridCells();
27815
27816 // create src grid
27817 ParallelIo srcGrid("src/grid.Netcdf", maia::parallel_io::PIO_READ, mpiComm());
27818
27819
27831 // what src file are we dealing with
27832 MInt srcFileType = 0;
27833 srcFileType = Context::getSolverProperty<MInt>("srcFileType", m_solverId, AT_, &srcFileType);
27834
27835 // src noCells
27836 MInt srcNoCells;
27837 srcGrid.readScalar(&srcNoCells, "noCells");
27838
27839 // - stuff that might needs to be hardcoded for some src grids
27840 MFloat srcLengthLevel0;
27841 MFloat srcCenterOfGravity[nDim];
27842 MInt srcMinLevel;
27843 MInt srcMaxLevel;
27844 MFloat fileTypeFac;
27845 if(srcFileType == 1) { // Thomas
27846 IF_CONSTEXPR(nDim == 2) mTerm(1, AT_, "Not for 2D!");
27847 srcLengthLevel0 = 3.5000000032596290112;
27848 srcCenterOfGravity[0] = 0.021997896999999988488;
27849 srcCenterOfGravity[1] = 0.0;
27850 srcCenterOfGravity[2] = 0.0;
27851 fileTypeFac = 100.0;
27852 srcMinLevel = 9;
27853 srcMaxLevel = 11;
27854 } else if(srcFileType == 2) { // Thomas
27855 IF_CONSTEXPR(nDim == 2) mTerm(1, AT_, "Not for 2D!");
27856 srcLengthLevel0 = 3.0000000027939677238;
27857 srcCenterOfGravity[0] = 0.021997896999999988488;
27858 srcCenterOfGravity[1] = 0.0;
27859 srcCenterOfGravity[2] = 0.0;
27860 fileTypeFac = 100.0;
27861 srcMinLevel = 9;
27862 srcMaxLevel = 14;
27863 } else if(srcFileType == 3) { // Thomas
27864 IF_CONSTEXPR(nDim == 2) mTerm(1, AT_, "Not for 2D!");
27865 srcGrid.readScalar(&srcLengthLevel0, "lengthLevel0");
27866 srcGrid.readScalar(&(srcCenterOfGravity[0]), "CX");
27867 srcGrid.readScalar(&(srcCenterOfGravity[1]), "CY");
27868 srcGrid.readScalar(&(srcCenterOfGravity[2]), "CZ");
27869 fileTypeFac = 100.0;
27870 srcMinLevel = -1;
27871 srcMaxLevel = -1;
27872 } else { // all
27873 srcGrid.setOffset(nDim, 0);
27874 srcGrid.readArray(&(srcCenterOfGravity[0]), "centerOfGravity");
27875 srcGrid.readScalar(&srcLengthLevel0, "lengthLevel0");
27876 srcGrid.readScalar(&srcMinLevel, "minLevel");
27877 srcGrid.readScalar(&srcMaxLevel, "maxLevel");
27878 fileTypeFac = F1;
27879 }
27880
27881 srcLengthLevel0 *= fileTypeFac;
27882 for(MInt dim = 0; dim < nDim; dim++)
27883 srcCenterOfGravity[dim] *= fileTypeFac;
27884
27885 m_log << "srcLengthLevel0 = " << srcLengthLevel0 << endl;
27886 for(MInt dim = 0; dim < nDim; dim++)
27887 m_log << "srcCenterOfGravity[" << dim << "] = " << srcCenterOfGravity[dim] << endl;
27888
27889 MInt srcNmbrPartitionCells = (MInt)srcGrid.getArraySize("partitionCellsId");
27890 MIntScratchSpace srcPartitionCellsGlobalId(srcNmbrPartitionCells + 1, AT_, "srcPartitionCellsGlobalId");
27891 srcGrid.setOffset(srcNmbrPartitionCells, 0);
27892 srcGrid.readArray(srcPartitionCellsGlobalId.begin(), "partitionCellsId");
27893 srcPartitionCellsGlobalId(srcNmbrPartitionCells) = srcNoCells;
27894
27895 // src structure, generated once and then saved to an auxiliary file
27896 // "src/srcPartitionCellsHilbertId"
27898 multiset<MInt> srcPartitionCellHilbertIds;
27900 vector<multimap<MLong, MInt>> higherLvlPartitionCellHilbertIds;
27901 // maps local cells to srcPartitionCellIds
27902 multimap<MInt, MInt> partitionCellsToLoad;
27903 // misc
27904 vector<MString> varNames;
27905 vector<MInt> uncollatedBndryCells;
27906 vector<MInt> uncollatedCells;
27907
27908 // this should be a clustered read operation, later ... or never :)
27909 { // scope start
27910 MIntScratchSpace srcPartitionCellsHilbertId(srcNmbrPartitionCells, AT_, "srcPartitionCellsHilbertId");
27911 if(ParallelIo::fileExists("src/srcPartitionCellsHilbertId", mpiComm())) {
27912 m_log << "read srcPartitionCellHilbertIds ..." << endl;
27913 ParallelIo srcHilbertId("src/srcPartitionCellsHilbertId", maia::parallel_io::PIO_READ, mpiComm());
27914 srcHilbertId.setOffset(srcNmbrPartitionCells, 0);
27915 srcHilbertId.readArray(srcPartitionCellsHilbertId.begin(), "srcPartitionCellsHilbertId");
27916 // fill the multiset and multimaps
27917 for(MInt mcCnt = 0; mcCnt < srcNmbrPartitionCells; mcCnt++) {
27918 multiset<MInt>::iterator it = srcPartitionCellHilbertIds.end();
27919 srcPartitionCellHilbertIds.insert(it, srcPartitionCellsHilbertId(mcCnt));
27920 }
27921 if(srcHilbertId.hasDataset("noHighLevels")) {
27922 MInt maxLvlDiff = 0;
27923 srcHilbertId.readScalar(&maxLvlDiff, "noHighLevels");
27924 for(MInt lDiff = 0; lDiff < maxLvlDiff; lDiff++) {
27925 higherLvlPartitionCellHilbertIds.push_back(multimap<MLong, MInt>());
27926 stringstream hilbertStr;
27927 hilbertStr << "higherLvlHilbertId_" << lDiff;
27928 stringstream idStr;
27929 idStr << "partitionCellId_" << lDiff;
27930 MInt noHighLvl = srcHilbertId.getArraySize(idStr.str());
27931 srcHilbertId.setOffset(noHighLvl, 0);
27932 MLongScratchSpace tmpHilbert(noHighLvl, AT_, "tmpHilbert");
27933 MIntScratchSpace tmpId(noHighLvl, AT_, "tmpId");
27934 srcHilbertId.readArray(tmpHilbert.begin(), hilbertStr.str());
27935 srcHilbertId.readArray(tmpId.begin(), idStr.str());
27936 for(MInt cCnt = 0; cCnt < noHighLvl; cCnt++)
27937 higherLvlPartitionCellHilbertIds[lDiff].insert(make_pair(tmpHilbert(cCnt), tmpId(cCnt)));
27938 }
27939 }
27940 } else {
27941 m_log << "calc srcPartitionCellHilbertIds ..." << endl;
27942 // distribute partitionCells among processors
27943 MIntScratchSpace locNoPartitionCells(noDomains(), AT_, "locNoPartitionCells");
27944 MIntScratchSpace locPartitionCellStart(noDomains(), AT_, "locPartitionCellStart");
27945 locNoPartitionCells.fill(srcNmbrPartitionCells / noDomains());
27946 MInt rem = srcNmbrPartitionCells % noDomains();
27947 for(MInt dId = 0; dId < noDomains(); dId++) {
27948 locPartitionCellStart(dId) = dId * locNoPartitionCells(dId);
27949 if(dId < rem) locNoPartitionCells(dId)++;
27950 if(dId < rem)
27951 locPartitionCellStart(dId) += dId;
27952 else
27953 locPartitionCellStart(dId) += rem;
27954 }
27955 m_log << " " << locNoPartitionCells(domainId()) << " read operations ..." << endl;
27956 // read partitionCellsLvlDiff info for higher min level information
27957 MIntScratchSpace srcPartitionCellsLvlDiff(locNoPartitionCells(domainId()), AT_, "srcPartitionCellsLvlDiff");
27958 srcGrid.setOffset(locNoPartitionCells(domainId()), locPartitionCellStart(domainId()));
27959 srcGrid.readArray(srcPartitionCellsLvlDiff.begin(), "partitionCellsLvlDiff");
27960 // get the highest levelDiff
27961 MInt maxLvlDiff = 0;
27962 for(MInt cId = 0; cId < locNoPartitionCells(domainId()); cId++) {
27963 maxLvlDiff = mMax(maxLvlDiff, srcPartitionCellsLvlDiff(cId));
27964 }
27965 MPI_Allreduce(MPI_IN_PLACE, &maxLvlDiff, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "maxLvlDiff");
27966 m_log << "highest partition cell difference is " << maxLvlDiff << endl;
27967 // compute offsets, local and total required memory
27968 MIntScratchSpace noHighLvl(maxLvlDiff, AT_, "noHighLvl");
27969 MIntScratchSpace highLvlOffset(maxLvlDiff, AT_, "highLvlOffset");
27970 MIntScratchSpace highLvlSum(maxLvlDiff, AT_, "highLvlSum");
27971 noHighLvl.fill(0);
27972 highLvlOffset.fill(0);
27973 highLvlSum.fill(0);
27974 for(MInt cId = 0; cId < locNoPartitionCells(domainId()); cId++) {
27975 for(MInt lvlId = 0; lvlId < srcPartitionCellsLvlDiff(cId); lvlId++)
27976 noHighLvl(lvlId)++;
27977 }
27978 for(MInt lvlId = 0; lvlId < maxLvlDiff; lvlId++) {
27979 MIntScratchSpace highLvlTmp(noDomains(), AT_, "highLvlTmp");
27980 highLvlTmp.fill(0);
27981 highLvlTmp(domainId()) = noHighLvl(lvlId);
27982 MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, highLvlTmp.begin(), 1, MPI_INT, mpiComm(), AT_,
27983 "MPI_IN_PLACE", "highLvlTmp.begin()");
27984 for(MInt dom = 0; dom < domainId(); dom++) {
27985 highLvlOffset(lvlId) += highLvlTmp(dom);
27986 highLvlSum(lvlId) += highLvlTmp(dom);
27987 }
27988 for(MInt dom = domainId(); dom < noDomains(); dom++)
27989 highLvlSum(lvlId) += highLvlTmp(dom);
27990 m_log << "number of higher level hilbert ids to store for lvlDiff " << lvlId + 1 << " is "
27991 << highLvlSum(lvlId) << endl;
27992 }
27993 // tmp memory for the higher level hilbetIds and corresponding partitionCellIds
27994 MIntScratchSpace offTotalHigherLvl(maxLvlDiff + 1, AT_, "offTotalHigherLvl");
27995 offTotalHigherLvl.fill(0);
27996 for(MInt lDiff = 1; lDiff <= maxLvlDiff; lDiff++)
27997 for(MInt lDiffi = lDiff; lDiffi <= maxLvlDiff; lDiffi++)
27998 offTotalHigherLvl(lDiffi) += highLvlSum(lDiff - 1);
27999 m_log << "higher level offsets in common memory" << endl;
28000 for(MInt lDiff = 0; lDiff <= maxLvlDiff; lDiff++)
28001 m_log << offTotalHigherLvl(lDiff) << endl;
28002 MIntScratchSpace highLvlId(offTotalHigherLvl(maxLvlDiff), AT_, "highLvlId");
28003 MLongScratchSpace highLvlHilbert(offTotalHigherLvl(maxLvlDiff), AT_,
28004 "highLvlHilbert"); // Long stuff
28005 highLvlId.fill(0);
28006 highLvlHilbert.fill(0);
28007 // ParallelIo variablename stuff
28008 for(MInt j = 0; j < nDim; ++j) {
28009 stringstream ss;
28010 ss << "coordinates_" << j;
28011 varNames.push_back(ss.str());
28012 ss.clear();
28013 ss.str("");
28014 }
28015 // counter for the higherLvl information
28016 MIntScratchSpace highLvlCnt(maxLvlDiff, AT_, "highLvlCnt");
28017 highLvlCnt.fill(0);
28018 // action
28019 for(MInt i = 0; i < locNoPartitionCells(domainId()); i++) {
28020 MInt mcCnt = locPartitionCellStart(domainId()) + i;
28021 MFloatScratchSpace srcPartitionCellsCoords(nDim, AT_, "srcPartitionCellsCoords");
28022 srcGrid.setOffset(1, srcPartitionCellsGlobalId(mcCnt));
28023 srcGrid.readArray(srcPartitionCellsCoords.begin(), varNames, nDim);
28024 srcPartitionCellsCoords(0) =
28025 (fileTypeFac * srcPartitionCellsCoords(0) - srcCenterOfGravity[0] + srcLengthLevel0 * 0.5)
28026 / srcLengthLevel0;
28027 srcPartitionCellsCoords(1) =
28028 (fileTypeFac * srcPartitionCellsCoords(1) - srcCenterOfGravity[1] + srcLengthLevel0 * 0.5)
28029 / srcLengthLevel0;
28030 IF_CONSTEXPR(nDim == 3)
28031 srcPartitionCellsCoords(2) =
28032 (fileTypeFac * srcPartitionCellsCoords(2) - srcCenterOfGravity[2] + srcLengthLevel0 * 0.5)
28033 / srcLengthLevel0;
28034 srcPartitionCellsHilbertId(mcCnt) =
28035 maia::grid::hilbert::index<nDim>(&(srcPartitionCellsCoords(0)), srcMinLevel);
28036 for(MInt lDiff = 0; lDiff < srcPartitionCellsLvlDiff(i); lDiff++) {
28037 highLvlId(offTotalHigherLvl(lDiff) + highLvlOffset(lDiff) + highLvlCnt(lDiff)) = mcCnt;
28038 MLong tmpHilbert =
28039 maia::grid::hilbert::index<nDim>(&(srcPartitionCellsCoords(0)), (MLong)(srcMinLevel + (lDiff + 1)));
28040 highLvlHilbert(offTotalHigherLvl(lDiff) + highLvlOffset(lDiff) + highLvlCnt(lDiff)) = tmpHilbert;
28041 highLvlCnt(lDiff)++;
28042 }
28043 }
28044 if(rem && domainId() >= rem) { // fake reads
28045 MFloatScratchSpace srcPartitionCellsCoords(nDim, AT_, "srcPartitionCellsCoords");
28046 srcGrid.setOffset(0, 0);
28047 srcGrid.readArray(srcPartitionCellsCoords.begin(), varNames, nDim);
28048 }
28049 varNames.clear();
28050 MPI_Barrier(mpiComm(), AT_);
28051 m_log << " done" << endl;
28052 m_log << " writing hilbert ids to file ..." << endl;
28053 // save lowest Lvl HilbertIds
28054 ParallelIo srcHilbertId("src/srcPartitionCellsHilbertId", maia::parallel_io::PIO_CREATE, mpiComm());
28055 // define arrays
28056 srcHilbertId.defineArray(maia::parallel_io::PIO_INT, "srcPartitionCellsHilbertId", srcNmbrPartitionCells);
28057 for(MInt lDiff = 0; lDiff < maxLvlDiff; lDiff++) {
28058 stringstream hilbertStr;
28059 hilbertStr << "higherLvlHilbertId_" << lDiff;
28060 stringstream idStr;
28061 idStr << "partitionCellId_" << lDiff;
28062 srcHilbertId.defineArray(maia::parallel_io::PIO_LONG, hilbertStr.str(), highLvlSum(lDiff));
28063 srcHilbertId.defineArray(maia::parallel_io::PIO_INT, idStr.str(), highLvlSum(lDiff));
28064 }
28065 // define scalars
28066 if(maxLvlDiff) srcHilbertId.defineScalar(maia::parallel_io::PIO_INT, "noHighLevels");
28067 // write lowest level
28068 srcHilbertId.setOffset(locNoPartitionCells(domainId()), locPartitionCellStart(domainId()));
28069 srcHilbertId.writeArray(srcPartitionCellsHilbertId.begin() + locPartitionCellStart(domainId()),
28070 "srcPartitionCellsHilbertId");
28071 // write the higher Lvl HilberIds and corresponding partitionCellIds (count not
28072 // globalId)
28073 for(MInt lDiff = 0; lDiff < maxLvlDiff; lDiff++) {
28074 stringstream hilbertStr;
28075 hilbertStr << "higherLvlHilbertId_" << lDiff;
28076 stringstream idStr;
28077 idStr << "partitionCellId_" << lDiff;
28078 srcHilbertId.setOffset(noHighLvl(lDiff), highLvlOffset(lDiff));
28079 srcHilbertId.writeArray(highLvlHilbert.begin() + offTotalHigherLvl(lDiff) + highLvlOffset(lDiff),
28080 hilbertStr.str());
28081 srcHilbertId.writeArray(highLvlId.begin() + offTotalHigherLvl(lDiff) + highLvlOffset(lDiff), idStr.str());
28082 }
28083 // write scalars
28084 if(maxLvlDiff) srcHilbertId.writeScalar(maxLvlDiff, "noHighLevels");
28085 // communicate the ids
28086 MPI_Barrier(mpiComm(), AT_);
28087 m_log << " done" << endl;
28088 m_log << " exchange hilbert ids ..." << endl;
28089 MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, srcPartitionCellsHilbertId.begin(),
28090 locNoPartitionCells.begin(), locPartitionCellStart.begin(), MPI_INT, mpiComm(), AT_,
28091 "MPI_IN_PLACE", "srcPartitionCellsHilbertId.begin()");
28092 for(MInt lDiff = 0; lDiff < maxLvlDiff; lDiff++) {
28093 MIntScratchSpace noHighLvlTmp(noDomains(), AT_, "noHighLvlTmp");
28094 MIntScratchSpace offHighLvlTmp(noDomains(), AT_, "offHighLvlTmp");
28095 noHighLvlTmp.fill(0);
28096 offHighLvlTmp.fill(0);
28097 noHighLvlTmp(domainId()) = noHighLvl(lDiff);
28098 MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, noHighLvlTmp.begin(), 1, MPI_INT, mpiComm(), AT_,
28099 "MPI_IN_PLACE", "noHighLvlTmp.begin()");
28100 for(MInt dom = 1; dom < noDomains(); dom++) {
28101 offHighLvlTmp(dom) = offHighLvlTmp(dom - 1) + noHighLvlTmp(dom - 1);
28102 }
28103 MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, highLvlHilbert.begin() + offTotalHigherLvl(lDiff),
28104 noHighLvlTmp.begin(), offHighLvlTmp.begin(), MPI_LONG, mpiComm(), AT_, "MPI_IN_PLACE",
28105 "highLvlHilbert.begin() + offTotalHigherLvl(lDiff)");
28106 MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, highLvlId.begin() + offTotalHigherLvl(lDiff),
28107 noHighLvlTmp.begin(), offHighLvlTmp.begin(), MPI_INT, mpiComm(), AT_, "MPI_IN_PLACE",
28108 "highLvlId.begin() + offTotalHigherLvl(lDiff)");
28109 }
28110 MPI_Barrier(mpiComm(), AT_);
28111 m_log << " done" << endl;
28112 // fill the multiset and multimaps
28113 for(MInt mcCnt = 0; mcCnt < srcNmbrPartitionCells; mcCnt++) {
28114 multiset<MInt>::iterator it = srcPartitionCellHilbertIds.end();
28115 srcPartitionCellHilbertIds.insert(it, srcPartitionCellsHilbertId(mcCnt));
28116 }
28117 for(MInt lDiff = 0; lDiff < maxLvlDiff; lDiff++) {
28118 higherLvlPartitionCellHilbertIds.push_back(multimap<MLong, MInt>());
28119 for(MInt cCnt = 0; cCnt < highLvlSum(lDiff); cCnt++) {
28120 higherLvlPartitionCellHilbertIds[lDiff].insert(make_pair(
28121 highLvlHilbert(offTotalHigherLvl(lDiff) + cCnt), highLvlId(offTotalHigherLvl(lDiff) + cCnt)));
28122 }
28123 }
28124 }
28125 } // scope end
28126 MPI_Barrier(mpiComm(), AT_);
28127 m_log << "done" << endl;
28128
28129 m_log << "create connectivity multimap ..." << endl;
28130 for(MInt cid = 0; cid < noInternalCells(); cid++) {
28131 if(c_noChildren(cid) > 0) continue;
28132 MFloatScratchSpace xyz(nDim, AT_, "xyz");
28133 xyz(0) = (a_coordinate(cid, 0) - srcCenterOfGravity[0] + srcLengthLevel0 * 0.5) / srcLengthLevel0;
28134 xyz(1) = (a_coordinate(cid, 1) - srcCenterOfGravity[1] + srcLengthLevel0 * 0.5) / srcLengthLevel0;
28135 IF_CONSTEXPR(nDim == 3)
28136 xyz(2) = (a_coordinate(cid, 2) - srcCenterOfGravity[2] + srcLengthLevel0 * 0.5) / srcLengthLevel0;
28137 MInt retVal = maia::grid::hilbert::index<nDim>(&(xyz(0)), srcMinLevel);
28138
28139 pair<multiset<MInt>::iterator, multiset<MInt>::iterator> itPair =
28140 srcPartitionCellHilbertIds.equal_range(retVal);
28141
28142
28143 if(itPair.first == itPair.second) {
28144 if(a_bndryId(cid) > -1) {
28145 uncollatedBndryCells.push_back(cid);
28146 } else {
28147 uncollatedCells.push_back(cid);
28148 }
28149 } else if(distance(itPair.first, itPair.second) == 1) {
28150 MInt locSrcPartitionCellId = distance(srcPartitionCellHilbertIds.begin(), itPair.first);
28151 partitionCellsToLoad.insert(make_pair(locSrcPartitionCellId, cid)); // (srcPartitionCellId,cellId)
28152 } else { // partition level shift
28153 for(MInt lDiff = 0; lDiff < (MInt)higherLvlPartitionCellHilbertIds.size(); lDiff++) {
28154 MLong highRetVal = maia::grid::hilbert::index<nDim>(&(xyz(0)), (MLong)(srcMinLevel + (lDiff + 1)));
28155 pair<multimap<MLong, MInt>::iterator, multimap<MLong, MInt>::iterator> highItPair =
28156 higherLvlPartitionCellHilbertIds[lDiff].equal_range(highRetVal);
28157 if(highItPair.first == highItPair.second) {
28158 if(a_bndryId(cid) > -1) {
28159 uncollatedBndryCells.push_back(cid);
28160 } else {
28161 uncollatedCells.push_back(cid);
28162 }
28163 break;
28164 } else if(distance(highItPair.first, highItPair.second) == 1) {
28165 MInt locSrcPartitionCellId = highItPair.first->second;
28166 partitionCellsToLoad.insert(make_pair(locSrcPartitionCellId, cid)); // (srcPartitionCellId,cellId)
28167 break;
28168 } else {
28169 if(lDiff == (MInt)higherLvlPartitionCellHilbertIds.size() - 1)
28170 mTerm(1, "this should not happen, there should not be identical hilbertIds on "
28171 "the highest level");
28172 }
28173 }
28174 }
28175 }
28176 MPI_Barrier(mpiComm(), AT_);
28177 m_log << "done" << endl;
28178
28179 m_log << "cluster read operations ..." << endl;
28180 vector<multimap<MInt, MInt>::iterator> readClusteringIterators;
28181 MInt noReadOps;
28182 {
28183 MInt srcPartitionCellId;
28184 for(multimap<MInt, MInt>::iterator it = partitionCellsToLoad.begin(); it != partitionCellsToLoad.end();
28185 it = partitionCellsToLoad.upper_bound(srcPartitionCellId)) { // first element larger than the key
28186
28187 readClusteringIterators.push_back(it);
28188 srcPartitionCellId = it->first;
28189 MInt srcPartitionCellNoOffsprings =
28190 srcPartitionCellsGlobalId(srcPartitionCellId + 1) - srcPartitionCellsGlobalId(srcPartitionCellId);
28191
28192 // how much cells would extending the read to the next partition cell add?
28193 MInt additionalPartitionCellNoOffsprings = 0;
28194 while(1) {
28195 multimap<MInt, MInt>::iterator itNext = partitionCellsToLoad.upper_bound(srcPartitionCellId);
28196 if(itNext == partitionCellsToLoad.end()) break;
28197 MInt nextSrcPartitionCellId = itNext->first;
28198 for(MInt i = srcPartitionCellId + 1; i <= nextSrcPartitionCellId; i++) {
28199 additionalPartitionCellNoOffsprings += srcPartitionCellsGlobalId(i + 1) - srcPartitionCellsGlobalId(i);
28200 }
28201 if(additionalPartitionCellNoOffsprings + srcPartitionCellNoOffsprings > maxNoCellsToRead) break;
28202 srcPartitionCellId = nextSrcPartitionCellId;
28203 }
28204 }
28205 noReadOps = readClusteringIterators.size();
28206 readClusteringIterators.push_back(partitionCellsToLoad.end());
28207 }
28208
28209 MPI_Barrier(mpiComm(), AT_);
28210 m_log << "done" << endl;
28211
28212 MInt noFakeReads = 0;
28213 MInt minNoReadOps;
28214 if(noDomains() > 1) {
28215 MInt maxNoReadOps;
28216 MPI_Allreduce(&noReadOps, &maxNoReadOps, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "noReadOps", "maxNoReadOps");
28217 MPI_Allreduce(&noReadOps, &minNoReadOps, 1, MPI_INT, MPI_MIN, mpiComm(), AT_, "noReadOps", "minNoReadOps");
28218 noFakeReads = maxNoReadOps - noReadOps;
28219 m_log << maxNoReadOps << " max number of read operations" << endl;
28220 m_log << minNoReadOps << " min number of read operations" << endl;
28221 }
28222
28223 MPI_Barrier(mpiComm(), AT_);
28224 m_log << "get leaf cell data ..." << endl;
28225
28226 // allocate memory
28227 ParallelIo srcData("src/initialCondition", maia::parallel_io::PIO_READ, mpiComm());
28228 MFloatScratchSpace srcCoords(maxNoCellsToRead, nDim, AT_, "srcCoords");
28229 MIntScratchSpace srcChildIds(maxNoCellsToRead, IPOW2(nDim), AT_, "srcChildIds");
28230 MIntScratchSpace srcNoChildIds(maxNoCellsToRead, AT_, "srcNoChildIds");
28231 MIntScratchSpace srcLevel(maxNoCellsToRead, AT_, "srcLevel");
28232 MFloatScratchSpace srcVars(maxNoCellsToRead, noPVars, AT_, "srcVars");
28233 for(MInt noOps = 0; noOps < noReadOps; noOps++) {
28234 multimap<MInt, MInt>::iterator it = readClusteringIterators[noOps];
28235 multimap<MInt, MInt>::iterator nextIt = readClusteringIterators[noOps + 1];
28236 multimap<MInt, MInt>::iterator lastIt = prev(nextIt);
28237 MInt srcPartitionCellGlobalId = srcPartitionCellsGlobalId(it->first);
28238 MInt srcCellsToRead = 0;
28239 for(MInt smcid = it->first; smcid <= lastIt->first; smcid++)
28240 srcCellsToRead += srcPartitionCellsGlobalId(smcid + 1) - srcPartitionCellsGlobalId(smcid);
28241 srcGrid.setOffset(srcCellsToRead, srcPartitionCellGlobalId);
28242 srcData.setOffset(srcCellsToRead, srcPartitionCellGlobalId);
28243 // load coords
28244 for(MInt j = 0; j < nDim; ++j) {
28245 stringstream ss;
28246 ss << "coordinates_" << j;
28247 varNames.push_back(ss.str());
28248 ss.clear();
28249 ss.str("");
28250 }
28251 srcGrid.readArray(&srcCoords(0, 0), varNames, nDim);
28252 varNames.clear();
28253 // load nmbr child
28254 srcGrid.readArray(srcNoChildIds.begin(), "noChildIds");
28255 // level
28256 srcGrid.readArray(srcLevel.begin(), "level_0");
28257 // load childIds
28258 for(MInt j = 0; j < IPOW2(nDim); ++j) {
28259 stringstream ss;
28260 ss << "childIds_" << j;
28261 varNames.push_back(ss.str());
28262 ss.clear();
28263 ss.str("");
28264 }
28265 srcGrid.readArray(&srcChildIds(0, 0), varNames, IPOW2(nDim));
28266 varNames.clear();
28267 // correct Ids
28268 for(MInt i = 0; i < maxNoCellsToRead; i++)
28269 for(MInt j = 0; j < IPOW2(nDim); j++)
28270 srcChildIds(i, j) -= srcPartitionCellGlobalId;
28271 // correct Coords
28272 for(MInt i = 0; i < maxNoCellsToRead; i++)
28273 for(MInt j = 0; j < nDim; j++)
28274 srcCoords(i, j) *= fileTypeFac;
28275 // load vars
28276 for(MInt j = 0; j < noPVars; ++j) {
28277 stringstream ss;
28278 ss << "variables" << j;
28279 varNames.push_back(ss.str());
28280 ss.clear();
28281 ss.str("");
28282 }
28283 srcData.readArray(&srcVars(0, 0), varNames, noPVars);
28284 varNames.clear();
28285 // loop over corresponding internal cells
28286 for(multimap<MInt, MInt>::iterator i = it; i != nextIt; advance(i, 1)) {
28287 // vector<pair<MInt,MInt>> routeToStuck;
28288 // vector<MInt> debInfo;
28289 MInt locSrcPartitionCellId = srcPartitionCellsGlobalId(i->first) - srcPartitionCellGlobalId;
28290 MInt cid = i->second;
28291 MFloat* coord = (MFloat*)(&(a_coordinate(cid, 0)));
28292 // go to the leaf cell
28293 MInt srcSrcId = locSrcPartitionCellId;
28294 // MInt LvlCnt = 0;
28295 while(srcNoChildIds(srcSrcId)) {
28296 // routeToStuck.push_back(make_pair(srcLevel(srcSrcId),srcNoChildIds(srcSrcId)));
28297 // debInfo.push_back(srcSrcId);
28298 // whileCnt++;
28299 // if(whileCnt > (srcMaxLevel - srcMinLevel)){ // suspicious, might
28300 // lead to problem with partition level shift
28301 // cerr << " stuck in partition cell " <<
28302 // srcPartitionCellsGlobalId(i->first) << " " << whileCnt << endl;
28303 // cerr << "cell " << c_globalId(cid) << " at " << coord[0] << " " <<
28304 // coord[1] << " " << coord[2] << endl; cerr << "partition cell " <<
28305 // " at " << srcCoords(locSrcPartitionCellId,0) << " " <<
28306 // srcCoords(locSrcPartitionCellId,1) << " " <<
28307 // srcCoords(locSrcPartitionCellId,2) << endl;
28308 // for(MInt l = 0; l < (MInt)routeToStuck.size();l++){
28309 // cerr << routeToStuck[l].first << " " << routeToStuck[l].second << " " <<
28310 // debInfo[l] << endl;
28311 //}
28312 // mTerm(1," initial condition 81, stuck in partition cell ");
28313 // }
28314 MFloat minDist = std::numeric_limits<MFloat>::max();
28315 MFloat minTcid = -1;
28316 for(MInt cc = 0; cc < IPOW2(nDim); cc++) {
28317 MInt tcid = srcChildIds(srcSrcId, cc);
28318 if(tcid >= 0) {
28319 MFloat* srcCoord = &srcCoords(tcid, 0);
28320 MFloat hdc = srcLengthLevel0 / IPOW2(srcLevel(tcid) + 1);
28321 // if the cell is inside the child break loop
28322 MInt insideCnt = 0;
28323 for(MInt dim = 0; dim < nDim; dim++)
28324 if(coord[dim] < srcCoord[dim] + hdc && coord[dim] >= srcCoord[dim] - hdc) insideCnt++;
28325 if(insideCnt == nDim) {
28326 srcSrcId = tcid;
28327 break;
28328 }
28329 // otherwise prepare for a dist comparison
28330 MFloat tmpDist = 0.0;
28331 for(MInt dim = 0; dim < nDim; dim++)
28332 tmpDist += pow(coord[dim] - srcCoord[dim], F2);
28333 tmpDist = sqrt(tmpDist);
28334 // if(srcNoChildIds(srcSrcId) == 1)
28335 // cerr << tmpDist << " " << minDist << " " << srcLengthLevel0 << endl;
28336 if(tmpDist < minDist) {
28337 minDist = tmpDist;
28338 minTcid = tcid;
28339 }
28340 }
28341 if(cc == IPOW2(nDim) - 1) srcSrcId = minTcid;
28342 }
28343 }
28344 // set cell data
28345 for(MInt var = 0; var < noPVars; var++)
28346 a_pvariable(cid, var) = srcVars(srcSrcId, var);
28347 }
28348 }
28349
28350 // fake reads
28351 for(MInt fr = 0; fr < noFakeReads; fr++) {
28352 // load coords
28353 for(MInt j = 0; j < nDim; ++j) {
28354 stringstream ss;
28355 ss << "coordinates_" << j;
28356 varNames.push_back(ss.str());
28357 ss.clear();
28358 ss.str("");
28359 }
28360 srcGrid.setOffset(0, 0);
28361 srcData.setOffset(0, 0);
28362 srcGrid.readArray(&srcCoords(0, 0), varNames, nDim);
28363 varNames.clear();
28364 // load nmbr child
28365 srcGrid.readArray(srcNoChildIds.begin(), "noChildIds");
28366 // level
28367 srcGrid.readArray(srcLevel.begin(), "level_0");
28368 // load childIds
28369 for(MInt j = 0; j < IPOW2(nDim); ++j) {
28370 stringstream ss;
28371 ss << "childIds_" << j;
28372 varNames.push_back(ss.str());
28373 ss.clear();
28374 ss.str("");
28375 }
28376 srcGrid.readArray(&srcChildIds(0, 0), varNames, IPOW2(nDim));
28377 varNames.clear();
28378 // load vars
28379 for(MInt j = 0; j < noPVars; ++j) {
28380 stringstream ss;
28381 ss << "variables" << j;
28382 varNames.push_back(ss.str());
28383 ss.clear();
28384 ss.str("");
28385 }
28386 srcData.readArray(&srcVars(0, 0), varNames, noPVars);
28387 varNames.clear();
28388 }
28389
28390 MPI_Barrier(mpiComm(), AT_);
28391 m_log << "done" << endl;
28392
28393 // statistics of cells that could not be found in the source grid
28394 MInt sumUncollated = uncollatedCells.size();
28395 MPI_Allreduce(MPI_IN_PLACE, &sumUncollated, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
28396 "sumUncollated");
28397 m_log << sumUncollated << " uncollated cells" << endl;
28398 // to exclude other noncollated cells from the averaging below, we need the
28399 // globalIds frome all uncollated cells
28400 MInt sumUncollatedBndry = 0;
28401 set<MInt> allUncollatedBndryGlobalIds;
28402 {
28403 MIntScratchSpace noGlobalUncollatedBndry(noDomains(), AT_, "noGlobalUncollatedBndry");
28404 MIntScratchSpace noGlobalUncollatedBndryOffset(noDomains() + 1, AT_, "noGlobalUncollatedBndryOffset");
28405 noGlobalUncollatedBndry.fill(0);
28406 noGlobalUncollatedBndryOffset.fill(0);
28407 noGlobalUncollatedBndry[domainId()] = uncollatedBndryCells.size();
28408 MPI_Allgather(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, noGlobalUncollatedBndry.begin(), 1, MPI_INT, mpiComm(), AT_,
28409 "MPI_IN_PLACE", "noGlobalUncollatedBndry.begin()");
28410 for(MInt dom = 0; dom < noDomains(); dom++) {
28411 sumUncollatedBndry += noGlobalUncollatedBndry[dom];
28412 noGlobalUncollatedBndryOffset[dom + 1] = sumUncollatedBndry;
28413 }
28414 MIntScratchSpace globalUncollatedBndry(sumUncollatedBndry, AT_, "globalUncollatedBndry");
28415 for(MInt cnt = 0; cnt < (MInt)uncollatedBndryCells.size(); cnt++) {
28416 MInt globalId = c_globalId(uncollatedBndryCells[cnt]);
28417 globalUncollatedBndry[noGlobalUncollatedBndryOffset[domainId()] + cnt] = globalId;
28418 }
28419 MPI_Allgatherv(MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, globalUncollatedBndry.begin(),
28420 noGlobalUncollatedBndry.begin(), noGlobalUncollatedBndryOffset.begin(), MPI_INT, mpiComm(),
28421 AT_, "MPI_IN_PLACE", "globalUncollatedBndry.begin()");
28422 for(MInt cnt = 0; cnt < sumUncollatedBndry; cnt++)
28423 allUncollatedBndryGlobalIds.insert(allUncollatedBndryGlobalIds.end(), noGlobalUncollatedBndry[cnt]);
28424 }
28425
28426 m_log << sumUncollatedBndry << " uncollated bndry cells" << endl;
28427 if(sumUncollatedBndry)
28428 m_log << "WARNING that is almost an ERROR: we have non "
28429 << "collated boundary cells in initial consdition 8111" << endl
28430 << "i will try to fix it, but we will see" << endl;
28431
28432 exchangeAll();
28433
28434 MPI_Barrier(mpiComm(), AT_);
28435 m_log << "exchange done" << endl;
28436
28437 // fix uncollated boundary cells using the data of the neighbors
28438 for(MInt cnt = 0; cnt < (MInt)uncollatedBndryCells.size(); cnt++) {
28439 MInt cid = uncollatedBndryCells[cnt];
28440 cerr << "fixing uncollated state for cell " << c_globalId(cid) << endl;
28441 // reset variables
28442 for(MInt var = 0; var < noPVars; var++)
28443 a_pvariable(cid, var) = F0;
28444 // sum data of valid neighbors
28445 MInt validNghbrs = 0;
28446
28447 for(MInt dir = 0; dir < a_noReconstructionNeighbors(cid); dir++) {
28448 MInt nid = a_reconstructionNeighborId(cid, dir);
28449 cerr << " rec nghbr " << dir << ", neighborId " << nid << endl;
28450
28451 if(a_isBndryGhostCell(nid)) {
28452 cerr << "-- is ghost cell" << endl;
28453 continue;
28454 }
28455
28456 if(allUncollatedBndryGlobalIds.find(c_globalId(nid)) != allUncollatedBndryGlobalIds.end()) {
28457 cerr << "-- neighbor " << c_globalId(nid) << " is also uncollated" << endl;
28458 continue;
28459 }
28460
28461 validNghbrs++;
28462 for(MInt var = 0; var < noPVars; var++)
28463 a_pvariable(cid, var) += a_pvariable(nid, var);
28464 }
28465 if(!validNghbrs) mTerm(1, "no valid nghbrs for initialisation of uncollated boundary cell");
28466 // average
28467 for(MInt var = 0; var < noPVars; var++)
28468 a_pvariable(cid, var) /= validNghbrs;
28469 }
28470
28471 exchangeAll();
28472
28473 MPI_Barrier(mpiComm(), AT_);
28474 m_log << "exchange done" << endl;
28475
28476 MInt tmpGlobalTimeStep = globalTimeStep;
28477 globalTimeStep = 0;
28478 saveRestartFile(false);
28479 globalTimeStep = tmpGlobalTimeStep;
28480
28481 computeConservativeVariables();
28482 LSReconstructCellCenter();
28483
28484 break;
28485 }
28486
28487 case 1: {
28488 IF_CONSTEXPR(nDim == 2) mTerm(-1, "This IC is untested in 2D! If it works uncomment this warning.");
28489
28490 // channel with perturbations
28491
28492 computeInitialPressureLossForChannelFlow(); // computes m_deltaP.
28493
28494 m_fvBndryCnd->m_deltaP = m_deltaP;
28495
28496 MFloat factor, perturbation;
28497 MFloat UT = m_Ma * sqrt(m_TInfinity);
28498
28499 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28500 if(cellId % 2 == 0) {
28501 factor = -F1;
28502 } else {
28503 factor = F1;
28504 }
28505
28506 // density
28507 a_variable(cellId, CV->RHO) = m_rhoInfinity;
28508 // momentum
28509 for(MUint d = 0; d < nDim; d++) {
28510 // TODO labels:FV The rand call here makes this function noDomains dependent. To fix, halo cells have to be
28511 // excluded and the rand state has to communicated between domains. Also note that the function
28512 // applyInitialCondition() is called twice.
28513 perturbation = (MFloat(rand()) / RAND_MAX) * 0.001 * UT * factor;
28514 a_variable(cellId, CV->RHO_VV[d]) = F2B3 * m_rhoVVInfinity[d] + perturbation;
28515 }
28516
28517 // energy
28518 const MFloat pressure = m_PInfinity - m_deltaP * (a_coordinate(cellId, 0) - m_domainBoundaries[0]);
28519 MFloat velPOW2 = 0;
28520 for(MUint d = 0; d < nDim; d++)
28521 velPOW2 += POW2(a_variable(cellId, CV->RHO_VV[d]));
28522 IF_CONSTEXPR(hasE<SysEqn>)
28523 a_variable(cellId, CV->RHO_E) = pressure / gammaMinusOne + (F1B2 * velPOW2) / m_rhoInfinity;
28524 }
28525 break;
28526 }
28527 // ring vortex - sphere interaction - artificially increased Mach number (factor 1000)
28528 // ring vortex - sphere interaction
28529 case 15: // Taylor-Green vortex (TGV), hijacked by Lennart ( for levelSetMb)
28530 {
28531 if(m_levelSetMb) {
28532 m_rhoInfinity = F1;
28533 m_TInfinity = F1;
28534 m_PInfinity = sysEqn().pressure_ES(m_TInfinity, m_rhoInfinity);
28535 m_UInfinity = m_Ma;
28536 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
28537 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
28538 m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
28539 m_rhoEInfinity = sysEqn().internalEnergy(m_PInfinity, m_rhoInfinity, POW2(m_UInfinity));
28540 m_hInfinity = sysEqn().enthalpy(m_PInfinity, m_rhoInfinity);
28541 sysEqn().m_Re0 = m_Re * SUTHERLANDLAW(m_TInfinity) / (m_rhoInfinity * m_UInfinity);
28542 m_timeRef = m_Ma;
28543 }
28544 MFloat bbox[2 * nDim];
28545 for(MInt i = 0; i < nDim; i++) {
28546 bbox[i] = numeric_limits<MFloat>::max();
28547 bbox[nDim + i] = numeric_limits<MFloat>::lowest();
28548 }
28549 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28550 if(a_isHalo(cellId)) continue;
28551 if(a_isPeriodic(cellId)) continue;
28552 for(MInt i = 0; i < nDim; i++) {
28553 bbox[i] = mMin(bbox[i], a_coordinate(cellId, i) - F1B2 * c_cellLengthAtCell(cellId));
28554 bbox[nDim + i] = mMax(bbox[nDim + i], a_coordinate(cellId, i) + F1B2 * c_cellLengthAtCell(cellId));
28555 }
28556 }
28557 MPI_Allreduce(MPI_IN_PLACE, &bbox[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[0]");
28558 MPI_Allreduce(MPI_IN_PLACE, &bbox[nDim], nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
28559 "bbox[nDim]");
28560
28561 MFloat FX;
28562 IF_CONSTEXPR(nDim == 3) { FX = F2; }
28563 else {
28564 FX = F1;
28565 }
28566 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28567 const MFloat x = (a_coordinate(cellId, 0) - bbox[0]) / (bbox[nDim] - bbox[0]);
28568 const MFloat y = (a_coordinate(cellId, 1) - bbox[1]) / (bbox[nDim + 1] - bbox[1]);
28569 MFloat z;
28570 IF_CONSTEXPR(nDim == 3) { z = (a_coordinate(cellId, 2) - bbox[2]) / (bbox[nDim + 2] - bbox[2]); }
28571 else {
28572 z = 0.0;
28573 }
28574 const MFloat u = m_Ma * sin(FX * PI * x) * cos(FX * PI * y) * cos(F2 * PI * z);
28575 const MFloat v = -m_Ma * cos(FX * PI * x) * sin(FX * PI * y) * cos(F2 * PI * z);
28576 const MFloat w = F0;
28577 MFloat p;
28578 IF_CONSTEXPR(nDim == 3) {
28579 p = m_PInfinity
28580 + F1B16 * POW2(m_Ma) * m_rhoInfinity * (cos(F4 * PI * x) + cos(F4 * PI * y)) * (cos(F4 * PI * z) + F2);
28581 }
28582 else {
28583 p = m_PInfinity + F1B4 * POW2(m_Ma) * m_rhoInfinity * (cos(F2 * PI * x) + sin(F2 * PI * y));
28584 }
28585 const MFloat rho = sysEqn().density_ES(p, m_TInfinity);
28586 a_variable(cellId, CV->RHO) = rho;
28587 a_variable(cellId, CV->RHO_U) = rho * u;
28588 a_variable(cellId, CV->RHO_V) = rho * v;
28589 a_variable(cellId, CV->RHO_W) = rho * w;
28590 IF_CONSTEXPR(hasE<SysEqn>) {
28591 a_variable(cellId, CV->RHO_E) = sysEqn().internalEnergy(p, rho, (POW2(u) + POW2(v) + POW2(w)));
28592 }
28593 }
28594 break;
28595 }
28596
28597 // isotropic turbulence spectrum
28598 case 16: {
28599 IF_CONSTEXPR(nDim == 2) mTerm(-1, "Only works for 3D!");
28600 const MFloat time0 = MPI_Wtime();
28601 computeCellVolumes();
28602 const MInt fftLevel = maxUniformRefinementLevel();
28603 const MFloat DX = c_cellLengthAtLevel(fftLevel);
28604 if(fftLevel > maxUniformRefinementLevel()) {
28605 mTerm(1, AT_, "Isotropic mesh expected (0).");
28606 }
28607 MFloat* bbox = new MFloat[2 * nDim];
28608 m_geometry->getBoundingBox(bbox);
28609 if(Context::propertyExists("cutOffCoordinates", m_solverId)) {
28610 for(MInt i = 0; i < nDim; i++) {
28611 bbox[i] = numeric_limits<MFloat>::max();
28612 bbox[nDim + i] = numeric_limits<MFloat>::lowest();
28613 }
28614 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28615 if(a_isHalo(cellId)) continue;
28616 if(a_isPeriodic(cellId)) continue;
28617 if(a_isBndryGhostCell(cellId)) continue;
28618 for(MInt i = 0; i < nDim; i++) {
28619 bbox[i] = mMin(bbox[i], a_coordinate(cellId, i) - F1B2 * c_cellLengthAtCell(cellId));
28620 bbox[nDim + i] = mMax(bbox[nDim + i], a_coordinate(cellId, i) + F1B2 * c_cellLengthAtCell(cellId));
28621 }
28622 }
28623 MPI_Allreduce(MPI_IN_PLACE, &bbox[0], nDim, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "bbox[0]");
28624 MPI_Allreduce(MPI_IN_PLACE, &bbox[nDim], nDim, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
28625 "bbox[nDim]");
28626 }
28627
28628 // fft-domain dimensions
28629 // this holds the size of the domain in number of cells on lowest level
28630 const MFloat dxeps = 0.1 * DX;
28631 MInt nx = (bbox[3] - bbox[0] + dxeps) / DX;
28632 MInt ny = (bbox[4] - bbox[1] + dxeps) / DX;
28633 MInt nz = (bbox[5] - bbox[2] + dxeps) / DX;
28634 const MInt size = nx * ny * nz;
28635
28636 m_rhoInfinity = F1;
28637 m_TInfinity = F1;
28638 m_PInfinity = sysEqn().pressure_ES(m_TInfinity, m_rhoInfinity);
28639 m_UInfinity = m_Ma;
28640 m_VInfinity = F0;
28641 m_WInfinity = F0;
28642 m_rhoUInfinity = m_rhoInfinity * m_UInfinity;
28643 m_rhoVInfinity = m_rhoInfinity * m_VInfinity;
28644 m_rhoWInfinity = m_rhoInfinity * m_WInfinity;
28645 m_rhoEInfinity = sysEqn().internalEnergy(m_PInfinity, m_rhoInfinity, POW2(m_UInfinity));
28646 m_hInfinity = sysEqn().enthalpy(m_PInfinity, m_rhoInfinity);
28647 sysEqn().m_muInfinity = SUTHERLANDLAW(m_TInfinity);
28648 sysEqn().m_Re0 = m_Re * sysEqn().m_muInfinity / (m_rhoInfinity * m_UInfinity);
28649 m_timeRef = m_Ma;
28650 m_VVInfinity[0] = m_UInfinity;
28651 m_VVInfinity[1] = m_VInfinity;
28652 m_VVInfinity[2] = m_WInfinity;
28653 m_rhoVVInfinity[0] = m_rhoUInfinity;
28654 m_rhoVVInfinity[1] = m_rhoVInfinity;
28655 m_rhoVVInfinity[2] = m_rhoWInfinity;
28666 if(Context::propertyExists("ReLambdaRestart", m_solverId)) {
28667 m_Re = Context::getSolverProperty<MFloat>("ReLambdaRestart", m_solverId, AT_);
28668 sysEqn().m_Re0 = m_Re * SUTHERLANDLAW(m_TInfinity) / (m_rhoInfinity * m_UInfinity);
28669 if(domainId() == 0) cerr << "Loading out/restartVariables_init.Netcdf" << endl;
28670 loadGridFlowVarsPar("out/restartVariables_init.Netcdf");
28671 exchangeDataFV(&a_pvariable(0, 0), noPVars, false, m_rotIndVarsPV);
28672 computeConservativeVariables();
28673 m_log << "Restart Reynolds number: " << setprecision(15) << m_Re << " (Re_L=" << m_Re * (bbox[3] - bbox[0])
28674 << ")"
28675 << " " << sysEqn().m_Re0 << endl;
28676 break;
28677 }
28678
28679 MBool goodSpectrum = false;
28680 MUlong seed = 0;
28681 while(!goodSpectrum) {
28682 const MInt spectrumId = 2; // prescribed energy spectrum, see maiamath.cpp
28683 const MFloat kpRatio = F4; // peak wave number of prescribed spectrum
28684 fftw_complex* uPhysField;
28685 fftw_complex* nabla2P;
28686 MIntScratchSpace fftInfo(4, AT_, "fftInfo");
28687
28688
28689 seed = maia::math::initFft(uPhysField, nabla2P, nx, ny, nz, kpRatio, spectrumId, fftInfo, mpiComm(), true);
28690
28691 MInt maxRank = fftInfo[0];
28692 MInt local_n0 = fftInfo[1];
28693 MInt local_0_start = fftInfo[2];
28694 MInt alloc_local = fftInfo[3];
28695
28696 MIntScratchSpace noSendIds(globalNoDomains(), AT_, "noSendIds");
28697 MInt sendIdsSize = 0;
28698 MIntScratchSpace offsetsIds(globalNoDomains() + 1, AT_, "offsetsIds");
28699 MInt locOffsetIds = (globalDomainId() < maxRank) ? ((MInt)local_0_start) * ny * nz : size;
28700 MPI_Allgather(&locOffsetIds, 1, MPI_INT, &offsetsIds[0], 1, MPI_INT, mpiComm(), AT_, "locOffsetIds",
28701 "offsetsIds[0]");
28702 offsetsIds(globalNoDomains()) = size;
28703 noSendIds.fill(0);
28704
28705 // Count no of sendIds
28706 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28707 if(a_isHalo(cellId)) continue;
28708 if(a_isBndryGhostCell(cellId)) continue;
28709 if(a_level(cellId) != fftLevel) continue;
28710 MFloat actualCellLength = c_cellLengthAtCell(cellId);
28711 MInt xPos = floor((F1B2 * nx + (a_coordinate(cellId, 0) - F1B2 * (actualCellLength)) / DX) + 0.1);
28712 MInt yPos = floor((F1B2 * ny + (a_coordinate(cellId, 1) - F1B2 * (actualCellLength)) / DX) + 0.1);
28713 MInt zPos = floor((F1B2 * nz + (a_coordinate(cellId, 2) - F1B2 * (actualCellLength)) / DX) + 0.1);
28714 MInt pos = maia::math::getGlobalPosFFTW(xPos, yPos, zPos, ny, nz);
28715 MInt nghbrDomain = mMin(maxRank - 1, pos / (size / maxRank));
28716 while(pos < offsetsIds(nghbrDomain) || pos >= offsetsIds(nghbrDomain + 1)) {
28717 if(pos < offsetsIds(nghbrDomain)) nghbrDomain--;
28718 if(pos >= offsetsIds(nghbrDomain + 1)) nghbrDomain++;
28719 }
28720 if(nghbrDomain >= maxRank) mTerm(1, AT_, "wrong domain");
28721 noSendIds(nghbrDomain)++;
28722 sendIdsSize++;
28723 }
28724 MIntScratchSpace sendIdsOffsets(globalNoDomains(), AT_, "sendIdsOffsets");
28725 MIntScratchSpace sendIdsOffsetsTmp(globalNoDomains(), AT_, "sendIdsOffsetsTmp");
28726 sendIdsOffsets[0] = 0;
28727 sendIdsOffsetsTmp[0] = 0;
28728 for(MInt nghbrDomain = 0; nghbrDomain < globalNoDomains() - 1; nghbrDomain++) {
28729 sendIdsOffsets[nghbrDomain + 1] = sendIdsOffsets[nghbrDomain] + noSendIds[nghbrDomain];
28730 sendIdsOffsetsTmp[nghbrDomain + 1] = sendIdsOffsets[nghbrDomain] + noSendIds[nghbrDomain];
28731 }
28732 MIntScratchSpace sendIds(sendIdsSize, AT_, "sendIdsSize");
28733
28734 // Fill sendIds
28735 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28736 if(a_isHalo(cellId)) continue;
28737 if(a_isBndryGhostCell(cellId)) continue;
28738 if(a_level(cellId) != fftLevel) continue;
28739 MFloat actualCellLength = c_cellLengthAtCell(cellId);
28740 MInt xPos = floor((F1B2 * nx + (a_coordinate(cellId, 0) - F1B2 * (actualCellLength)) / DX) + 0.1);
28741 MInt yPos = floor((F1B2 * ny + (a_coordinate(cellId, 1) - F1B2 * (actualCellLength)) / DX) + 0.1);
28742 MInt zPos = floor((F1B2 * nz + (a_coordinate(cellId, 2) - F1B2 * (actualCellLength)) / DX) + 0.1);
28743 MInt pos = maia::math::getGlobalPosFFTW(xPos, yPos, zPos, nx, ny);
28744 MInt nghbrDomain = mMin(maxRank - 1, pos / (size / maxRank));
28745 while(pos < offsetsIds(nghbrDomain) || pos >= offsetsIds(nghbrDomain + 1)) {
28746 if(pos < offsetsIds(nghbrDomain)) nghbrDomain--;
28747 if(pos >= offsetsIds(nghbrDomain + 1)) nghbrDomain++;
28748 }
28749 if(nghbrDomain >= maxRank) mTerm(1, AT_, "wrong domain");
28750 sendIds[sendIdsOffsetsTmp[nghbrDomain]++] = pos;
28751 }
28752 MIntScratchSpace noRecvIds(globalNoDomains(), AT_, "noRecvIds");
28753 noRecvIds.fill(0);
28754 MPI_Alltoall(&noSendIds[0], 1, MPI_INT, &noRecvIds[0], 1, MPI_INT, mpiComm(), AT_, "noSendIds[0]",
28755 "noRecvIds[0]");
28756
28757 MIntScratchSpace recvIdsOffsets(globalNoDomains(), AT_, "recvIdsOffsets");
28758 recvIdsOffsets[0] = 0;
28759 MInt recvIdsSize = 0;
28760 for(MInt nghbrDomain = 0; nghbrDomain < globalNoDomains() - 1; nghbrDomain++) {
28761 recvIdsOffsets[nghbrDomain + 1] = recvIdsOffsets[nghbrDomain] + noRecvIds[nghbrDomain];
28762 recvIdsSize += noRecvIds[nghbrDomain];
28763 }
28764 recvIdsSize += noRecvIds[globalNoDomains() - 1];
28765
28766 // Exchange Ids
28767 MIntScratchSpace recvIds(mMax(1, recvIdsSize), AT_, "recvIds");
28768 MPI_Alltoallv(&sendIds[0], &noSendIds[0], &sendIdsOffsets[0], MPI_INT, &recvIds[0], &noRecvIds[0],
28769 &recvIdsOffsets[0], MPI_INT, mpiComm(), AT_, "sendIds[0]", "recvIds[0]");
28770
28771 MIntScratchSpace sendVarsOffsets(globalNoDomains(), AT_, "sendVarsOffsets");
28772 MIntScratchSpace sendVarsOffsetsTmp(globalNoDomains(), AT_, "sendVarsOffsetsTmp");
28773 MIntScratchSpace noSendVars(globalNoDomains(), AT_, "noSendVars");
28774 sendVarsOffsets[0] = 0;
28775 sendVarsOffsetsTmp[0] = 0;
28776 MInt sendVarsSize = 0;
28777 for(MInt i = 0; i < globalNoDomains() - 1; i++) {
28778 sendVarsOffsets[i + 1] = sendVarsOffsets[i] + noRecvIds[i] * 4;
28779 sendVarsOffsetsTmp[i + 1] = sendVarsOffsetsTmp[i] + noRecvIds[i] * 4;
28780 noSendVars[i] = noRecvIds[i] * 4;
28781 sendVarsSize += noRecvIds[i] * 4;
28782 }
28783 if(recvIdsSize != 0) {
28784 noSendVars[globalNoDomains() - 1] = noRecvIds[globalNoDomains() - 1] * 4;
28785 sendVarsSize += noRecvIds[globalNoDomains() - 1] * 4;
28786 }
28787
28788 // Fill sendVars: for each Id received 4 variables have to be send
28789 MFloatScratchSpace sendVars(mMax(1, sendVarsSize), AT_, "sendVars");
28790 sendVars.fill(0);
28791 MFloat cnt = F0;
28792 MFloat upr[3] = {F0, F0, F0};
28793 for(MInt i = 0; i < recvIdsSize; i++) {
28794 MInt pos = recvIds[i];
28795 ASSERT(pos > -1 && pos < size, "");
28796 if(!(pos >= ((MInt)local_0_start) * nx * ny && pos < ((MInt)(local_0_start + local_n0) * ny * nx))) {
28797 mTerm(1, AT_, "Position not available on this domain(1).");
28798 }
28799 MInt localPos = pos - (((MInt)local_0_start) * ny * nz);
28800 if(3 * localPos + 2 > alloc_local) {
28801 mTerm(1, AT_, "index exceeds array(1)");
28802 }
28803 sendVars[i * 4] = uPhysField[3 * localPos][0];
28804 sendVars[i * 4 + 1] = uPhysField[3 * localPos + 1][0];
28805 sendVars[i * 4 + 2] = uPhysField[3 * localPos + 2][0];
28806 sendVars[i * 4 + 3] = nabla2P[localPos][0];
28807 MFloat u = uPhysField[3 * localPos][0];
28808 MFloat v = uPhysField[3 * localPos + 1][0];
28809 MFloat w = uPhysField[3 * localPos + 2][0];
28810 upr[0] += POW2(u);
28811 upr[1] += POW2(v);
28812 upr[2] += POW2(w);
28813 cnt++;
28814 }
28815
28816 MPI_Allreduce(MPI_IN_PLACE, &cnt, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cnt");
28817 MPI_Allreduce(MPI_IN_PLACE, &upr, 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "upr");
28818
28819 MFloat uprime0 = sqrt(F1B3 * (upr[0] + upr[1] + upr[2]) / cnt);
28820
28821 fftw_free(uPhysField);
28822 fftw_free(nabla2P);
28823
28824 MIntScratchSpace recvVarsOffsets(globalNoDomains(), AT_, "recvVarsOffsets");
28825 MIntScratchSpace noRecvVars(globalNoDomains(), AT_, "noRecvVars");
28826 recvVarsOffsets[0] = 0;
28827 MInt recvVarsSize = 0;
28828 for(MInt i = 0; i < globalNoDomains() - 1; i++) {
28829 recvVarsOffsets[i + 1] = recvVarsOffsets[i] + noSendIds[i] * 4;
28830 noRecvVars[i] = noSendIds[i] * 4;
28831 recvVarsSize += noSendIds[i] * 4;
28832 }
28833 recvVarsSize += noSendIds[globalNoDomains() - 1] * 4;
28834 noRecvVars[globalNoDomains() - 1] = noSendIds[globalNoDomains() - 1] * 4;
28835
28836 // Exchange Variables
28837 MFloatScratchSpace recvVars(recvVarsSize, AT_, "recvVars");
28838 recvVars.fill(0);
28839 MPI_Alltoallv(&sendVars[0], &noSendVars[0], &sendVarsOffsets[0], MPI_DOUBLE, &recvVars[0], &noRecvVars[0],
28840 &recvVarsOffsets[0], MPI_DOUBLE, mpiComm(), AT_, "sendVars[0]", "recvVars[0]");
28841
28842 cnt = F0;
28843 upr[0] = 0;
28844 upr[1] = 0;
28845 upr[2] = 0;
28846 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28847 if(a_isHalo(cellId)) continue;
28848 if(a_isBndryGhostCell(cellId)) continue;
28849 if(a_level(cellId) != fftLevel) continue;
28850 // if (cellId+4 >= recvVarsSize ) mTerm(1, AT_, "Not enough Variables
28851 // received");
28852 MFloat actualCellLength = c_cellLengthAtCell(cellId);
28853 MInt xPos = floor((F1B2 * nx + (a_coordinate(cellId, 0) - F1B2 * (actualCellLength)) / DX) + 0.1);
28854 MInt yPos = floor((F1B2 * ny + (a_coordinate(cellId, 1) - F1B2 * (actualCellLength)) / DX) + 0.1);
28855 MInt zPos = floor((F1B2 * nz + (a_coordinate(cellId, 2) - F1B2 * (actualCellLength)) / DX) + 0.1);
28856 MInt pos = maia::math::getGlobalPosFFTW(xPos, yPos, zPos, nx, ny);
28857 MInt nghbrDomain = mMin(maxRank - 1, pos / (size / maxRank));
28858 while(pos < offsetsIds(nghbrDomain) || pos >= offsetsIds(nghbrDomain + 1)) {
28859 if(pos < offsetsIds(nghbrDomain)) nghbrDomain--;
28860 if(pos >= offsetsIds(nghbrDomain + 1)) nghbrDomain++;
28861 }
28862 if(nghbrDomain >= maxRank) mTerm(1, AT_, "wrong domain");
28863 if(sendIds[sendIdsOffsets[nghbrDomain]] != pos) mTerm(1, AT_, "pos mismatch");
28864 MFloat u = recvVars[sendIdsOffsets[nghbrDomain] * 4];
28865 MFloat v = recvVars[sendIdsOffsets[nghbrDomain] * 4 + 1];
28866 MFloat w = recvVars[sendIdsOffsets[nghbrDomain] * 4 + 2];
28867 MFloat p = recvVars[sendIdsOffsets[nghbrDomain] * 4 + 3];
28868 sendIdsOffsets[nghbrDomain]++;
28869 upr[0] += POW2(u);
28870 upr[1] += POW2(v);
28871 upr[2] += POW2(w);
28872 a_pvariable(cellId, PV->U) = u;
28873 a_pvariable(cellId, PV->V) = v;
28874 a_pvariable(cellId, PV->W) = w;
28875 a_pvariable(cellId, PV->P) = m_PInfinity + p * POW2(m_UInfinity);
28876 cnt++;
28877 }
28878
28879 MPI_Allreduce(MPI_IN_PLACE, &cnt, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "cnt");
28880 MPI_Allreduce(MPI_IN_PLACE, &upr, 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "upr");
28881
28882 MFloat uprime1 = sqrt(F1B3 * (upr[0] + upr[1] + upr[2]) / cnt);
28883 upr[0] = sqrt(upr[0] / cnt);
28884 upr[1] = sqrt(upr[1] / cnt);
28885 upr[2] = sqrt(upr[2] / cnt);
28886
28887 if(fabs(uprime0 - uprime1) > exp(-10)) mTerm(1, AT_, "Communication went wrong.");
28888
28889 if(domainId() == 0)
28890 cerr << "initial urpime: " << upr[0] << " " << upr[1] << " " << upr[2] << " (" << uprime1 << ")" << endl;
28891
28892 // Konstantin: The initial spectrum is cut off for coarse LES grids which
28893 // results into a lower energy level. If uprime != 1, this energy
28894 // will be modified such that all resolved scales have the DNS-energy,
28895 // i.e. large scales get the energy which have been cut off at the small
28896 // scales.
28897 uprime1 = F1;
28898
28899 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28900 if(a_isHalo(cellId)) continue;
28901 if(a_isBndryGhostCell(cellId)) continue;
28902 if(a_level(cellId) != fftLevel) continue;
28903 // scale velocities such that mean urms is m_UInfinity
28904 MFloat u = a_pvariable(cellId, PV->U) * m_UInfinity / uprime1;
28905 MFloat v = a_pvariable(cellId, PV->V) * m_UInfinity / uprime1;
28906 MFloat w = a_pvariable(cellId, PV->W) * m_UInfinity / uprime1;
28907 MFloat p = a_pvariable(cellId, PV->P);
28908 MFloat rho = sysEqn().density_ES(p, m_TInfinity);
28909 a_variable(cellId, CV->RHO) = rho;
28910 a_variable(cellId, CV->RHO_U) = rho * u;
28911 a_variable(cellId, CV->RHO_V) = rho * v;
28912 a_variable(cellId, CV->RHO_W) = rho * w;
28913 IF_CONSTEXPR(hasE<SysEqn>) {
28914 a_variable(cellId, CV->RHO_E) = sysEqn().internalEnergy(p, rho, (POW2(u) + POW2(v) + POW2(w)));
28915 }
28916 a_pvariable(cellId, PV->U) = u;
28917 a_pvariable(cellId, PV->V) = v;
28918 a_pvariable(cellId, PV->W) = w;
28919 a_pvariable(cellId, PV->P) = p;
28920 a_pvariable(cellId, PV->RHO) = rho;
28921 }
28922
28923 exchangeDataFV(&a_variable(0, 0), noCVars, false, m_rotIndVarsPV);
28924 exchangeDataFV(&a_pvariable(0, 0), noPVars, false, m_rotIndVarsCV);
28925
28926 MFloat umean[3] = {F0, F0, F0};
28927 MFloat urms[6] = {F0, F0, F0, F0, F0, F0};
28928 MFloat reyn[6] = {F0, F0, F0, F0, F0, F0};
28929 MFloat aniso[6] = {F0, F0, F0, F0, F0, F0};
28930 MFloat dudx[3] = {F0, F0, F0};
28931 MFloat skew[4] = {F0, F0, F0, F0};
28932 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
28933 if(a_isHalo(cellId)) continue;
28934 if(a_isBndryGhostCell(cellId)) continue;
28935 if(a_level(cellId) != fftLevel) continue;
28936 MFloat u = a_pvariable(cellId, PV->U);
28937 MFloat v = a_pvariable(cellId, PV->V);
28938 MFloat w = a_pvariable(cellId, PV->W);
28939 for(MInt i = 0; i < nDim; i++) {
28940 MInt n0 = (a_hasNeighbor(cellId, 2 * i) > 0) ? c_neighborId(cellId, 2 * i) : cellId;
28941 MInt n1 = (a_hasNeighbor(cellId, 2 * i + 1) > 0) ? c_neighborId(cellId, 2 * i + 1) : cellId;
28942 if(n0 == n1) continue;
28943 dudx[i] += POW2((a_pvariable(n1, PV->VV[i]) - a_pvariable(n0, PV->VV[i]))
28944 / (a_coordinate(n1, i) - a_coordinate(n0, i)));
28945 skew[i] += POW3((a_pvariable(n1, PV->VV[i]) - a_pvariable(n0, PV->VV[i]))
28946 / (a_coordinate(n1, i) - a_coordinate(n0, i)));
28947 }
28948 urms[0] += POW2(u);
28949 urms[1] += POW2(v);
28950 urms[2] += POW2(w);
28951 urms[3] += u * v;
28952 urms[4] += u * w;
28953 urms[5] += v * w;
28954 umean[0] += u;
28955 umean[1] += v;
28956 umean[2] += w;
28957 }
28958 MPI_Allreduce(MPI_IN_PLACE, &urms[0], 6, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "urms[0]");
28959 MPI_Allreduce(MPI_IN_PLACE, &umean[0], 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "umean[0]");
28960 MPI_Allreduce(MPI_IN_PLACE, &dudx[0], 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "dudx[0]");
28961 MPI_Allreduce(MPI_IN_PLACE, &skew[0], 3, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "skew[0]");
28962 skew[3] = ((skew[0] + skew[1] + skew[2]) / (F3 * cnt)) / pow((dudx[0] + dudx[1] + dudx[2]) / (F3 * cnt), 1.5);
28963 for(MInt i = 0; i < 3; i++)
28964 skew[i] = (skew[i] / cnt) / pow(dudx[i] / cnt, 1.5);
28965 for(MInt i = 0; i < 6; i++)
28966 reyn[i] = urms[i] / cnt;
28967 for(MInt i = 0; i < 6; i++)
28968 aniso[i] = urms[i] / (urms[0] + urms[1] + urms[2]);
28969 for(MInt i = 0; i < 3; i++)
28970 aniso[i] -= F1B3;
28971 for(MInt i = 0; i < 6; i++)
28972 urms[i] = sqrt(fabs(urms[i]) / cnt);
28973 for(MInt i = 0; i < 3; i++)
28974 umean[i] /= cnt;
28975 for(MInt i = 0; i < 3; i++)
28976 dudx[i] /= cnt;
28977 MFloat lambda[3];
28978 MFloat Rel[4];
28979 MFloat eps[3];
28980 for(MInt i = 0; i < 3; i++)
28981 lambda[i] = urms[i] / sqrt(dudx[i]);
28982
28983 if(domainId() == 0)
28984 cerr << "u_mean: " << umean[0] << " " << umean[1] << " " << umean[2] << " (" << (MInt)cnt << ")" << endl;
28985 if(domainId() == 0)
28986 cerr << "u_rms/u_inf: " << urms[0] / m_UInfinity << " " << urms[1] / m_UInfinity << " "
28987 << urms[2] / m_UInfinity << " " << urms[3] / m_UInfinity << " " << urms[4] / m_UInfinity << " "
28988 << urms[5] / m_UInfinity << " (" << F1B3 * (urms[0] + urms[1] + urms[2]) / m_UInfinity << ")" << endl;
28989 if(domainId() == 0)
28990 cerr << "skewness: " << skew[0] << " " << skew[1] << " " << skew[2] << " (" << skew[3] << ")" << endl;
28991 if(domainId() == 0)
28992 cerr << "Anisotropy: " << aniso[0] << " " << aniso[1] << " " << aniso[2] << " " << aniso[3] << " "
28993 << aniso[4] << " " << aniso[5] << endl;
28994 if(domainId() == 0)
28995 cerr << "Reynolds stress: " << reyn[0] << " " << reyn[1] << " " << reyn[2] << " " << reyn[3] << " "
28996 << reyn[4] << " " << reyn[5] << endl;
28997 if(domainId() == 0)
28998 cerr << "Realizability 1: " << reyn[3] * reyn[3] << " <= " << reyn[0] * reyn[1] << ", " << reyn[4] * reyn[4]
28999 << " <= " << reyn[0] * reyn[2] << ", " << reyn[5] * reyn[5] << " <= " << reyn[1] * reyn[2] << endl;
29000 if(domainId() == 0)
29001 cerr << "Realizability 2: det = "
29002 << reyn[0] * reyn[1] * reyn[2] + F2 * reyn[3] * reyn[4] * reyn[5] - reyn[0] * reyn[5] * reyn[5]
29003 - reyn[1] * reyn[4] * reyn[4] - reyn[2] * reyn[4] * reyn[4]
29004 << " >= 0" << endl;
29005
29006 // prescribe Taylor microscale Reynolds number
29007 // Konstantin: ReLambda is unkown in LES and has to be defined to get the
29008 // same viscosity as in the DNS.
29009 const MFloat time1 = MPI_Wtime();
29010 m_log << "initFFT time " << time1 - time0 << endl;
29011 if(nx < 256) {
29024 if(!Context::propertyExists("ReLambdaOverwrite", m_solverId)) {
29025 mTerm(1, AT_, "Undefined ReLambda for LES grid.");
29026 }
29027 m_Re = Context::getSolverProperty<MFloat>("ReLambdaOverwrite", m_solverId, AT_) / m_referenceLength;
29028 sysEqn().m_Re0 = m_Re * SUTHERLANDLAW(m_TInfinity) / (m_rhoInfinity * m_UInfinity);
29029 m_log << "Overwritten Reynolds number: " << setprecision(15) << m_Re
29030 << " (Re_L=" << m_Re * (bbox[3] - bbox[0]) << ")"
29031 << " " << sysEqn().m_Re0 << endl;
29032 break;
29033 }
29034
29047 m_Re = Context::getSolverProperty<MFloat>("ReLambda", m_solverId, AT_) / m_referenceLength;
29048 m_Re *= F3 / (lambda[0] + lambda[1] + lambda[2]);
29049 // m_Re *= (sqrt(dudx[0])+sqrt(dudx[1])+sqrt(dudx[2]))/(urms[0]+urms[1]+urms[2]);
29050 sysEqn().m_Re0 = m_Re * SUTHERLANDLAW(m_TInfinity) / (m_rhoInfinity * m_UInfinity);
29051 m_log << "Computed Reynolds number: " << setprecision(15) << m_Re << " (Re_L=" << m_Re * (bbox[3] - bbox[0])
29052 << ")"
29053 << " " << sysEqn().m_Re0 << endl;
29054
29055 MFloat mue = SUTHERLANDLAW(m_TInfinity) / sysEqn().m_Re0;
29056 for(MInt i = 0; i < 3; i++)
29057 Rel[i] = m_rhoInfinity * urms[i] * lambda[i] / mue;
29058 Rel[3] =
29059 m_rhoInfinity * F1B3 * (urms[0] + urms[1] + urms[2]) * F1B3 * (lambda[0] + lambda[1] + lambda[2]) / mue;
29060 for(MInt i = 0; i < 3; i++)
29061 eps[i] = (15.0 * sysEqn().m_muInfinity * dudx[i]) * (bbox[nDim + i] - bbox[i])
29062 / (sysEqn().m_Re0 * POW3(urms[i]));
29063 if(domainId() == 0)
29064 cerr << "lambda: " << lambda[0] << " " << lambda[1] << " " << lambda[2] << " ("
29065 << F1B3 * (lambda[0] + lambda[1] + lambda[2]) << ")" << endl;
29066 if(domainId() == 0)
29067 cerr << "eps: " << eps[0] << " " << eps[1] << " " << eps[2] << " (" << F1B3 * (eps[0] + eps[1] + eps[2])
29068 << ")" << endl;
29069 if(domainId() == 0)
29070 cerr << "Re_lambda: " << Rel[0] << " " << Rel[1] << " " << Rel[2] << " (" << Rel[3] << ", "
29071 << F1B3 * (Rel[0] + Rel[1] + Rel[2]) << ")" << endl;
29072 if(domainId() == 0)
29073 cerr << "Kolmogorov length: "
29074 << pow(sysEqn().m_muInfinity / sysEqn().m_Re0, 0.75) / pow(F1B3 * (eps[0] + eps[1] + eps[2]), 0.25)
29075 << endl;
29076
29077
29078 MFloat maxd = mMax(fabs(Rel[0] - Rel[1]), mMax(fabs(Rel[0] - Rel[2]), fabs(Rel[1] - Rel[2])));
29079 if(maxd < F1) m_log << "spectrum " << maxd << " " << F1B3 * (Rel[0] + Rel[1] + Rel[2]) << " " << seed << endl;
29080 // if ( maxd < 0.3 && F1B3*(Rel[0]+Rel[1]+Rel[2]) > 79.0 ) {
29081 // if ( maxd < 0.3 ) {
29082 goodSpectrum = true;
29083 if(domainId() == 0) m_log << "spectrum " << seed << endl;
29084 //}
29085 //}
29086 }
29087 if(domainId() == 0) cerr << "seed " << seed << endl;
29088 m_randomDeviceSeed = seed;
29089 MPI_Barrier(mpiComm(), AT_);
29090
29091 if(fftLevel < maxRefinementLevel()) {
29092 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29093 if(a_isHalo(cellId)) continue;
29094 if(a_isBndryGhostCell(cellId)) continue;
29095 if(a_level(cellId) <= fftLevel) continue;
29096 if(c_noChildren(cellId) > 0) continue;
29097 MInt parentId = c_parentId(cellId);
29098 while(a_level(parentId) != fftLevel) {
29099 parentId = c_parentId(parentId);
29100 }
29101 if(a_level(parentId) == fftLevel) {
29102 for(MInt varId = 0; varId < noCVars; varId++) {
29103 a_variable(cellId, varId) = a_variable(parentId, varId);
29104 }
29105 for(MInt varId = 0; varId < noPVars; varId++) {
29106 a_pvariable(cellId, varId) = a_pvariable(parentId, varId);
29107 }
29108 }
29109 }
29110 }
29111
29112 exchangeDataFV(&a_pvariable(0, 0), noPVars, false, m_rotIndVarsPV);
29113 exchangeDataFV(&a_variable(0, 0), noCVars, false, m_rotIndVarsCV);
29114
29115 break;
29116 }
29117
29118 case 1155:
29119 /* 3D single round jet initial condition; simple extension to 2D from 3D version
29120 * Seong et. al. Turbulence and heat excited noise sources in single and coaxial jets,2010.
29121 * Onur Cetin, August 2013
29122 */
29123 {
29124 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29125 const MFloat radius = (nDim == 3) ? sqrt(POW2(a_coordinate(cellId, 1)) + POW2(a_coordinate(cellId, 2)))
29126 : a_coordinate(cellId, 1);
29127
29128 // Round jet
29129 if(radius <= 1.5 * m_jetHeight) {
29130 // const MFloat jet = F1B2 * (1 + tanh((F1B2 - radius) / (0.05 / 2))); // old version
29131 const MFloat jet = F1B2 * (1.0 + tanh((m_jetHeight - radius) / (2 * m_momentumThickness)));
29132 // Temperature profile with Crocco-Busemann
29133 const MFloat profile_T = sysEqn().CroccoBusemann(m_Ma, jet);
29134 // Set the density
29135 a_variable(cellId, CV->RHO) = m_rhoInfinity / profile_T;
29136 // Set the velocities // old version
29137 /* a_variable(cellId, CV->RHO_U) = a_variable(cellId, CV->RHO) * m_Ma * F1B2 */
29138 /* * (1 + tanh((F1B2 - radius) / (0.05 / 2))); */
29139 a_variable(cellId, CV->RHO_U) = a_variable(cellId, CV->RHO) * jet * m_VVInfinity[0];
29140 a_variable(cellId, CV->RHO_V) = F0;
29141 IF_CONSTEXPR(nDim == 3) a_variable(cellId, CV->RHO_W) = F0;
29142 // Set the energy
29143 IF_CONSTEXPR(hasE<SysEqn>)
29144 a_variable(cellId, CV->RHO_E) =
29145 m_PInfinity / gammaMinusOne
29146 + F1B2 * POW2(a_variable(cellId, CV->RHO_U)) / (a_variable(cellId, CV->RHO));
29147 }
29148 // Round jet end
29149 else {
29150 // zero velocity outside of the jet region;
29151 a_variable(cellId, CV->RHO) = m_rhoInfinity;
29152 a_variable(cellId, CV->RHO_V) = F0;
29153 a_variable(cellId, CV->RHO_U) = F0;
29154 IF_CONSTEXPR(nDim == 3) a_variable(cellId, CV->RHO_W) = F0;
29155 IF_CONSTEXPR(hasE<SysEqn>)
29156 a_variable(cellId, CV->RHO_E) =
29157 m_PInfinity / gammaMinusOne + F1B2 * POW2(a_variable(cellId, CV->RHO_U)) / m_rhoInfinity;
29158 }
29159 }
29160 break;
29161 }
29162
29163 case 1156:
29164 /* 3D round coaxial jet initial condition; simple extension to 2D from 3D version
29165 * Seong et. al. Turbulence and heat excited noise sources in single and coaxial jets,2010.
29166 * Onur Cetin, August 2013
29167 */
29168 {
29169 // Round jet region:
29170 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29171 // Round jet
29172 const MFloat radius = nDim == 3 ? sqrt(POW2(a_coordinate(cellId, 1)) + POW2(a_coordinate(cellId, 2)))
29173 : a_coordinate(cellId, 1);
29174
29175 if(radius <= m_primaryJetRadius) {
29176 // Hot air jet---
29177 //---------------
29178
29179 const MFloat jet = F1B2 * (1 + tanh((m_primaryJetRadius - radius) / (m_momentumThickness / 2)));
29180 // Temperature profile with Crocco-Busemann
29181 const MFloat profile_T = sysEqn().CroccoBusemann(m_Ma, jet) * m_densityRatio;
29182 // Set the density
29183 a_variable(cellId, CV->RHO) = m_rhoInfinity / profile_T;
29184 // Set the velocities (Take momentum thickness 0.05 ref:Bogey & Bailly)
29185 a_variable(cellId, CV->RHO_U) = a_variable(cellId, CV->RHO) * m_targetVelocityFactor * F1B2
29186 * (1 + tanh((m_primaryJetRadius - radius) / (m_momentumThickness / 2)));
29187 a_variable(cellId, CV->RHO_V) = F0;
29188 IF_CONSTEXPR(nDim == 3) a_variable(cellId, CV->RHO_W) = F0;
29189 // Set the energy
29190 IF_CONSTEXPR(hasE<SysEqn>)
29191 a_variable(cellId, CV->RHO_E) =
29192 m_PInfinity / gammaMinusOne
29193 + F1B2 * POW2(a_variable(cellId, CV->RHO_U)) / (a_variable(cellId, CV->RHO));
29194 }
29195
29196 else if(radius <= m_secondaryJetRadius && m_primaryJetRadius <= radius) {
29197 // Cold air jet---
29198 //----------------
29199 const MFloat jet = F1B2 * (1 + tanh((m_secondaryJetRadius - radius) / (2 * m_momentumThickness)));
29200 // Temperature profile
29201 const MFloat profile_T = sysEqn().CroccoBusemann(m_Ma, jet);
29202 // Set the density
29203 a_variable(cellId, CV->RHO) = m_rhoInfinity / profile_T;
29204 a_variable(cellId, CV->RHO_U) = a_variable(cellId, CV->RHO) * m_targetVelocityFactor
29205 * m_targetVelocityFactor * F1B2
29206 * (1 + tanh((m_secondaryJetRadius - radius) / (2 * m_momentumThickness)));
29207 a_variable(cellId, CV->RHO_V) = F0;
29208 IF_CONSTEXPR(nDim == 3) a_variable(cellId, CV->RHO_W) = F0;
29209 // Set the energy
29210 IF_CONSTEXPR(hasE<SysEqn>)
29211 a_variable(cellId, CV->RHO_E) =
29212 m_PInfinity / gammaMinusOne
29213 + F1B2 * POW2(a_variable(cellId, CV->RHO_U)) / a_variable(cellId, CV->RHO);
29214 }
29215 // Round jet end
29216 else {
29217 // zero velocity outside of the jet region;
29218
29219 a_variable(cellId, CV->RHO) = m_rhoInfinity;
29220 a_variable(cellId, CV->RHO_U) = F0;
29221 a_variable(cellId, CV->RHO_V) = F0;
29222 IF_CONSTEXPR(nDim == 3) a_variable(cellId, CV->RHO_W) = F0;
29223 IF_CONSTEXPR(hasE<SysEqn>)
29224 a_variable(cellId, CV->RHO_E) =
29225 m_PInfinity / gammaMinusOne + F1B2 * POW2(a_variable(cellId, CV->RHO_U)) / m_rhoInfinity;
29226 }
29227 }
29228 break;
29229 }
29230
29231 case 1164: // Initial conditions for jets with chevron nozzles
29232 /* Compare Xia et. al. 2009, 1067-1079, Int.J.Heat&Fluid
29233 * Xia 2015, 189-197, Comp&Fluids
29234 *
29235 * IC for chevron nozzle jet flow smc000 configuration with the reference length D_j = 1.0
29236 */
29237 {
29238 // const MFloat inletRadius = m_inletRadius;
29239 const MFloat outletRadius = m_outletRadius;
29240 const MFloat scale = 1.0; // TODO labels:FV from vitali, not used so far
29241 const MFloat nozzleExit = 2.5959; // TODO labels:FV FIXME hard-coded nozzle exit position
29242
29243 // exit conditions
29244 const MFloat mach_j = m_nozzleExitMaJet;
29245 const MFloat temperature_j = m_nozzleExitTemp;
29246 const MFloat density_j = m_nozzleExitRho;
29247 // ambient conditions
29248 const MFloat pressureAmbient = m_PInfinity;
29249 const MFloat densityAmbient = m_rhoInfinity;
29250
29251 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29252 const MFloat x = a_coordinate(cellId, 0);
29253 // Initialisation of the surrounding domain
29254 a_variable(cellId, CV->RHO) = densityAmbient;
29255 a_variable(cellId, CV->RHO_U) = 0.0;
29256 a_variable(cellId, CV->RHO_V) = 0.0;
29257 a_variable(cellId, CV->RHO_W) = 0.0;
29258 IF_CONSTEXPR(hasE<SysEqn>)
29259 a_variable(cellId, CV->RHO_E) = sysEqn().internalEnergy(pressureAmbient, densityAmbient, 0.0);
29260
29261 // Note: assumes center of nozzle is y=z=0.0 and various other nozzle specific
29262 // parameters
29263 const MFloat radius = sqrt(POW2(a_coordinate(cellId, 1) - 0.0) + POW2(a_coordinate(cellId, 2) - 0.0));
29264
29265 MFloat splineRadius = m_inletRadius;
29266 MFloat Ma_x = m_maNozzleInlet;
29267
29268 // Check the spline functions
29269 if((x >= -1.0 * scale) && (x < 0.0 * scale)) {
29270 splineRadius = m_inletRadius;
29271 Ma_x = m_maNozzleInlet;
29272 }
29273
29274 if((x >= 0.0 * scale) && (x < 0.25 * scale)) {
29275 splineRadius = (0.000352 * x * x * x) / (scale * scale) - (0.678568 * x * x) / scale + 0.84 * scale;
29276 Ma_x = m_maNozzleInlet;
29277 }
29278
29279 if((x >= 0.25 * scale) && (x < 2.19473 * scale)) {
29280 splineRadius = -(0.049195 * x * x * x) / (scale * scale) + (0.236615 * x * x) / scale - 0.445812 * x
29281 + 0.89286 * scale;
29282 Ma_x = 0.5;
29283 }
29284
29285 if((x >= 2.19473 * scale) && (x < 2.5959 * scale)) {
29286 splineRadius = -(0.00011 * x * x * x) / (scale * scale) + (0.00072617 * x * x) / scale - 0.08883 * x
29287 + 0.727624 * scale;
29288 Ma_x = 0.85;
29289 }
29290
29291 // Newton-Method for calculating Ma_x = Ma(x)
29292 const MInt newtonSteps = 5;
29293 for(MInt n = 0; n < newtonSteps; n++) {
29294 const MFloat fkt_g = POW2(m_outletRadius / splineRadius) * m_maNozzleExit
29295 / pow(1 / (sysEqn().temperature_IR(m_maNozzleExit)), 3);
29296 const MFloat diff_g = -625 * (1 - POW2(Ma_x)) / pow(POW2(Ma_x) + 5, 4); // = g'(x_n)
29297 Ma_x = Ma_x - fkt_g / diff_g;
29298 }
29299
29300 // Check the spline functions
29301 if((x >= -1.0 * scale) && (x < 0.0 * scale)) {
29302 splineRadius = m_inletRadius;
29303 Ma_x = m_maNozzleInlet;
29304 }
29305
29306 if((x <= nozzleExit * scale) && (radius <= splineRadius)) {
29307 // Within the nozzle
29308 const MFloat temperature_x = sysEqn().temperature_IR(Ma_x);
29309 const MFloat pressure_x = sysEqn().pressure_IR(temperature_x);
29310 const MFloat density_x = sysEqn().density_ES(pressure_x, temperature_x);
29311 const MFloat u_jet = Ma_x * sysEqn().speedOfSound(temperature_x);
29312 const MFloat deltaMomentum = m_momentumThickness * splineRadius;
29313 const MFloat jet = tanh((splineRadius - radius) / (2.0 * deltaMomentum));
29314
29315 // With Crocco-Busemann:
29316 a_variable(cellId, CV->RHO) = density_x / sysEqn().CroccoBusemann(Ma_x, jet);
29317 // Without Crocco-Busemann:
29318 // a_variable(cellId, CV->RHO) = density_x;
29319
29320 a_variable(cellId, CV->RHO_U) = a_variable(cellId, CV->RHO) * u_jet * jet;
29321 a_variable(cellId, CV->RHO_V) = 0.0;
29322 a_variable(cellId, CV->RHO_W) = 0.0;
29323
29324 IF_CONSTEXPR(hasE<SysEqn>) {
29325 a_variable(cellId, CV->RHO_E) =
29326 sysEqn().internalEnergy(pressure_x, a_variable(cellId, CV->RHO), POW2(u_jet * jet));
29327 }
29328
29329 } else if((x >= nozzleExit * scale) && (x <= 4.5 * scale) && (radius <= outletRadius)) {
29330 // Downstream of nozzle exit
29331 const MFloat xFactor = 0.5 * (1.0 + cos(PI / ((4.5 - nozzleExit) * scale) * (x - nozzleExit * scale)));
29332 const MFloat deltaMomentum = m_momentumThickness * outletRadius;
29333
29334 const MFloat u_jet = xFactor * m_maNozzleExit * sqrt(temperature_j);
29335 const MFloat jet = tanh((outletRadius - radius) / (2.0 * deltaMomentum));
29336
29337 // With Crocco-Busemann:
29338 const MFloat density_crocco = density_j / sysEqn().CroccoBusemann(mach_j, jet);
29339 // Without Crocco-Busemann:
29340 // MFloat density_crocco = density_j;
29341
29342 a_variable(cellId, CV->RHO) = densityAmbient + (density_crocco - densityAmbient) * xFactor;
29343
29344 a_variable(cellId, CV->RHO_U) = a_variable(cellId, CV->RHO) * u_jet * jet;
29345 a_variable(cellId, CV->RHO_V) = 0.0;
29346 a_variable(cellId, CV->RHO_W) = 0.0;
29347
29348 IF_CONSTEXPR(hasE<SysEqn>) {
29349 a_variable(cellId, CV->RHO_E) =
29350 pressureAmbient / (m_gamma - 1)
29351 + 0.5 * POW2(a_variable(cellId, CV->RHO_U)) / (a_variable(cellId, CV->RHO));
29352 }
29353 }
29354 }
29355 break;
29356 }
29357
29358 // pipe --> Alexej Pogorelov
29359 case 34: {
29360 IF_CONSTEXPR(nDim == 2) mTerm(-1, "Pipe IC in 2D meaningless, because of the use of deltaP_pipe!");
29361
29374 MBool fluctuations = false;
29375 fluctuations = Context::getSolverProperty<MBool>("fluctuations", m_solverId, AT_, &fluctuations);
29376
29377 MFloat UT = m_Ma * sqrt(m_TInfinity);
29378
29379 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29380 m_deltaP = 0.3164 / sqrt(sqrt(sysEqn().m_Re0)) * m_referenceLength * F1B2 * m_rhoInfinity * POW2(UT);
29381 // m_deltaP = 64 / m_Re0 * F1 / m_referenceLength * F1B2 * m_rhoInfinity * POW2(UT);
29382 m_fvBndryCnd->m_deltaP = m_deltaP;
29383
29384
29385 MFloat radius_1 =
29386 sqrt((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) * (a_coordinate(cellId, 1) - m_rotAxisCoord[0])
29387 + (a_coordinate(cellId, 2) - m_rotAxisCoord[1]) * (a_coordinate(cellId, 2) - m_rotAxisCoord[1]));
29388 MFloat fk = 0;
29389
29390 if((a_coordinate(cellId, 0) > 4.0 && a_coordinate(cellId, 0) < 1.0)
29391 && radius_1 > 0.45) { // FIXME labels:FV,toenhance This can never be satisfied
29392 fk = 0;
29393 } else {
29394 if(cellId % 2 == 0) {
29395 fk = -F1;
29396 } else {
29397 fk = F1;
29398 }
29399 }
29400
29401 if(!fluctuations) {
29402 fk = 0.0;
29403 }
29404
29405 a_variable(cellId, CV->RHO) = m_rhoInfinity;
29406 a_variable(cellId, CV->RHO_VV[0]) = m_rhoVVInfinity[0] * 2.0 * (1.0 - (radius_1 / 0.5) * (radius_1 / 0.5))
29407 + (MFloat(rand()) / RAND_MAX) * 0.005 * UT * fk;
29408 for(MInt d = 1; d < nDim; d++) {
29409 a_variable(cellId, CV->RHO_VV[d]) = m_rhoVVInfinity[d] + (MFloat(rand()) / RAND_MAX) * 0.005 * UT * fk;
29410 }
29411 const MFloat pressure = m_PInfinity; // - m_deltaP *
29412 //( a_coordinate( cellId , 0 ) );
29413 MFloat velPOW2 = 0;
29414 for(MInt d = 0; d < nDim; d++)
29415 velPOW2 += POW2(a_variable(cellId, CV->RHO_VV[d]));
29416 IF_CONSTEXPR(hasE<SysEqn>)
29417 a_variable(cellId, CV->RHO_E) = pressure / gammaMinusOne + F1B2 * velPOW2 / m_rhoInfinity;
29418 }
29419 break;
29420 }
29421
29422 // cyl 3d
29423 case 36: {
29424 IF_CONSTEXPR(nDim == 2) mTerm(-1, "Pipe IC with 3D features in 2D meaningless!");
29425
29426 MFloat UT = m_Ma * sqrt(m_TInfinity);
29427 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29428 m_deltaP = 3.0 * 64.0 / sysEqn().m_Re0 * F1 / m_referenceLength * F1B2 * m_rhoInfinity * POW2(m_UInfinity);
29429 m_fvBndryCnd->m_deltaP = m_deltaP;
29430
29431 MFloat radius_1 =
29432 sqrt((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) * (a_coordinate(cellId, 1) - m_rotAxisCoord[0])
29433 + (a_coordinate(cellId, 2) - m_rotAxisCoord[1]) * (a_coordinate(cellId, 2) - m_rotAxisCoord[1]));
29434
29435 MFloat phi_1 = 0;
29436 if((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) >= 0 && (a_coordinate(cellId, 2) - m_rotAxisCoord[1]) >= 0) {
29437 phi_1 = asin((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) / radius_1);
29438 } else if((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) >= 0
29439 && (a_coordinate(cellId, 2) - m_rotAxisCoord[1]) < 0) {
29440 phi_1 = PI - asin((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) / radius_1);
29441 } else if((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) < 0
29442 && (a_coordinate(cellId, 2) - m_rotAxisCoord[1]) < 0) {
29443 phi_1 = PI - asin((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) / radius_1);
29444 } else {
29445 phi_1 = 2 * PI + asin((a_coordinate(cellId, 1) - m_rotAxisCoord[0]) / radius_1);
29446 }
29447 MFloat fk = 0;
29448
29449 // if((a_coordinate(cellId, 0) > 73.0 && a_coordinate(cellId, 0) < 1.0) && radius_1
29450 // > 24.0) {
29451 // fk = 0;
29452 //}
29453 // else {
29454 // if(cellId % 2 == 0) {
29455 // fk = 0.0;//-F1;
29456 //} else { fk = 0.0; }// F1;
29457 //}
29458 a_variable(cellId, CV->RHO) = m_rhoInfinity;
29459 a_variable(cellId, CV->RHO_VV[0]) = m_rhoVVInfinity[0] + (MFloat(rand()) / RAND_MAX) * 0.0005 * UT * fk;
29460 a_variable(cellId, CV->RHO_VV[1]) =
29461 m_rhoVVInfinity[1] * cos(phi_1) / 29.0 * radius_1 + (MFloat(rand()) / RAND_MAX) * 0.0005 * UT * fk;
29462 a_variable(cellId, CV->RHO_VV[2]) =
29463 -m_rhoVVInfinity[1] * sin(phi_1) / 29.0 * radius_1 + (MFloat(rand()) / RAND_MAX) * 0.0005 * UT * fk;
29464 const MFloat pressure = m_PInfinity; // - m_deltaP *
29465
29466 IF_CONSTEXPR(hasE<SysEqn>)
29467 a_variable(cellId, CV->RHO_E) =
29468 pressure / gammaMinusOne
29469 + (F1B2
29470 * (POW2(m_rhoVVInfinity[0]) + POW2(m_rhoVVInfinity[1] * cos(phi_1) / 29.0 * radius_1)
29471 + POW2(m_rhoVVInfinity[1] * sin(phi_1) / 29.0 * radius_1)))
29472 * m_rhoInfinity;
29473 }
29474 break;
29475 }
29476 case 21: {
29477 IF_CONSTEXPR(nDim == 2) mTerm(-1, "Pipe IC with 3D features in 2D meaningless!");
29478
29479 // circular pipe flow with square profile
29480 MFloat UT = m_Ma * sqrt(m_TInfinity);
29481 m_deltaP = 0.3164 / sqrt(sqrt(sysEqn().m_Re0)) * F5 * m_referenceLength * F1B2 * m_rhoInfinity * POW2(UT);
29482
29483 m_fvBndryCnd->m_deltaP = m_deltaP;
29484 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29485 const MFloat pressure = m_PInfinity;
29486
29487 a_variable(cellId, CV->RHO) = m_rhoInfinity;
29488
29489 a_variable(cellId, CV->RHO_U) = F0;
29490 if(fabs(a_coordinate(cellId, 0)) < 0.2 || fabs(a_coordinate(cellId, 2)) < 0.2) {
29491 a_variable(cellId, CV->RHO_V) = m_rhoVInfinity;
29492 } else {
29493 a_variable(cellId, CV->RHO_V) = F0;
29494 }
29495 a_variable(cellId, CV->RHO_W) = F0;
29496
29497 IF_CONSTEXPR(hasE<SysEqn>)
29498 a_variable(cellId, CV->RHO_E) =
29499 pressure / gammaMinusOne
29500 + (F1B2
29501 * (POW2(a_variable(cellId, CV->RHO_VV[0])) + POW2(a_variable(cellId, CV->RHO_VV[1]))
29502 + POW2(a_variable(cellId, CV->RHO_VV[2]))))
29503 / m_rhoInfinity;
29504 }
29505
29506 break;
29507 }
29508 case 22: { // round pipe -- Konstantin, Laurent (check also updateInfinityVar in FVMB)
29509 IF_CONSTEXPR(nDim == 2) mTerm(-1, AT_, "Pipe flow only implemented in 3D.");
29510
29511 MFloat noPeriodicDirs = 0;
29512 for(MInt dim = 0; dim < nDim; dim++) {
29513 if(grid().periodicCartesianDir(dim)) {
29514 m_volumeForcingDir = dim;
29515 noPeriodicDirs++;
29516 }
29517 }
29518 if(noPeriodicDirs > 1) mTerm(1, AT_, "Only one periodic direction is implemented for the pipe case");
29519 if(m_volumeForcingDir == -1) mTerm(-1, AT_, "IC 22 requires a volumeForcingDir");
29520
29521 // Reynolds set in properties is based on unit length L=1
29522 MInt Re_r = Context::getSolverProperty<MFloat>("Re", m_solverId, AT_) * m_pipeRadius;
29523 m_pipeRadius = Context::getSolverProperty<MFloat>("pipeRadius", m_solverId, AT_);
29524
29525 MBool fluctuations = false;
29526 fluctuations = Context::getSolverProperty<MBool>("pipeFluctuations", m_solverId, AT_, &fluctuations);
29527 MFloat fluctuationsPercentage = 0.005;
29528 fluctuationsPercentage =
29529 Context::getSolverProperty<MFloat>("pipeFluctuationsPercentage", m_solverId, AT_, &fluctuationsPercentage);
29530
29531 // Any other perpendicular direction indicates the pipe diameter
29532 const MInt rDir1 = ((m_volumeForcingDir + 1) % nDim);
29533 const MInt rDir2 = ((rDir1 + 1) % nDim);
29534 if(rDir1 == rDir2 || rDir1 == m_volumeForcingDir || rDir2 == m_volumeForcingDir)
29535 mTerm(-1, AT_, "Inconsistent dirs.");
29536
29537 const MFloat pipeLength = computeDomainLength(m_volumeForcingDir);
29538
29539 cerr0 << "Intialized with IC 22: found pipeRadius = " << m_pipeRadius << " and pipeLength = " << pipeLength
29540 << ". Fluctuations: " << fluctuations << " (" << fluctuationsPercentage << ")" << endl;
29541
29542 MFloat lambda = F0;
29543 MFloat uMax = F2 * m_UInfinity;
29544 if(Re_r < 1500) {
29545 lambda = 32.0 / Re_r;
29546 if(domainId() == 0) cerr << "IC 22, using case Re<1500" << endl;
29547 } else {
29548 lambda = 0.316 / pow(Re_r * F2, 0.25);
29549 if(domainId() == 0) cerr << "IC 22, using case Re>=1500" << endl;
29550 }
29551 MFloat reTau = Re_r * sqrt(lambda / F8);
29552 MFloat uTau = reTau * m_Ma * sqrt(m_TInfinity) / Re_r;
29553 MFloat deltaP = F2 * m_rhoInfinity * POW2(uTau) * (pipeLength) / m_pipeRadius;
29554 m_volumeAcceleration[m_volumeForcingDir] = deltaP / (m_rhoInfinity * pipeLength);
29555
29556 MFloat rMin = m_pipeRadius / F2;
29557 MFloat ampl = uMax * (F1 - POW2((m_pipeRadius - rMin / F4) / m_pipeRadius));
29558 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29559 if(a_isHalo(cellId)) continue;
29560 if(a_isPeriodic(cellId)) continue;
29561 if(a_isBndryGhostCell(cellId)) continue;
29562 // center of mass should be in the pipe axis
29563 const MFloat r = sqrt(POW2(a_coordinate(cellId, rDir1)) + POW2(a_coordinate(cellId, rDir2)));
29564
29565 MFloat fk = F0;
29566 MFloat u = F0;
29567 // if within pipe set streamwise velocity to u else 0
29568 if(r <= m_pipeRadius) {
29569 if(Re_r > 1500) {
29570 const MFloat dist = m_pipeRadius - r;
29571 // faster convergence towards a turbulent profile via initial shear layer
29572 u = (dist > rMin ? (F1 - POW2(r / rMin)) * uMax : sin(dist / rMin * F2 * M_PI) * ampl);
29573 } else {
29574 u = (F1 - POW2(r / m_pipeRadius)) * uMax; // parabolic Poiseuille profile
29575 }
29576 if(fluctuations) {
29577 if(cellId % 2 == 0)
29578 fk = -F1;
29579 else
29580 fk = F1;
29581 }
29582 }
29583 MFloat fluct = fluctuationsPercentage * m_UInfinity * fk;
29584 a_pvariable(cellId, PV->VV[m_volumeForcingDir]) = u + (MFloat(rand()) / RAND_MAX) * fluct;
29585 a_pvariable(cellId, PV->VV[rDir1]) = (MFloat(rand()) / RAND_MAX) * fluct;
29586 a_pvariable(cellId, PV->VV[rDir2]) = (MFloat(rand()) / RAND_MAX) * fluct;
29587 a_pvariable(cellId, PV->P) = m_PInfinity;
29588 a_pvariable(cellId, PV->RHO) = sysEqn().density_ES(m_PInfinity, m_TInfinity);
29589 }
29590 exchange();
29591 computeConservativeVariables();
29592 break;
29593 }
29594 case 30:
29595 case 45302: { // careful, special setting for TINA engine triggered with TINA_TC keyword!
29596 IF_CONSTEXPR(nDim == 2) mTerm(-1, "This is a 3D IC!");
29597 MFloat UT = m_Ma * sqrt(m_TInfinity);
29598 if((string2enum(m_testCaseName) == SUZI_TC) || (string2enum(m_testCaseName) == TINA_TC)) {
29599 m_deltaP = 64 / sysEqn().m_Re0 * F1 / m_referenceLength * F1B2 * m_rhoInfinity * POW2(UT) / 10.0;
29600 } else {
29601 m_deltaP = 64 / sysEqn().m_Re0 * F1 / m_referenceLength * F1B2 * m_rhoInfinity * POW2(UT) / 5.0;
29602 }
29603 m_log << " Initializing pressure difference: m_deltaP = " << m_deltaP
29604 << " (built with m_Re0 = " << sysEqn().m_Re0 << " , refLength = " << m_referenceLength << ")" << endl;
29605 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29606 a_variable(cellId, CV->RHO) = 1.0;
29607 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
29608 a_variable(cellId, CV->RHO_VV[spaceId]) = 0;
29609 }
29610 IF_CONSTEXPR(hasE<SysEqn>)
29611 a_variable(cellId, CV->RHO_E) = sysEqn().pressureEnergy(sysEqn().p_Ref());
29612 }
29613
29614 computePV();
29615
29616 for(MInt bndryId = 0; bndryId < m_bndryCells->size(); bndryId++) {
29617 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
29618 for(MInt srfc = 0; srfc < m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
29619 for(MInt v = 0; v < PV->noVariables; v++) {
29620 // compute initial image point value
29621 m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_imageVariables[v] =
29622 a_pvariable(cellId, v);
29623 a_pvariable(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId, v) =
29624 a_pvariable(cellId, v);
29625 }
29626 }
29627 }
29628 break;
29629 }
29630
29633 case 1751600:
29634 case 2751600: {
29635 IF_CONSTEXPR(nDim == 2) mTerm(-1, "This is a 3D IC!");
29636 IF_CONSTEXPR(!hasPV_C<SysEqn>::value) mTerm(1, AT_, "SysEqn not suitable!");
29637 else {
29638 MFloat err = 0.01;
29639 MFloat activationTemperature = 30;
29640 MFloat alpha = F1 - F1 / mMax(1.1, m_burntUnburntTemperatureRatio);
29641 MFloat beta = alpha * activationTemperature / m_burntUnburntTemperatureRatio;
29642 MFloat filteredFlameThickness = 10.0 * m_subfilterVariance * c_cellLengthAtLevel(maxRefinementLevel());
29643 MFloat theta = F0, c = F0, x, xCoord, zCoord;
29644 MFloat jetArea = F0, jetInflowArea = F0, massflux = F0;
29645 MFloat factor1, factor2;
29646
29647 //---
29648 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29649 xCoord = a_coordinate(cellId, 0);
29650 zCoord = a_coordinate(cellId, 2);
29651
29652 if((xCoord > -m_radiusFlameTube - err) && (xCoord < m_radiusFlameTube + err)
29653 && (zCoord > -m_jetHalfLength - err) && (zCoord < m_jetHalfLength + err)) {
29654 MFloat minXG = ABS(xCoord) - (m_jetHalfWidth + err);
29655 MFloat minZG = ABS(zCoord) - (m_jetHalfLength + err);
29656 MFloat maxG = mMax(minXG, minZG);
29657
29658 x = sqrt(2.0 - 1.0) * m_initialFlameHeight * maxG + a_coordinate(cellId, 1) - m_yOffsetFlameTube;
29659
29660 if(x < F0) {
29661 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
29662 c = m_c0 * exp(x / filteredFlameThickness);
29663 // progress variabel in unburnt premixed gas
29664 } else {
29665 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
29666 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
29667 // progress variabel in burnt premixed gas
29668 }
29669 } else {
29670 x = a_coordinate(cellId, 1) - 1.0;
29671 if(x < F0) {
29672 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
29673 c = m_c0 * exp(x / filteredFlameThickness);
29674 } else {
29675 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
29676 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
29677 }
29678 }
29679 // compute the density
29680 a_variable(cellId, CV->RHO) =
29681 m_rhoFlameTube + (m_rhoFlameTube / m_burntUnburntTemperatureRatio - m_rhoFlameTube) * theta;
29682 // compute the specific momentum
29683 a_variable(cellId, CV->RHO_U) = F0;
29684 a_variable(cellId, CV->RHO_W) = F0;
29685
29686 factor1 = a_coordinate(cellId, 0);
29687 // factor2 = a_coordinate( cellId , 1);
29688 factor2 = a_coordinate(cellId, 2);
29689
29690
29691 if(fabs(a_coordinate(cellId, 0)) <= m_jetHalfWidth && fabs(a_coordinate(cellId, 2)) <= m_jetHalfLength
29692 && fabs(a_coordinate(cellId, 1)) <= 4.5) {
29693 a_variable(cellId, CV->RHO_V) = a_variable(cellId, CV->RHO) * m_Ma
29694 * (F1B2 * (1 + tanh(m_shearLayerThickness * (factor1 + m_jetHalfWidth)))
29695 * (1 - tanh(m_shearLayerThickness * (factor1 - m_jetHalfWidth)))
29696 - 1)
29697 * (F1B2 * (1 + tanh(m_shearLayerThickness * (factor2 + m_jetHalfLength)))
29698 * (1 - tanh(m_shearLayerThickness * (factor2 - m_jetHalfLength)))
29699 - 1);
29700
29701 jetArea = POW2(c_cellLengthAtCell(cellId));
29702 if(cellId < noInternalCells() && c_isLeafCell(cellId)) {
29703 massflux += a_variable(cellId, CV->RHO_V) * jetArea;
29704 jetInflowArea += jetArea;
29705 }
29706 } else {
29707 a_variable(cellId, CV->RHO_V) = a_variable(cellId, CV->RHO) * m_Ma * 0.5;
29708 }
29709
29710
29711 // a_variable( cellId , CV->RHO_E ) = m_pressureFlameTube / gammaMinusOne + F1B2 *
29712 // POW2( m_velocityFlameTube ) * a_variable( cellId , CV->RHO );
29713 // progress variable
29714 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
29715 a_variable(cellId, CV->RHO_C) = a_variable(cellId, CV->RHO) * c;
29716 }
29717
29718 MPI_Allreduce(MPI_IN_PLACE, &massflux, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "massflux");
29719 MPI_Allreduce(MPI_IN_PLACE, &jetInflowArea, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
29720 "jetInflowArea");
29721
29722 // compute massflux per unit area
29723 massflux /= jetInflowArea;
29724
29725 // compute static pressure and density iteratively (see e.g. thesis of Ingolf Hoerschler)
29726 m_jetPressure = sysEqn().p_Ref();
29727 for(MInt i = 0; i < 20; i++) {
29728 m_jetPressure = pow((1 - gammaMinusOne / F2 * pow(m_jetPressure, -2.0 / m_gamma) * POW2(massflux)),
29729 (m_gamma * FgammaMinusOne));
29730 }
29731 m_jetDensity = sysEqn().density_IR_P(m_jetPressure);
29732 m_jetPressure = m_jetPressure / m_gamma;
29733 m_jetTemperature = sysEqn().temperature_ES(m_jetDensity, m_jetPressure);
29734 m_log << "calculated pressure" << m_jetPressure << endl;
29735 m_log << "calculated density" << m_jetDensity << endl;
29736 m_log << "calculated temperature" << m_jetTemperature << endl;
29737 m_log << "calculated massflux" << massflux << endl;
29738
29739
29740 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29741 IF_CONSTEXPR(hasE<SysEqn>)
29742 a_variable(cellId, CV->RHO_E) =
29743 m_jetPressure / gammaMinusOne + F1B2 * POW2(a_variable(cellId, CV->RHO_V)) / m_rhoInfinity;
29744 }
29745 }
29746
29747 break;
29748 }
29749 case 5401000: {
29750 IF_CONSTEXPR(!hasPV_C<SysEqn>::value) mTerm(1, AT_, "SysEqn not suitable!");
29751 else {
29752 MFloat err = 0.0001;
29753 MFloat activationTemperature = 30;
29754 MFloat alpha = F1 - F1 / mMax(1.1, m_burntUnburntTemperatureRatio);
29755 MFloat beta = alpha * activationTemperature / m_burntUnburntTemperatureRatio;
29756 MFloat filteredFlameThickness = 10.0 * m_subfilterVariance * c_cellLengthAtLevel(maxRefinementLevel());
29757 MFloat theta = F0, c = F0, x, xCoord, zCoord;
29758 MFloat jetArea = F0, jetInflowArea = F0, massflux = F0;
29759 MFloat radius;
29760
29761 //---
29762 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29763 xCoord = a_coordinate(cellId, 0);
29764 zCoord = a_coordinate(cellId, 2);
29765 radius = sqrt(POW2(xCoord) + POW2(zCoord));
29766
29767 if((radius > -0.52 - err) && (radius < 0.52 + err)) {
29768 MFloat maxG = ABS(radius) - (0.52 + err);
29769 x = sqrt(2.0 - 1.0) * m_initialFlameHeight * maxG + a_coordinate(cellId, 1) - m_yOffsetFlameTube;
29770
29771 if(x < F0) {
29772 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
29773 c = m_c0 * exp(x / filteredFlameThickness);
29774 // progress variabel in unburnt premixed gas
29775 } else {
29776 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
29777 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
29778 // progress variabel in burnt premixed gas
29779 }
29780 } else {
29781 x = a_coordinate(cellId, 1) - 1.0;
29782 if(x < F0) {
29783 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
29784 c = m_c0 * exp(x / filteredFlameThickness);
29785 } else {
29786 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
29787 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
29788 }
29789 }
29790 // compute the density
29791 a_variable(cellId, CV->RHO) =
29792 m_rhoFlameTube + (m_rhoFlameTube / m_burntUnburntTemperatureRatio - m_rhoFlameTube) * theta;
29793 // compute the specific momentum
29794 a_variable(cellId, CV->RHO_U) = F0;
29795 a_variable(cellId, CV->RHO_W) = F0;
29796
29797 radius = sqrt(POW2(xCoord) + POW2(zCoord));
29798
29799
29800 if(radius <= 0.52 && fabs(a_coordinate(cellId, 1)) <= 4.5) {
29801 a_variable(cellId, CV->RHO_V) = a_variable(cellId, CV->RHO) * m_Ma
29802 * (F1B2 * (1 + tanh(m_shearLayerThickness * (radius + 0.5)))
29803 * (1 - tanh(m_shearLayerThickness * (radius - 0.5)))
29804 - 1);
29805
29806 jetArea = POW2(c_cellLengthAtCell(cellId));
29807 if(cellId < noInternalCells() && c_isLeafCell(cellId)) {
29808 massflux += a_variable(cellId, CV->RHO_V) * jetArea;
29809 jetInflowArea += jetArea;
29810 }
29811 } else {
29812 a_variable(cellId, CV->RHO_V) = a_variable(cellId, CV->RHO) * m_Ma * 0.5;
29813 }
29814 // progress variable
29815 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
29816 a_variable(cellId, CV->RHO_C) = a_variable(cellId, CV->RHO) * c;
29817 }
29818
29819 MPI_Allreduce(MPI_IN_PLACE, &massflux, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "massflux");
29820 MPI_Allreduce(MPI_IN_PLACE, &jetInflowArea, 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
29821 "jetInflowArea");
29822
29823 // compute massflux per unit area
29824 massflux /= jetInflowArea;
29825
29826 // compute static pressure and density iteratively (see e.g. thesis of Ingolf Hoerschler)
29827 m_jetPressure = sysEqn().p_Ref();
29828 for(MInt i = 0; i < 20; i++) {
29829 m_jetPressure = pow((1 - gammaMinusOne / F2 * pow(m_jetPressure, -2.0 / m_gamma) * POW2(massflux)),
29830 (m_gamma * FgammaMinusOne));
29831 }
29832 m_jetDensity = sysEqn().density_IR_P(m_jetPressure);
29833 m_jetPressure = m_jetPressure / m_gamma;
29834 m_jetTemperature = sysEqn().temperature_ES(m_jetDensity, m_jetPressure);
29835 m_log << "calculated pressure" << m_jetPressure << endl;
29836 m_log << "calculated density" << m_jetDensity << endl;
29837 m_log << "calculated temperature" << m_jetTemperature << endl;
29838 m_log << "calculated massflux" << massflux << endl;
29839
29840
29841 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29842 IF_CONSTEXPR(hasE<SysEqn>)
29843 a_variable(cellId, CV->RHO_E) =
29844 m_jetPressure / gammaMinusOne + F1B2 * POW2(a_variable(cellId, CV->RHO_V)) / m_rhoInfinity;
29845 }
29846 }
29847
29848 break;
29849 }
29850
29851 case 1184: { // initial condition for fvape::lae convergence test: pulse for RHO_U
29852 if(Context::getSolverProperty<MString>("solvertype", m_solverId, AT_) != "MAIA_FV_APE") {
29853 mTerm(1, "this initial condition is for the FV_APE solver only");
29854 }
29855 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29856 // compute squared distance from pulse center at (0.5,0.5) for 2D and (0.5, 0.5, 0.5) for
29857 // 3D cases
29858 MFloat pulse_center_length_unnormed = 0.0;
29859 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
29860 pulse_center_length_unnormed += std::pow(a_coordinate(cellId, spaceId) - 0.5, 2.0);
29861 }
29862 // set other variables to free stream values
29863 IF_CONSTEXPR(hasE<SysEqn>)
29864 a_variable(cellId, CV->RHO_E) = m_rhoEInfinity;
29865 a_variable(cellId, CV->RHO) = m_rhoInfinity;
29866
29867 // initialize velocity densities in y (and z) - direction to zero (just to be sure)
29868 for(MInt spaceId = 1; spaceId < nDim; spaceId++) {
29869 a_variable(cellId, CV->RHO_VV[spaceId]) = 0;
29870 }
29871 // set RHO_U to pulse initial condition
29872 a_variable(cellId, CV->RHO_VV[0]) =
29873 m_rhoVVInfinity[0] * (1.0 + std::exp(-pulse_center_length_unnormed * 20.0));
29874 }
29875 break;
29876 }
29877
29878 case 361: // spinning vortices
29879 {
29880 // Fixed values for initial time and density
29881 const MFloat t = 0.0;
29882 const MFloat rho = 1.0;
29883
29884 // Get circulation (gamma) and core radius (rC) parameters from properties
29896 const MFloat gamma = Context::getSolverProperty<MFloat>("circulation", m_solverId, AT_);
29897
29909 const MFloat rC = Context::getSolverProperty<MFloat>("coreRadius", m_solverId, AT_);
29910
29911 // Vatistas vortex core model (nC = 1 corresponds to Scully model)
29912 MInt nC = 1;
29913 nC = Context::getSolverProperty<MInt>("coreModelExponent", m_solverId, AT_, &nC);
29914
29915 // Calculate rotation frequency and offsets
29916 const MFloat omega = gamma / 4. / PI;
29917 const MFloat bx = cos(omega * t);
29918 const MFloat by = sin(omega * t);
29919
29920 // Set initial condition for all cells
29921 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29922 // Calculate vortex-local coordinates
29923 const MFloat x = a_coordinate(cellId, 0);
29924 const MFloat y = a_coordinate(cellId, 1);
29925 const MFloat rPos = sqrt(POW2(x - bx) + POW2(y - by));
29926 const MFloat thetaPos = atan2(y - by, x - bx);
29927 const MFloat rNeg = sqrt(POW2(x + bx) + POW2(y + by));
29928 const MFloat thetaNeg = atan2(y + by, x + bx);
29929
29930 // Determine velocity from potential flow theory (x-direction)
29931 MFloat ux = 0.;
29932 if(nC == 1) {
29933 ux += rPos / (rC * rC + rPos * rPos) * sin(thetaPos);
29934 ux += rNeg / (rC * rC + rNeg * rNeg) * sin(thetaNeg);
29935 } else {
29936 ux += rPos / pow(pow(rC, 2 * nC) + pow(rPos, 2 * nC), 1.0 / nC) * sin(thetaPos);
29937 ux += rNeg / pow(pow(rC, 2 * nC) + pow(rNeg, 2 * nC), 1.0 / nC) * sin(thetaNeg);
29938 }
29939 ux *= -gamma / 2. / PI;
29940
29941 // Determine velocity from potential flow theory (y-direction)
29942 MFloat uy = 0.;
29943 if(nC == 1) {
29944 uy += rPos / (rC * rC + rPos * rPos) * cos(thetaPos);
29945 uy += rNeg / (rC * rC + rNeg * rNeg) * cos(thetaNeg);
29946 } else {
29947 uy += rPos / pow(pow(rC, 2 * nC) + pow(rPos, 2 * nC), 1.0 / nC) * cos(thetaPos);
29948 uy += rNeg / pow(pow(rC, 2 * nC) + pow(rNeg, 2 * nC), 1.0 / nC) * cos(thetaNeg);
29949 }
29950 uy *= gamma / 2. / PI;
29951
29952 // Determine pressure using steady-state Bernoulli equation
29953 const MFloat p = 1. / m_gamma - 0.5 * rho * (ux * ux + uy * uy);
29954
29955 // Set conservative variables
29956 a_variable(cellId, CV->RHO) = rho;
29957 a_variable(cellId, CV->RHO_VV[0]) = rho * ux;
29958 a_variable(cellId, CV->RHO_VV[1]) = rho * uy;
29959 IF_CONSTEXPR(hasE<SysEqn>) {
29960 a_variable(cellId, CV->RHO_E) = sysEqn().internalEnergy(p, rho, (ux * ux + uy * uy));
29961 }
29962
29963 // Set primitive variables
29964 a_pvariable(cellId, PV->P) = p;
29965 a_pvariable(cellId, PV->RHO) = rho;
29966 a_pvariable(cellId, PV->U) = ux;
29967 a_pvariable(cellId, PV->V) = uy;
29968 }
29969 break;
29970 }
29971
29972 // vortex dipole - cylinder interaction (Lamb vortex)
29973 // thickened flame test cases
29974 // parallel inflow field with a burnt circle in the middle
29975 // hybrid capturing-tracking scheme
29976 // Bunsen flame
29977 // Bunsen flame (G-equation)
29978 // steady flame front in a duct
29979 // vortex-flame interactions (for G-equation/progress variable)
29980 // DL instability (for G-equation/progress variable) optimized version
29983 case 17516: {
29984 MFloat err = 0.01;
29985 MFloat activationTemperature = 30;
29986 MFloat alpha = F1 - F1 / mMax(1.1, m_burntUnburntTemperatureRatio);
29987 MFloat beta = alpha * activationTemperature / m_burntUnburntTemperatureRatio;
29988 MFloat filteredFlameThickness = 10.0 * m_subfilterVariance * c_cellLengthAtLevel(maxRefinementLevel());
29989 MFloat theta = F0, c = F0, x;
29990 IF_CONSTEXPR(!hasPV_C<SysEqn>::value) std::ignore = c;
29991 MFloat deltaX = m_flameRadiusOffset;
29992
29993 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
29994 // two flame initial field
29995 if(m_twoFlames) {
29996 err = 0.2;
29997 // first flame surface
29998 if((a_coordinate(cellId, 0) <= m_radiusFlameTube + m_xOffsetFlameTube + err)
29999 && (a_coordinate(cellId, 0) >= -m_radiusFlameTube + m_xOffsetFlameTube - err)) {
30000 x = sqrt(2.0 - 1.0) * (ABS(a_coordinate(cellId, 0) - m_xOffsetFlameTube) - m_radiusFlameTube)
30001 + a_coordinate(cellId, 1) - m_yOffsetFlameTube;
30002
30003 if((x < F0)) {
30004 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
30005 c = m_c0 * exp(x / filteredFlameThickness);
30006 // progress variabel in unburnt premixed gas
30007 } else {
30008 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
30009 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
30010 // progress variabel in burnt premixed gas
30011 }
30012 // second flame surface
30013 } else if((a_coordinate(cellId, 0) <= (m_radiusFlameTube2 + m_xOffsetFlameTube2 + err))
30014 && (a_coordinate(cellId, 0) >= (-m_radiusFlameTube2 + m_xOffsetFlameTube2 - err))) {
30015 x = sqrt(2.0 - 1.0) * (ABS(a_coordinate(cellId, 0) - m_xOffsetFlameTube2) - m_radiusFlameTube2)
30016 + a_coordinate(cellId, 1) - m_yOffsetFlameTube2;
30017
30018 if(x < F0) {
30019 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
30020 c = m_c0 * exp(x / filteredFlameThickness);
30021 } else {
30022 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
30023 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
30024 }
30025 // defining the initial function outside the domain between the tubes
30026 } else if(((a_coordinate(cellId, 0) > (m_radiusFlameTube + m_xOffsetFlameTube + err))
30027 || (a_coordinate(cellId, 0) < (-m_radiusFlameTube + m_xOffsetFlameTube - err)))
30028 && (a_coordinate(cellId, 0) >= 0.0)) {
30029 x = a_coordinate(cellId, 1) + 0.5;
30030 if(x < F0) {
30031 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
30032 c = m_c0 * exp(x / filteredFlameThickness);
30033 } else {
30034 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
30035 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
30036 }
30037 // defining the initial function outside the domain between the tubes
30038 } else if(((a_coordinate(cellId, 0) > (m_radiusFlameTube2 + m_xOffsetFlameTube2 + err))
30039 || (a_coordinate(cellId, 0) < (-m_radiusFlameTube2 + m_xOffsetFlameTube2 - err)))
30040 && (a_coordinate(cellId, 0) < 0.0)) {
30041 x = a_coordinate(cellId, 1) + 0.5;
30042 if((x < F0)) {
30043 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
30044 c = m_c0 * exp(x / filteredFlameThickness);
30045 } else {
30046 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
30047 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
30048 }
30049 }
30050
30051 // one flame initial field with plenum
30052 } else if(m_plenum) {
30053 // determine the reduced temperature and the progress variable
30054 if((a_coordinate(cellId, 0) <= m_radiusFlameTube + m_xOffsetFlameTube + err)
30055 && (a_coordinate(cellId, 0) >= -m_radiusFlameTube + m_xOffsetFlameTube - err)) {
30056 x = sqrt(2.0 - 1.0) * (ABS(a_coordinate(cellId, 0) - m_xOffsetFlameTube) - m_radiusFlameTube)
30057 + a_coordinate(cellId, 1) - m_yOffsetFlameTube;
30058
30059 if((x < F0)) {
30060 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
30061 c = m_c0 * exp(x / filteredFlameThickness);
30062 // progress variabel in unburnt premixed gas
30063 } else {
30064 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
30065 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
30066 // progress variabel in burnt premixed gas
30067 }
30068
30069
30070 // defining the initial function outside the domain
30071 } else if((a_coordinate(cellId, 0) > m_radiusFlameTube + err)
30072 || (a_coordinate(cellId, 0) < -(m_radiusFlameTube + err))) {
30073 x = a_coordinate(cellId, 1) + 0.5;
30074 if((x < F0)) {
30075 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
30076 c = m_c0 * exp(x / filteredFlameThickness);
30077 } else {
30078 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
30079 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
30080 }
30081 }
30082 // one flame initial field without plenum
30083 } else {
30084 x = sqrt(2.0 - 1.0) * (ABS(a_coordinate(cellId, 0) - m_xOffsetFlameTube) - (m_radiusFlameTube + deltaX))
30085 + a_coordinate(cellId, 1) - m_yOffsetFlameTube;
30086
30087 if(x < F0) {
30088 theta = (F1 - F1 / beta) * exp(x / filteredFlameThickness);
30089 c = m_c0 * exp(x / filteredFlameThickness);
30090 // progress variabel in unburnt premixed gas
30091 } else {
30092 theta = F1 - F1 / beta * exp((F1 - beta) * x / filteredFlameThickness);
30093 c = F1 - (F1 - m_c0) * exp(-x * m_c0 / ((F1 - m_c0) * filteredFlameThickness));
30094 // progress variabel in burnt premixed gas
30095 }
30096 }
30097
30098
30099 // compute the density
30100 a_variable(cellId, CV->RHO) =
30101 m_rhoFlameTube + (m_rhoFlameTube / m_burntUnburntTemperatureRatio - m_rhoFlameTube) * theta;
30102 // compute the specific momentum
30103 a_variable(cellId, CV->RHO_U) = F0;
30104 a_variable(cellId, CV->RHO_V) =
30105 a_variable(cellId, CV->RHO) * m_velocityFlameTube; // a_variable( cellId , CV->RHO ) * ( v0 );
30106 IF_CONSTEXPR(hasE<SysEqn>)
30107 a_variable(cellId, CV->RHO_E) =
30108 m_pressureFlameTube / gammaMinusOne + F1B2 * POW2(m_velocityFlameTube) * a_variable(cellId, CV->RHO);
30109 // progress variable
30110 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
30111 a_variable(cellId, CV->RHO_C) = a_variable(cellId, CV->RHO) * c;
30112
30113 if(m_twoFlames) {
30114 a_variable(cellId, CV->RHO_V) =
30115 a_variable(cellId, CV->RHO) * m_velocityFlameTube; // a_variable( cellId , CV->RHO ) * ( v0 );
30116 IF_CONSTEXPR(hasE<SysEqn>)
30117 a_variable(cellId, CV->RHO_E) =
30118 m_pressureFlameTube / gammaMinusOne + F1B2 * POW2(m_velocityFlameTube) * a_variable(cellId, CV->RHO);
30119 }
30120 }
30121
30122 break;
30123 }
30124
30126 // symmetric flame (tested for tube radius chosen to 0.5), forced response (for
30127 // G-equation/progress variable)
30128
30129 default: {
30130 stringstream errorMessage;
30131 errorMessage << "WARNING: Initial condition " << m_initialCondition << ", does not exist" << endl;
30132 if(domainId() == 0) {
30133 cerr << errorMessage.str() << endl;
30134 }
30135 m_log << errorMessage.str() << endl;
30136 // mTerm(1, AT_, errorMessage.str());
30137 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30138 // parallel inflow field
30139 a_variable(cellId, CV->RHO) = m_rhoInfinity;
30140 for(MInt spaceId = 0; spaceId < nDim; spaceId++) {
30141 a_variable(cellId, CV->RHO_VV[spaceId]) = m_rhoVVInfinity[spaceId];
30142 }
30143 IF_CONSTEXPR(hasE<SysEqn>)
30144 a_variable(cellId, CV->RHO_E) = m_rhoEInfinity;
30145 }
30146 break;
30147 }
30148 } // switch(m_initialCondition)
30149 } else {
30150 // initialize all ghost cells
30151 for(MInt bndryId = 0; bndryId < m_fvBndryCnd->m_bndryCells->size(); bndryId++) {
30152 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
30153 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; srfc++) {
30154 MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
30155 for(MInt varId = 0; varId < noCVars; varId++) {
30156 a_variable(ghostCellId, varId) = a_variable(cellId, varId);
30157 }
30158 }
30159 }
30160 }
30161
30162 if(!m_combustion) {
30163 MFloat L = F1;
30176 L = Context::getSolverProperty<MFloat>("pressureDropLength", m_solverId, AT_, &L);
30177 m_deltaPL = m_deltaP * L;
30178 m_fvBndryCnd->m_deltaP = m_deltaP;
30179 m_fvBndryCnd->m_deltaPL = m_deltaPL;
30180 }
30181
30182 // Initialize all old cell variables with the conservative variables
30183 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30184 for(MInt varId = 0; varId < noCVars; varId++) {
30185 a_oldVariable(cellId, varId) = a_variable(cellId, varId);
30186 }
30187 }
30188
30189 // For dual time stepping, initialize additional variables as well
30190 if(m_dualTimeStepping) {
30191 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
30192 for(MInt varId = 0; varId < noCVars; varId++) {
30193 a_dt1Variable(cellId, varId) = a_variable(cellId, varId);
30194 a_dt2Variable(cellId, varId) = a_variable(cellId, varId);
30195 }
30196 }
30197 }
30198
30199 m_log << "**************************" << endl;
30200 m_log << "Initial Condition summary" << endl;
30201 m_log << "**************************" << endl;
30202 m_log << "Re = " << m_Re << endl;
30203 m_log << "Re0 = " << sysEqn().m_Re0 << endl;
30204 m_log << "Ma = " << m_Ma << endl;
30205 m_log << "TInfinity = " << m_TInfinity << endl;
30206 m_log << "UInfinity = " << m_UInfinity << endl;
30207 m_log << "VInfinity = " << m_VInfinity << endl;
30208 IF_CONSTEXPR(nDim == 3) { m_log << "WInfinity = " << m_WInfinity << endl; }
30209 m_log << "PInfinity = " << m_PInfinity << endl;
30210 m_log << "rhoInfinity = " << m_rhoInfinity << endl;
30211 m_log << "rhoEInfinity = " << m_rhoEInfinity << endl;
30212 m_log << "muInfinity = " << sysEqn().m_muInfinity << endl;
30213 m_log << "DInfinity = " << m_DInfinity << endl;
30214 m_log << "DthInfinity = " << m_DthInfinity << endl;
30215 m_log << "timeRef = " << m_timeRef << endl;
30216
30217 checkInfinityVarsConsistency();
30218
30219 // check initial condition
30220 if(!m_restart && !m_resetInitialCondition) {
30221 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
30222 for(MInt v = 0; v < CV->noVariables; v++) {
30223 if(std::isnan(a_variable(cellId, v))) {
30224 cerr << "Variable " << v << " cellId : " << cellId << endl;
30225 mTerm(1, AT_, "Invalid initialcondition formulation!");
30226 }
30227 }
30228 }
30229 }
30230}
30231
30232
30234template <MInt nDim_, class SysEqn>
30236 TRACE();
30237
30238 std::vector<MFloat> infVars{};
30239 std::vector<MString> infVarNames{};
30240
30241 infVars.push_back(m_UInfinity);
30242 infVarNames.push_back("m_UInfinity");
30243 infVars.push_back(m_VInfinity);
30244 infVarNames.push_back("m_VInfinity");
30245 IF_CONSTEXPR(nDim == 3) {
30246 infVars.push_back(m_WInfinity);
30247 infVarNames.push_back("m_WInfinity");
30248 }
30249 infVars.push_back(m_PInfinity);
30250 infVarNames.push_back("m_PInfinity");
30251 infVars.push_back(m_TInfinity);
30252 infVarNames.push_back("m_TInfinity");
30253 infVars.push_back(m_DthInfinity);
30254 infVarNames.push_back("m_DthInfinity");
30255 infVars.push_back(sysEqn().m_muInfinity);
30256 infVarNames.push_back("m_muInfinity");
30257 infVars.push_back(m_DInfinity);
30258 infVarNames.push_back("m_DInfinity");
30259 infVars.push_back(m_SInfinity);
30260 infVarNames.push_back("m_SInfinity");
30261 infVars.push_back(m_hInfinity);
30262 infVarNames.push_back("m_hInfinity");
30263
30264 infVars.push_back(m_VVInfinity[0]);
30265 infVarNames.push_back("m_VVInfinity[0]");
30266 infVars.push_back(m_VVInfinity[1]);
30267 infVarNames.push_back("m_VVInfinity[1]");
30268 IF_CONSTEXPR(nDim == 3) {
30269 infVars.push_back(m_VVInfinity[2]);
30270 infVarNames.push_back("m_VVInfinity[2]");
30271 }
30272
30273 infVars.push_back(m_rhoUInfinity);
30274 infVarNames.push_back("m_rhoUInfinity");
30275 infVars.push_back(m_rhoVInfinity);
30276 infVarNames.push_back("m_rhoVInfinity");
30277 IF_CONSTEXPR(nDim == 3) {
30278 infVars.push_back(m_rhoWInfinity);
30279 infVarNames.push_back("m_rhoWInfinity");
30280 }
30281 infVars.push_back(m_rhoEInfinity);
30282 infVarNames.push_back("m_rhoEInfinity");
30283 infVars.push_back(m_rhoInfinity);
30284 infVarNames.push_back("m_rhoInfinity");
30285
30286 infVars.push_back(m_rhoVVInfinity[0]);
30287 infVarNames.push_back("m_rhoVVInfinity[0]");
30288 infVars.push_back(m_rhoVVInfinity[1]);
30289 infVarNames.push_back("m_rhoVVInfinity[1]");
30290 IF_CONSTEXPR(nDim == 3) {
30291 infVars.push_back(m_rhoVVInfinity[2]);
30292 infVarNames.push_back("m_rhoVVInfinity[2]");
30293 }
30294
30295 infVars.push_back(m_Ma);
30296 infVarNames.push_back("m_Ma");
30297 infVars.push_back(sysEqn().m_Re0);
30298 infVarNames.push_back("m_Re0");
30299 infVars.push_back(m_rRe0);
30300 infVarNames.push_back("m_rRe0");
30301 infVars.push_back(m_timeRef);
30302 infVarNames.push_back("m_timeRef");
30303 infVars.push_back(m_deltaP);
30304 infVarNames.push_back("m_deltaP");
30305 infVars.push_back(m_strouhal);
30306 infVarNames.push_back("m_strouhal");
30307 infVars.push_back(m_timeStep);
30308 infVarNames.push_back("m_timeStep");
30309
30310 // TODO labels:FV,COMM add missing variables!
30311
30312 const MInt noInfVars = infVars.size();
30313 std::vector<MFloat> recvInfVars(noInfVars);
30314
30315 if(infVars.size() != infVarNames.size()) {
30316 mTerm(1, "number of infinity variables mismatch");
30317 }
30318
30319 if(domainId() == 0) {
30320 std::copy(infVars.begin(), infVars.end(), recvInfVars.begin());
30321 } else {
30322 std::fill(recvInfVars.begin(), recvInfVars.end(), -1.0);
30323 }
30324
30325 MPI_Bcast(&recvInfVars[0], noInfVars, maia::type_traits<MFloat>::mpiType(), 0, mpiComm(), AT_, "recvInfVars[0]");
30326
30327 for(MInt i = 0; i < noInfVars; i++) {
30328 // Catch NaNs, might be used to invalidate some variables and prevent/detect their usage
30329 if(std::isnan(recvInfVars[i]) && std::isnan(infVars[i])) {
30330 const MString msg =
30331 "Infinity variable '" + infVarNames[i] + "' is NaN on multiple ranks, check if this is correct!";
30332 m_log << msg << std::endl;
30333 if(domainId() == 0) {
30334 std::cerr << msg << std::endl;
30335 }
30336 continue;
30337 }
30338 if(!approx(recvInfVars[i], infVars[i], MFloatEps)) {
30339 mTerm(1, "Infinity variable '" + infVarNames[i]
30340 + "' is inconsistent among ranks, domainId=" + std::to_string(domainId())
30341 + ", value=" + std::to_string(infVars[i]) + ", recvValue=" + std::to_string(recvInfVars[i]));
30342 }
30343 }
30344}
30345
30346
30347// -------------------------------------------
30348
30359template <MInt nDim_, class SysEqn>
30361 TRACE();
30362
30363 IF_CONSTEXPR(nDim == 2)
30364 mTerm(1, "Info: untested in 2D. By now only used in 3D."
30365 " To use in 2D delete this warning.");
30366
30377 MFloat ReTau = Context::getSolverProperty<MFloat>("ReTau", m_solverId, AT_) / m_referenceLength;
30378
30382 m_deltaP = POW2(m_Ma * ReTau * sqrt(m_TInfinity) / m_Re) * m_rhoInfinity / m_referenceLength;
30383
30384 m_fvBndryCnd->m_deltaP = m_deltaP;
30385}
30386
30387// -----------------------------------------------------------------
30393template <MInt nDim_, class SysEqn>
30394void FvCartesianSolverXD<nDim_, SysEqn>::updateJet() {
30395 TRACE();
30396
30397 if(m_jet && !m_levelSet) {
30398 switch(m_jetType) {
30399 //---Single Jet------
30400 //-------------------
30401 case 19516: {
30402 IF_CONSTEXPR(nDim == 2) mTerm(-1, "This case is designed for 3D!");
30403
30404 const MInt noCells = a_noCells();
30405 MInt cellId; // nghbrId;
30406 // ------------------Single Jet Forcing-------------------------
30407 //--------------------------------------------------------------
30408 for(cellId = 0; cellId < noCells; cellId++) {
30409 MFloat jet, uy1 = 0, uy11 = 0, ur0 = 0, ur = 0, u = 0, w = 0, radius, angle, swtrad, swtxsgn, swtzsgn;
30410 MFloat dx, dy, dz, angle2;
30411
30412 dx = a_coordinate(cellId, 0);
30413 dy = a_coordinate(cellId, 1);
30414 dz = a_coordinate(cellId, 2);
30415 radius = sqrt(POW2(dy) + POW2(dz));
30416 if(fabs(radius) > 1.5 * m_jetHeight) continue;
30417
30418 swtrad = 0.5 * F1 * (radius - 0.01 + abs(radius - 0.01)) / (abs(radius - 0.01) + 1e-32);
30419 swtxsgn = 0.5 * F1 * (dy + abs(dy)) / (abs(dy) + 1e-32);
30420 swtzsgn = 0.5 * F1 * (dz + abs(dz)) / (abs(dz) + 1e-32);
30421 angle = abs(dy) / (radius + 1e-32) * swtrad;
30422 angle = acos(angle);
30423 angle = angle * swtxsgn * swtzsgn + (PI - angle) * (1 - swtxsgn) * swtzsgn
30424 + (PI + angle) * (1 - swtxsgn) * (1 - swtzsgn) - angle * swtxsgn * (1 - swtzsgn);
30425
30426 // Mean inflow velocity profile
30427 jet = m_Ma * F1B2
30428 * (1
30429 - tanh(m_shearLayerThickness * (((dx) - (m_jetHeight)) / (m_jetHeight))
30430 * (((dx) + (m_jetHeight)) / (m_jetHeight))))
30431 * swtrad;
30432 radius = radius + 0.0000000000000001;
30433 // Vortex ring velocities
30434 uy1 = 2 * 0.5 / radius * (radius - 0.5) / 0.01
30435 * exp(-log(2) * (POW2(dx - 0.49) + POW2(radius - 0.5)) / POW2(0.01)) * jet;
30436 ur0 = -2 * 0.5 / radius * (dx - 0.49) / 0.01
30437 * exp(-log(2) * (POW2(dx - 0.49) + POW2(radius - 0.5)) / POW2(0.01)) * jet;
30438
30439 // Angle 2 and definition of modes
30440 angle2 = atan2(dz, dy);
30441 MFloat az = 0;
30442 // Choose noOfModes=16 for Bogey&Bailly reference.
30443 // Choose forceCoefficient 0.007 for Bogey&Bailly reference.
30444
30445 for(MInt i = 0; i < m_modeNumbers; i++) {
30446 // a[i]= -1.0 + rand()/(RAND_MAX/(1.0- (-1.0)));
30447 // phi[i]= 2*PI*rand()/(RAND_MAX/(1.0- (-1.0)));
30448 // Fluctuated part of the vortex rind
30449 const MFloat a = -1.0 + (float)rand() / ((float)RAND_MAX / (1.0 - (-1.0)));
30450 const MFloat phi = 0.00 + (float)rand() / ((float)RAND_MAX / (2 * acos(-1) - 0.00));
30451
30452 az += a * cos(phi + i * angle2);
30453 }
30454 uy11 = (m_forceCoefficient * az * uy1);
30455 ur = (m_forceCoefficient * az * ur0);
30456 u = ur * cos(angle2);
30457 w = ur * sin(angle2);
30458 a_rightHandSide(cellId, CV->RHO_U) += (a_cellVolume(cellId) * m_rhoInfinity * uy11);
30459 a_rightHandSide(cellId, CV->RHO_V) += (a_cellVolume(cellId) * m_rhoInfinity * u);
30460 a_rightHandSide(cellId, CV->RHO_W) += (a_cellVolume(cellId) * m_rhoInfinity * w);
30461 // cout<<angle<< endl;
30462 }
30463 break;
30464 }
30465 //---Single Jet (updated version; TODO labels:FV,toremove remove/replace 19516)------
30466 case 19517:
30467 case 19518: {
30468 if(!m_jetForcing) {
30469 break;
30470 }
30471 // ------------------Single Jet Forcing-------------------------
30472 // Bogey&Bailly reference:
30473 // noOfModes=16; forceCoefficient=0.007
30474
30475 // Random number generation
30476 std::vector<MFloat> randAng{};
30477 randAng.resize(m_modeNumbers);
30478 std::vector<MFloat> randAmp{};
30479 randAmp.resize(m_modeNumbers);
30480
30481 // Initial seed for deterministic same random number generation on all ranks
30482 const MInt seed = m_jetRandomSeed + globalTimeStep * m_noRKSteps + m_RKStep;
30483 if(Context::propertyExists("RNGSeed") || Context::propertyExists("seedRNGWithTime"))
30484 mTerm(1, "Properties RNGSeed or seedRNGWithTime not compatible with jetForcing");
30485 srand(seed); // use initial seed
30486 for(MInt i = 0; i < 10; i++) {
30487 srand(rand()); // re-seed with first random number of previous seed to obtain a seed for the random engine
30488 // below which is not a linear function of the globalTimeStep anymore
30489 }
30490 const MInt randSeed = rand();
30491 // m_log << "DEBUG seed " << seed << " " << randSeed << std::endl;
30492
30493 // Update random engine each timestep
30494 std::default_random_engine gen(randSeed);
30495 std::uniform_real_distribution<MFloat> ampDist(-1., 1.);
30496 std::uniform_real_distribution<MFloat> angDist(0., 2 * PI);
30497
30498 // Accumulate random amplitudes and angles
30499 for(MInt i = 0; i < m_modeNumbers; i++) {
30500 randAmp[i] = ampDist(gen);
30501 randAng[i] = angDist(gen);
30502 }
30503
30504 const MFloat r0 = m_jetHeight;
30505 const MFloat x0 = m_jetForcingPosition;
30506 const MFloat deltaY = c_cellLengthAtLevel(maxLevel());
30507 const MInt noCells = a_noCells();
30508
30509 for(MInt cellId = 0; cellId < noCells; cellId++) {
30510 const MFloat dx = a_coordinate(cellId, 0);
30511 const MFloat dy = a_coordinate(cellId, 1);
30512 const MFloat dz = a_coordinate(cellId, 2);
30513 const MFloat radius = sqrt(POW2(dy) + POW2(dz));
30514
30515 // Mean inflow velocity
30516 const MFloat u0 = m_UInfinity;
30517
30518 // for tanh inflow profile velocity is basically zero out of this range
30519 if(fabs(radius) / r0 <= 1.5) {
30520 MFloat prefac = 2.0 * r0 / (radius * deltaY);
30521 prefac *= exp(-log(2.0) * (POW2(dx - x0) + POW2(radius - r0)) / POW2(deltaY)) * u0;
30522 const MFloat u_ring = prefac * (radius - r0);
30523 const MFloat v_ring = -1.0 * prefac * (dx - x0);
30524 const MFloat angle = atan2(dz, dy);
30525
30526 MFloat randFluct = 0.0;
30527 for(MInt i = 0; i < m_modeNumbers; i++) {
30528 randFluct += randAmp[i] * cos(randAng[i] + i * angle);
30529 }
30530 const MFloat u_ax = (m_forceCoefficient * randFluct * u_ring);
30531 const MFloat u_rad = (m_forceCoefficient * randFluct * v_ring);
30532 const MFloat v = u_rad * cos(angle);
30533 const MFloat w = u_rad * sin(angle);
30534
30535 if(m_jetType == 19517) {
30536 a_rightHandSide(cellId, CV->RHO_U) += (a_cellVolume(cellId) * m_rhoInfinity * u_ax);
30537 a_rightHandSide(cellId, CV->RHO_V) += (a_cellVolume(cellId) * m_rhoInfinity * v);
30538 a_rightHandSide(cellId, CV->RHO_W) += (a_cellVolume(cellId) * m_rhoInfinity * w);
30539 } else {
30540 const MFloat rho = a_variable(cellId, CV->RHO);
30541 // Apply perturbation directly to velocities (see Bogey); jet type 19517 is not useful if the correct
30542 // velocity profile from the paper is used; previously the jet profile was cut of a m_jetHeight which lead
30543 // to a steep velocity gradient in the shear layer in the simulations, thus the negligible influence of
30544 // the jet forcing was not relevant/detected
30545 a_variable(cellId, CV->RHO_U) += (rho * u_ax);
30546 a_variable(cellId, CV->RHO_V) += (rho * v);
30547 a_variable(cellId, CV->RHO_W) += (rho * w);
30548 }
30549 }
30550 }
30551 break;
30552 }
30553 case 1156: {
30554 //---Coaxial Jet------
30555 //-------------------
30556 IF_CONSTEXPR(nDim == 2) mTerm(-1, "This case is designed for 3D!");
30557
30558 const MInt noCells = a_noCells();
30559 MInt cellId; // nghbrId;
30560
30561 // ------------------Coaxial Jet Forcing-------------------------
30562 //--------------------------------------------------------------
30563 for(cellId = 0; cellId < noCells; cellId++) {
30564 MFloat jet, uy1 = 0, uy11 = 0, ur0 = 0, ur = 0, u = 0, w = 0, radius, radius2, angle, swtrad, swtxsgn,
30565 swtzsgn;
30566 MFloat dx, dy, dz, angle2;
30567
30568 dx = a_coordinate(cellId, 0);
30569 dy = a_coordinate(cellId, 1);
30570 dz = a_coordinate(cellId, 2);
30571 radius = sqrt(POW2(dy) + POW2(dz));
30572 swtrad = 0.5 * F1 * (radius - 0.01 + abs(radius - 0.01)) / (abs(radius - 0.01) + 1e-32);
30573 swtxsgn = 0.5 * F1 * (dy + abs(dy)) / (abs(dy) + 1e-32);
30574 swtzsgn = 0.5 * F1 * (dz + abs(dz)) / (abs(dz) + 1e-32);
30575 angle = abs(dy) / (radius + 1e-32) * swtrad;
30576 angle = acos(angle);
30577 angle = angle * swtxsgn * swtzsgn + (PI - angle) * (1 - swtxsgn) * swtzsgn
30578 + (PI + angle) * (1 - swtxsgn) * (1 - swtzsgn) - angle * swtxsgn * (1 - swtzsgn);
30579
30580 //-- Primary JET --
30581 if(radius <= m_primaryJetRadius) {
30582 jet = m_Ma * F1B2
30583 * (1
30584 - tanh(m_shearLayerThickness * (((dx) - (m_jetHeight)) / (m_jetHeight))
30585 * (((dx) + (m_jetHeight)) / (m_jetHeight))))
30586 * swtrad;
30587 radius = radius + 0.0000000000000001;
30588 // Vortex ring velocities
30589 uy1 = 2 * m_primaryJetRadius / radius * (radius - m_primaryJetRadius) / 0.01
30590 * exp(-log(2) * (POW2(dx - 0.49) + POW2(radius - m_primaryJetRadius)) / POW2(0.01)) * jet;
30591 ur0 = -2 * m_primaryJetRadius / radius * (dx - 0.49) / 0.01
30592 * exp(-log(2) * (POW2(dx - 0.49) + POW2(radius - m_primaryJetRadius)) / POW2(0.01)) * jet;
30593
30594 // Angle 2 and definition of modes
30595 angle2 = atan2(dz, dy);
30596 MFloat az = 0;
30597 MFloat* a = new MFloat[m_modeNumbers];
30598 MFloat* phi = new MFloat[m_modeNumbers];
30599 for(MInt i = 0; i < m_modeNumbers; i++) {
30600 a[i] = -1.0 + (float)rand() / ((float)RAND_MAX / (1.0 - (-1.0)));
30601 phi[i] = 0.00 + (float)rand() / ((float)RAND_MAX / (2 * acos(-1) - 0.00));
30602
30603 az += a[i] * cos(phi[i] + i * angle2);
30604 }
30605 uy11 = (m_forceCoefficient * az * uy1);
30606 ur = (m_forceCoefficient * az * ur0);
30607 u = ur * cos(angle2);
30608 w = ur * sin(angle2);
30609 }
30610 //-- Secondary JET --
30611 else if(radius <= m_secondaryJetRadius) {
30612 radius2 = radius - m_primaryJetRadius;
30613 jet = m_Ma * F1B2
30614 * (1
30615 - tanh(m_shearLayerThickness * (((dx) - (m_jetHeight)) / (m_jetHeight))
30616 * (((dx) + (m_jetHeight)) / (m_jetHeight))))
30617 * swtrad;
30618 radius2 = radius2 + 0.0000000000000001;
30619
30620 uy1 = 2 * m_secondaryJetRadius / radius * (radius - m_secondaryJetRadius) / 0.01
30621 * exp(-log(2) * (POW2(dx - 0.49) + POW2(radius - m_secondaryJetRadius)) / POW2(0.01)) * jet;
30622 ur0 = -2 * m_secondaryJetRadius / radius * (dx - 0.49) / 0.01
30623 * exp(-log(2) * (POW2(dx - 0.49) + POW2(radius - m_secondaryJetRadius)) / POW2(0.01)) * jet;
30624
30625 // Angle 2 and definition of modes
30626 angle2 = atan2(dz, dy);
30627 MFloat az = 0;
30628 MFloat a[16];
30629 MFloat phi[16];
30630 for(MInt i = 0; i < 16; i++) {
30631 a[i] = -1.0 + (float)rand() / ((float)RAND_MAX / (1.0 - (-1.0)));
30632 phi[i] = 0.00 + (float)rand() / ((float)RAND_MAX / (2 * acos(-1) - 0.00));
30633 // To get better acoustic results first 4 modes are ommited for the secondary jet!!
30634 a[0] = 0;
30635 a[1] = 0;
30636 a[2] = 0;
30637 a[3] = 0;
30638 phi[0] = 0;
30639 phi[1] = 0;
30640 phi[2] = 0;
30641 phi[3] = 0;
30642 az += a[i] * cos(phi[i] + (i)*angle2);
30643 }
30644 uy11 = (m_forceCoefficient * az * uy1);
30645 ur = (m_forceCoefficient * az * ur0);
30646 u = ur * cos(angle2);
30647 w = ur * sin(angle2);
30648 }
30649 a_rightHandSide(cellId, CV->RHO_U) += (a_cellVolume(cellId) * m_rhoInfinity * uy11);
30650 a_rightHandSide(cellId, CV->RHO_V) += (a_cellVolume(cellId) * m_rhoInfinity * u);
30651 a_rightHandSide(cellId, CV->RHO_W) += (a_cellVolume(cellId) * m_rhoInfinity * w);
30652 }
30653 break;
30654 }
30655 // Dummy jetType, s.th. jet-BC can be used also with inletTurbulence and without the updateJet()-forcing
30656 case -1:
30657 break;
30658
30659 default: {
30660 stringstream errorMessage;
30661 errorMessage << "FvCartesianSolverXD::updateJet() switch variable 'm_jetType' with value " << m_jetType
30662 << " not matching any case." << endl;
30663 mTerm(1, AT_, errorMessage.str());
30664 }
30665 }
30666 }
30667}
30668
30669
30670// -------------------------------------------------------------------------
30671
30672
30673/*
30674 * \brief Creates a surface
30675 *
30676 * @author Daniel Hartmann, January 12, 2006
30677 *
30678 */
30679template <MInt nDim_, class SysEqn>
30680void FvCartesianSolverXD<nDim_, SysEqn>::computeSrfcs(MInt cellId, MInt nghbrId, MInt dirId, MInt srfcId) {
30681 // TRACE();
30682
30696 MBool bndryRfnJump = false;
30697 bndryRfnJump = Context::getSolverProperty<MBool>("bndryRfnJump", m_solverId, AT_, &bndryRfnJump);
30698
30699 //---
30700
30701 // store grid cell coordinates
30702 MFloat* coordinates = new MFloat[nDim];
30703 for(MInt dimId = 0; dimId < nDim; dimId++) {
30704 coordinates[dimId] = a_coordinate(cellId, dimId);
30705 if(a_bndryId(cellId) > -1) {
30706 MInt bndryId = a_bndryId(cellId);
30707 // correct coordinates of boundary cells
30708 coordinates[dimId] -= m_fvBndryCnd->m_bndryCells->a[bndryId].m_coordinates[dimId];
30709 }
30710 }
30711 // correct coordinates of internal cells which are masters of a small cell
30712 for(MInt smallId = 0; smallId < m_fvBndryCnd->m_smallBndryCells->size(); smallId++) {
30713 const MInt smallCell = m_fvBndryCnd->m_smallBndryCells->a[smallId];
30714 if(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId != -1) {
30715 if(a_bndryId(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId) == -1
30716 && m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId == cellId) {
30717 for(MInt dimId = 0; dimId < nDim; dimId++) {
30718 coordinates[dimId] = m_fvBndryCnd->m_bndryCells->a[smallCell].m_masterCoordinates[dimId];
30719 }
30720 break;
30721 }
30722 }
30723 }
30724
30725 // create the surface
30726 m_surfaces.append();
30727
30728 const MInt spaceId = dirId / 2;
30729 const MInt sideId = dirId % 2;
30730 const MInt otherSideId = (sideId + 1) % 2;
30731
30732 // store orientation
30733 a_surfaceOrientation(srfcId) = spaceId;
30734
30735 a_surfaceNghbrCellId(srfcId, sideId) = nghbrId;
30736 a_surfaceNghbrCellId(srfcId, otherSideId) = cellId;
30737
30738 // compute the surface coordinates and the surface area
30739 a_surfaceArea(srfcId) = F1;
30740
30741 MFloat cellHalfLength[nDim];
30742 for(MInt dimId = 0; dimId < nDim; dimId++) {
30743 cellHalfLength[dimId] = c_cellLengthAtLevel(a_level(cellId) + 1);
30744 }
30745
30746 a_surfaceCoordinate(srfcId, spaceId) = coordinates[spaceId] + F2 * ((MFloat)sideId - F1B2) * cellHalfLength[spaceId];
30747
30748 for(MInt dimId = 0; dimId < nDim; dimId++) {
30749 if(dimId != spaceId) {
30750 // surface area
30751 a_surfaceArea(srfcId) *= F2 * cellHalfLength[dimId];
30752 // coordinates
30753 a_surfaceCoordinate(srfcId, dimId) = coordinates[dimId];
30754 // bndry refinement jump method (new name: wall mesh variation method. See Paper Schilden2020)
30755 if(bndryRfnJump) {
30756 if(m_bndryRfnJumpInformation_[cellId] != -1 && nghbrId == m_bndryRfnJumpInformation_[cellId]) {
30757 a_surfaceArea(srfcId) = F0;
30758 }
30759 }
30760 }
30761 }
30762
30763 delete[] coordinates;
30764 coordinates = 0;
30765}
30766
30767
30768//-------------------------------------------------------------------------------------------------------
30769
30770
30781template <MInt nDim_, class SysEqn>
30783 TRACE();
30784
30785 const MInt noCells = a_noCells();
30786 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
30787 MBoolScratchSpace surfaceDenied(noBndryCells, m_noDirs, AT_, "surfaceDenied");
30788 MBoolScratchSpace surfaceCreated(noBndryCells, m_noDirs, AT_, "surfaceCreated");
30789 for(MInt i = 0; i < noBndryCells; i++) {
30790 for(MInt j = 0; j < m_noDirs; j++) {
30791 surfaceDenied(i, j) = false;
30792 surfaceCreated(i, j) = false;
30793 }
30794 }
30795
30796 MInt otherDir[2 * nDim];
30797 for(MInt dim = 0; dim < nDim; dim++) {
30798 otherDir[2 * dim] = 2 * dim + 1;
30799 otherDir[2 * dim + 1] = 2 * dim;
30800 }
30801
30802 m_surfaces.size(m_bndryCellSurfacesOffset);
30803
30804 // store the surfaces of all boundary cells
30805 // here equal level neighbors are assumed!!!
30806 MInt counter = 0;
30807 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
30808 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
30809
30810 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
30811 continue;
30812 }
30813 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
30814 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_externalFaces[dirId]) {
30815 surfaceDenied(bndryId, dirId) = true;
30816 }
30817 MInt nghbrId;
30818 if(m_identNghbrIds[cellId * m_noDirs + dirId] < m_identNghbrIds[cellId * m_noDirs + dirId + 1]) {
30819 nghbrId = m_storeNghbrIds[m_identNghbrIds[cellId * m_noDirs + dirId]];
30820 if(a_level(cellId) < a_level(nghbrId)) {
30821 continue;
30822 }
30823 } else {
30824 continue;
30825 }
30826
30827 if(a_bndryId(nghbrId) < 0) {
30828 continue;
30829 }
30830
30831 MBool createSrfc = true;
30832
30833 MInt oldSrfcId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_associatedSrfc[dirId];
30834 if(oldSrfcId >= 0) {
30835 ASSERT(a_surfaceNghbrCellId(oldSrfcId, 0) > -1 && a_surfaceNghbrCellId(oldSrfcId, 1) > -1, "");
30836 // check conditions for surface generation
30837 // (1) no master-slave interface
30838 // (2) no slave-slave interface if both slave cells have the same master
30839 // (3) no periodic-periodic interface
30840 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > -1) {
30841 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == nghbrId
30842 || m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId
30843 == m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId) {
30844 createSrfc = false;
30845 surfaceDenied(bndryId, dirId) = true;
30846 }
30847 }
30848 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId > -1) {
30849 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == (MInt)cellId
30850 || m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId
30851 == m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId) {
30852 createSrfc = false;
30853 surfaceDenied(bndryId, dirId) = true;
30854 }
30855 }
30856 if(a_isPeriodic(cellId) && a_isPeriodic(nghbrId)) {
30857 createSrfc = false;
30858 surfaceDenied(bndryId, dirId) = true;
30859 }
30860
30861 // do not create a surface between two halo cells
30862 // create a surface if slave-neighbor are both halo cells but the master is not
30863 if(a_isHalo(cellId) && a_isHalo(nghbrId)) {
30864 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == -1
30865 && m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == -1) {
30866 createSrfc = false;
30867 surfaceDenied(bndryId, dirId) = true;
30868 }
30869 }
30870
30871 // this is valid for isotropical refinement only!!
30872 if(!createSrfc) {
30873 continue;
30874 }
30875
30876 if((a_level(cellId) > a_level(nghbrId)) || ((a_level(cellId) == a_level(nghbrId)) && dirId % 2 == 0)) {
30877 surfaceCreated(bndryId, dirId) = true;
30878
30879 if(oldSrfcId != counter) {
30880 m_surfaces.copy(oldSrfcId, counter);
30881 m_surfaces.erase(oldSrfcId);
30882 m_fvBndryCnd->m_bndryCells->a[bndryId].m_associatedSrfc[dirId] = counter;
30883 if(a_level(cellId) == a_level(nghbrId)) {
30884 m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_associatedSrfc[otherDir[dirId]] = counter;
30885 }
30886 }
30887 counter++;
30888 }
30889 }
30890 }
30891 }
30892
30893 // delete all other surfaces created in createCutFace
30894 while(a_noSurfaces() > counter) {
30895 MInt size = a_noSurfaces();
30896 m_surfaces.erase(size - 1);
30897 m_surfaces.size(size - 1);
30898 }
30899
30900 // set the offset of all boundary interfaces (important for mesh adaptation!)
30901 m_bndryCellSurfacesOffset = a_noSurfaces();
30902
30903 // set srfcId
30904 MInt srfcId = a_noSurfaces();
30905 MLong sumSrfc = srfcId;
30906 MPI_Allreduce(MPI_IN_PLACE, &sumSrfc, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "sumSrfc");
30907 m_log << "DEBUG: " << sumSrfc << " number of surfaces after first loop" << endl;
30908
30909 MLong nmbr1 = 0;
30910 MLong nmbr2 = 0;
30911
30912 for(MInt cellId = 0; cellId < noCells; cellId++) {
30913 if(a_isBndryGhostCell(cellId)) {
30914 nmbr1++;
30915 continue;
30916 }
30917 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
30918 nmbr2++;
30919 continue;
30920 }
30921
30922 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
30923 for(MInt nghbr = m_identNghbrIds[cellId * m_noDirs + dirId];
30924 nghbr < m_identNghbrIds[cellId * m_noDirs + dirId + 1];
30925 nghbr++) {
30926 MBool createSrfc = false;
30927 const MInt nghbrId = m_storeNghbrIds[nghbr];
30928 ASSERT(nghbrId > -1, "");
30929 if(a_bndryId(cellId) > -1 && a_bndryId(nghbrId) > -1) {
30930 if((surfaceDenied(a_bndryId(cellId), dirId) == false
30931 || surfaceDenied(a_bndryId(nghbrId), otherDir[dirId]) == false)
30932 && (surfaceCreated(a_bndryId(cellId), dirId) == false
30933 && surfaceCreated(a_bndryId(nghbrId), otherDir[dirId]) == false)) {
30934 createSrfc = true;
30935 }
30936 }
30937
30938 if(a_bndryId(cellId) == -1 || a_bndryId(nghbrId) == -1) {
30939 createSrfc = true;
30940 }
30941
30942 if(createSrfc) {
30943 // create one surface if the desicive level of the current cell is
30944 // less than the one from its neighbor
30945
30946 // do not create a surface between the master and the linked cell
30947 if(a_bndryId(cellId) > -1) {
30948 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_linkedCellId == nghbrId) {
30949 createSrfc = false;
30950 }
30951 }
30952
30953 if(a_bndryId(nghbrId) > -1) {
30954 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == cellId) {
30955 createSrfc = false;
30956 }
30957 }
30958
30959 // do not create a surface between periodic cells
30960 if(a_isPeriodic(cellId) && a_isPeriodic(nghbrId)) {
30961 createSrfc = false;
30962 }
30963
30964 // do not create a surface between two halo cells
30965 if(a_isHalo(cellId) && a_isHalo(nghbrId)) {
30966 createSrfc = false;
30967 }
30968
30969 // this is valid for isotropical refinement only!!
30970 if(createSrfc) {
30971 if((a_level(cellId) > a_level(nghbrId)) || ((a_level(cellId) == a_level(nghbrId)) && dirId % 2 == 0)) {
30972 computeSrfcs(cellId, nghbrId, dirId, srfcId);
30973 srfcId++;
30974 }
30975 }
30976 }
30977 }
30978 }
30979 }
30980
30981 for(MInt srfc = 0; srfc < a_noSurfaces(); srfc++) {
30982 MInt nghbr0 = a_surfaceNghbrCellId(srfc, 0);
30983 MInt nghbr1 = a_surfaceNghbrCellId(srfc, 1);
30984 MInt dir = a_surfaceOrientation(srfc);
30985 MInt dir0 = 2 * dir + 1;
30986 MInt dir1 = 2 * dir;
30987 if(a_bndryId(nghbr0) > -1) {
30988 m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbr0)].m_associatedSrfc[dir0] = srfc;
30989 }
30990 if(a_bndryId(nghbr1) > -1) {
30991 m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbr1)].m_associatedSrfc[dir1] = srfc;
30992 }
30993 }
30994 sumSrfc = a_noSurfaces();
30995 MPI_Allreduce(MPI_IN_PLACE, &sumSrfc, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "sumSrfc");
30996 MPI_Allreduce(MPI_IN_PLACE, &nmbr1, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "nmbr1");
30997 MPI_Allreduce(MPI_IN_PLACE, &nmbr2, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "nmbr2");
30998 m_log << "DEBUG: " << nmbr1 << " number of cells skipped: boundaryId ==-2" << endl;
30999 m_log << "DEBUG: " << nmbr2 << " number of cells skipped: IsOnCurrentMGLevel" << endl;
31000 m_log << "DEBUG: " << sumSrfc << " number of surfaces after second loop" << endl;
31001 return;
31002}
31003
31004
31005//-------------------------------------------------------------------------------------------------------
31006
31007template <MInt nDim_, class SysEqn>
31009 IF_CONSTEXPR(nDim == 2) { mTerm(1, "Only available in 3D. MGC not yet implemented in 2D."); }
31010 else {
31011 checkForSrfcsMGC_2_();
31012 }
31013}
31014
31028template <MInt nDim_, class SysEqn>
31030 TRACE();
31031 MBool createSrfc = true;
31032 MInt cell, counter;
31033 MInt srfcId, bndryId2, cell2;
31034 MInt nghbrId = 0, oldSrfcId, size;
31035 MInt noCells = a_noCells();
31036 MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
31037 MBool** surfaceDenied = new MBool*[noBndryCells];
31038 MBoolScratchSpace surfaceDenied_scratch(noBndryCells * m_noDirs, AT_, "surfaceDenied_scratch");
31039 for(MInt i = 0; i < noBndryCells; i++) {
31040 surfaceDenied[i] = &surfaceDenied_scratch.p[m_noDirs * i];
31041 for(MInt j = 0; j < m_noDirs; j++) {
31042 surfaceDenied[i][j] = false;
31043 }
31044 }
31045 MBool** surfaceCreated = new MBool*[noBndryCells];
31046 MBoolScratchSpace surfaceCreated_scratch(noBndryCells * m_noDirs, AT_, "surfaceCreated_scratch");
31047 for(MInt i = 0; i < noBndryCells; i++) {
31048 surfaceCreated[i] = &surfaceCreated_scratch.p[m_noDirs * i];
31049 for(MInt j = 0; j < m_noDirs; j++) {
31050 surfaceCreated[i][j] = false;
31051 }
31052 }
31053 constexpr MInt otherDir[] = {1, 0, 3, 2, 5, 4};
31054 MInt nghbr0, nghbr1;
31055 //---
31056
31057 m_surfaces.size(m_bndryCellSurfacesOffset);
31058
31059 // store the surfaces of all boundary cells
31060 // here equal level neighbors are assumed!!!
31061 counter = 0;
31062 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
31063 cell = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
31064
31065 if(m_fvBndryCnd->m_splitParents[bndryId] >= 0) {
31066 continue;
31067 }
31068 if(!a_hasProperty(cell, SolverCell::IsInvalid)) {
31069 if(a_hasProperty(cell, SolverCell::IsOnCurrentMGLevel)) {
31070 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
31071 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_externalFaces[dirId]) {
31072 surfaceDenied[bndryId][dirId] = true;
31073 }
31074 if(m_identNghbrIds[cell * m_noDirs + dirId] < m_identNghbrIds[cell * m_noDirs + dirId + 1]) {
31075 nghbrId = m_storeNghbrIds[m_identNghbrIds[cell * m_noDirs + dirId]];
31076 if(a_level(cell) < a_level(nghbrId)) {
31077 continue;
31078 }
31079 } else {
31080 continue;
31081 }
31082
31083 if(a_bndryId(nghbrId) < 0) {
31084 continue;
31085 }
31086
31087 if(a_hasProperty(nghbrId, SolverCell::IsInvalid)) {
31088 continue;
31089 }
31090 createSrfc = true;
31091
31092 // check if surface is a split surface - if yes, take care of the other neighbor, too;
31093 oldSrfcId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_associatedSrfc[dirId];
31094 if(oldSrfcId >= 0) {
31095 // check conditions for surface generation
31096 // (1) no master-slave interface
31097 // (2) no slave-slave interface if both slave cells have the same master
31098 // (3) no periodic-periodic interface
31099 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > -1) {
31100 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == nghbrId
31101 || m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId
31102 == m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId) {
31103 createSrfc = false;
31104 surfaceDenied[bndryId][dirId] = true;
31105 }
31106 }
31107 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId > -1) {
31108 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == (MInt)cell
31109 || m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId
31110 == m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId) {
31111 createSrfc = false;
31112 surfaceDenied[bndryId][dirId] = true;
31113 }
31114 }
31115 if(a_isPeriodic(cell) && a_isPeriodic(nghbrId)) {
31116 createSrfc = false;
31117 surfaceDenied[bndryId][dirId] = true;
31118 }
31119
31120 // do not create a surface between two halo cells
31121 // create a surface if slave-neighbor are both halo cells but the master is not
31122 if(a_isHalo(cell) && a_isHalo(nghbrId)) {
31123 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == -1
31124 && m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == -1) {
31125 createSrfc = false;
31126 surfaceDenied[bndryId][dirId] = true;
31127 }
31128 }
31129
31130 // this is valid for isotropical refinement only!!
31131 if(!createSrfc) {
31132 continue;
31133 }
31134
31135 oldSrfcId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_associatedSrfc[dirId];
31136
31137 if((a_level(cell) > a_level(nghbrId)) || ((a_level(cell) == a_level(nghbrId)) && dirId % 2 == 0)) {
31138 surfaceCreated[bndryId][dirId] = true;
31139
31140 if(oldSrfcId != counter) {
31141 m_surfaces.copy(oldSrfcId, counter);
31142 m_surfaces.erase(oldSrfcId);
31143 m_fvBndryCnd->m_bndryCells->a[bndryId].m_associatedSrfc[dirId] = counter;
31144 if(a_level(cell) == a_level(nghbrId)) {
31145 m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_associatedSrfc[otherDir[dirId]] = counter;
31146 }
31147 }
31148 counter++;
31149 }
31150 } else if(oldSrfcId < -1) { // split surface, check both neighbors
31151
31152 // first surface:
31153 srfcId = m_fvBndryCnd->m_splitSurfaces[-oldSrfcId * 6];
31154 nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
31155 nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
31156 if(nghbr0 == cell) {
31157 nghbrId = nghbr1;
31158 } else {
31159 nghbrId = nghbr0;
31160 }
31161
31162 // check conditions for surface generation
31163 // (1) no master-slave interface
31164 // (2) no slave-slave interface if both slave cells have the same master
31165 // (3) no periodic-periodic interface
31166 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > -1) {
31167 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == nghbrId
31168 || m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId
31169 == m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId) {
31170 createSrfc = false;
31171 surfaceDenied[bndryId][dirId] = true;
31172 }
31173 }
31174 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId > -1) {
31175 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == (MInt)cell
31176 || m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId
31177 == m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId) {
31178 createSrfc = false;
31179 surfaceDenied[bndryId][dirId] = true;
31180 }
31181 }
31182 if(a_isPeriodic(cell) && a_isPeriodic(nghbrId)) {
31183 createSrfc = false;
31184 surfaceDenied[bndryId][dirId] = true;
31185 }
31186
31187 // do not create a surface between two halo cells
31188 // create a surface if slave-neighbor are both halo cells but the master is not
31189 if(a_isHalo(cell) && a_isHalo(nghbrId)) {
31190 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == -1
31191 && m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == -1) {
31192 createSrfc = false;
31193 surfaceDenied[bndryId][dirId] = true;
31194 }
31195 }
31196
31197 // this is valid for isotropical refinement only!!
31198 if(!createSrfc) {
31199 continue;
31200 }
31201
31202 // check validity of first surface:
31203 if((a_level(cell) > a_level(nghbrId)) || ((a_level(cell) == a_level(nghbrId)) && dirId % 2 == 0)) {
31204 surfaceCreated[bndryId][dirId] = true;
31205
31206 if(srfcId != counter) {
31207 m_surfaces.copy(srfcId, counter);
31208 m_surfaces.erase(srfcId);
31209 m_fvBndryCnd->m_splitSurfaces[-oldSrfcId * 6] = counter;
31210 }
31211 counter++;
31212 }
31213
31214 // second surface:
31215 srfcId = m_fvBndryCnd->m_splitSurfaces[-oldSrfcId * 6 + 3];
31216 nghbr0 = a_surfaceNghbrCellId(srfcId, 0);
31217 nghbr1 = a_surfaceNghbrCellId(srfcId, 1);
31218 if(nghbr0 == cell) {
31219 nghbrId = nghbr1;
31220 } else {
31221 nghbrId = nghbr0;
31222 }
31223
31224 // check conditions for surface generation
31225 // (1) no master-slave interface
31226 // (2) no slave-slave interface if both slave cells have the same master
31227 // (3) no periodic-periodic interface
31228 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId > -1) {
31229 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == nghbrId
31230 || m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId
31231 == m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId) {
31232 createSrfc = false;
31233 surfaceDenied[bndryId][dirId] = true;
31234 }
31235 }
31236 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId > -1) {
31237 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == (MInt)cell
31238 || m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId
31239 == m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId) {
31240 createSrfc = false;
31241 surfaceDenied[bndryId][dirId] = true;
31242 }
31243 }
31244 if(a_isPeriodic(cell) && a_isPeriodic(nghbrId)) {
31245 createSrfc = false;
31246 surfaceDenied[bndryId][dirId] = true;
31247 }
31248
31249 // do not create a surface between two halo cells
31250 // create a surface if slave-neighbor are both halo cells but the master is not
31251 if(a_isHalo(cell) && a_isHalo(nghbrId)) {
31252 if(m_fvBndryCnd->m_bndryCells->a[bndryId].m_linkedCellId == -1
31253 && m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == -1) {
31254 createSrfc = false;
31255 surfaceDenied[bndryId][dirId] = true;
31256 }
31257 }
31258
31259 // this is valid for isotropical refinement only!!
31260 if(!createSrfc) {
31261 continue;
31262 }
31263
31264 // check validity of second surface:
31265 if((a_level(cell) > a_level(nghbrId)) || ((a_level(cell) == a_level(nghbrId)) && dirId % 2 == 0)) {
31266 surfaceCreated[bndryId][dirId] = true;
31267
31268 if(srfcId != counter) {
31269 m_surfaces.copy(srfcId, counter);
31270 m_surfaces.erase(srfcId);
31271 m_fvBndryCnd->m_splitSurfaces[-oldSrfcId * 6 + 3] = counter;
31272 }
31273 counter++;
31274 }
31275 }
31276 }
31277 }
31278 }
31279 for(MInt child = 0; child < 3; child++) {
31280 bndryId2 = m_fvBndryCnd->m_splitChildren[bndryId * 3 + child];
31281 if(bndryId2 == -1) {
31282 break;
31283 }
31284 cell2 = m_fvBndryCnd->m_bndryCells->a[bndryId2].m_cellId;
31285 if(!a_hasProperty(cell2, SolverCell::IsInvalid)) {
31286 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
31287 if(m_fvBndryCnd->m_bndryCells->a[bndryId2].m_externalFaces[dirId]) {
31288 surfaceDenied[bndryId2][dirId] = true;
31289 }
31290 if(m_identNghbrIds[cell2 * m_noDirs + dirId] < m_identNghbrIds[cell2 * m_noDirs + dirId + 1]) {
31291 nghbrId = m_storeNghbrIds[m_identNghbrIds[cell2 * m_noDirs + dirId]];
31292 if(a_level(cell2) < a_level(nghbrId)) {
31293 continue;
31294 }
31295 } else {
31296 continue;
31297 }
31298
31299 if(a_bndryId(nghbrId) < 0) {
31300 continue;
31301 }
31302 createSrfc = true;
31303
31304 // check conditions for surface generation
31305 // (1) no master-slave interface
31306 // (2) no slave-slave interface if both slave cells have the same master
31307 // (3) no periodic-periodic interface
31308 if(m_fvBndryCnd->m_bndryCells->a[bndryId2].m_linkedCellId > -1) {
31309 if(m_fvBndryCnd->m_bndryCells->a[bndryId2].m_linkedCellId == nghbrId
31310 || m_fvBndryCnd->m_bndryCells->a[bndryId2].m_linkedCellId
31311 == m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId) {
31312 createSrfc = false;
31313 surfaceDenied[bndryId2][dirId] = true;
31314 }
31315 }
31316 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId > -1) {
31317 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == (MInt)cell2
31318 || m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId
31319 == m_fvBndryCnd->m_bndryCells->a[bndryId2].m_linkedCellId) {
31320 createSrfc = false;
31321 surfaceDenied[bndryId2][dirId] = true;
31322 }
31323 }
31324 if(a_isPeriodic(cell2) && a_isPeriodic(nghbrId)) {
31325 createSrfc = false;
31326 surfaceDenied[bndryId2][dirId] = true;
31327 }
31328
31329 // do not create a surface between two halo cells
31330 // create a surface if slave-neighbor are both halo cells but the master is not
31331 if(a_isHalo(cell2) && a_isHalo(nghbrId)) {
31332 if(m_fvBndryCnd->m_bndryCells->a[bndryId2].m_linkedCellId == -1
31333 && m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == -1) {
31334 createSrfc = false;
31335 surfaceDenied[bndryId2][dirId] = true;
31336 }
31337 }
31338
31339 // this is valid for isotropical refinement only!!
31340 if(!createSrfc) {
31341 continue;
31342 }
31343
31344
31345 oldSrfcId = m_fvBndryCnd->m_bndryCells->a[bndryId2].m_associatedSrfc[dirId];
31346
31347 if(oldSrfcId == -1) {
31348 continue;
31349 }
31350
31351 if(oldSrfcId >= 0) {
31352 // create surface if its is no split surface:
31353
31354 if((a_level(cell2) > a_level(nghbrId)) || ((a_level(cell2) == a_level(nghbrId)) && dirId % 2 == 0)) {
31355 surfaceCreated[bndryId2][dirId] = true;
31356
31357 if(oldSrfcId != counter) {
31358 m_surfaces.copy(oldSrfcId, counter);
31359 m_surfaces.erase(oldSrfcId);
31360 m_fvBndryCnd->m_bndryCells->a[bndryId2].m_associatedSrfc[dirId] = counter;
31361 if(a_level(cell2) == a_level(nghbrId)) {
31362 m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_associatedSrfc[otherDir[dirId]] = counter;
31363 }
31364 }
31365 counter++;
31366 }
31367 }
31368 }
31369 }
31370 }
31371 }
31372
31373 createSrfc = false;
31374
31375 // delete all other surfaces created in createCutFace
31376 while(a_noSurfaces() > counter) {
31377 size = a_noSurfaces();
31378 m_surfaces.erase(size - 1);
31379 m_surfaces.size(size - 1);
31380 }
31381
31382 // set the offset of all boundary interfaces (important for mesh adaptation!)
31383 m_bndryCellSurfacesOffset = a_noSurfaces();
31384
31385 // set srfcId
31386 srfcId = a_noSurfaces();
31387
31388 for(MInt cellId = 0; cellId < noCells; cellId++) {
31389 if(a_isBndryGhostCell(cellId)) {
31390 continue;
31391 }
31392 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
31393 continue;
31394 }
31395
31396 for(MInt dirId = 0; dirId < m_noDirs; dirId++) {
31397 for(MInt nghbr = m_identNghbrIds[cellId * m_noDirs + dirId];
31398 nghbr < m_identNghbrIds[cellId * m_noDirs + dirId + 1];
31399 nghbr++) {
31400 createSrfc = false;
31401 nghbrId = m_storeNghbrIds[nghbr];
31402
31403 if(a_bndryId(cellId) > -1 && a_bndryId(nghbrId) > -1) {
31404 if((surfaceDenied[a_bndryId(cellId)][dirId] == false
31405 || surfaceDenied[a_bndryId(nghbrId)][otherDir[dirId]] == false)
31406 && (surfaceCreated[a_bndryId(cellId)][dirId] == false
31407 && surfaceCreated[a_bndryId(nghbrId)][otherDir[dirId]] == false)) {
31408 createSrfc = true;
31409 }
31410 }
31411
31412 if(a_bndryId(cellId) == -1 || a_bndryId(nghbrId) == -1) {
31413 createSrfc = true;
31414 }
31415
31416 if(createSrfc) {
31417 // create one surface if the desicive level of the current cell is
31418 // less than the one from its neighbor
31419
31420 // do not create a surface between the master and the linked cell
31421 if(a_bndryId(cellId) > -1) {
31422 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_linkedCellId == nghbrId) {
31423 createSrfc = false;
31424 }
31425 }
31426
31427 if(a_bndryId(nghbrId) > -1) {
31428 if(m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbrId)].m_linkedCellId == cellId) {
31429 createSrfc = false;
31430 }
31431 }
31432
31433 // do not create a surface between periodic cells
31434 if(a_isPeriodic(cellId) && a_isPeriodic(nghbrId)) {
31435 createSrfc = false;
31436 }
31437
31438 // do not create a surface between two halo cells
31439 if(a_isHalo(cellId) && a_isHalo(nghbrId)) {
31440 createSrfc = false;
31441 }
31442
31443 // this is valid for isotropical refinement only!!
31444 if(createSrfc) {
31445 if((a_level(cellId) > a_level(nghbrId)) || ((a_level(cellId) == a_level(nghbrId)) && dirId % 2 == 0)) {
31446 computeSrfcs(cellId, nghbrId, dirId, srfcId);
31447
31448 srfcId++;
31449 }
31450 }
31451 }
31452 }
31453 }
31454 }
31455 delete[] surfaceDenied;
31456 surfaceDenied = 0;
31457 delete[] surfaceCreated;
31458 surfaceCreated = 0;
31459
31460 for(MInt srfc = 0; srfc < a_noSurfaces(); srfc++) {
31461 nghbr0 = a_surfaceNghbrCellId(srfc, 0);
31462 nghbr1 = a_surfaceNghbrCellId(srfc, 1);
31463 MInt dir = a_surfaceOrientation(srfc);
31464 MInt dir0 = 2 * dir + 1;
31465 MInt dir1 = 2 * dir;
31466 if(a_bndryId(nghbr0) > -1) {
31467 m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbr0)].m_associatedSrfc[dir0] = srfc;
31468 }
31469 if(a_bndryId(nghbr1) > -1) {
31470 m_fvBndryCnd->m_bndryCells->a[a_bndryId(nghbr1)].m_associatedSrfc[dir1] = srfc;
31471 }
31472 }
31473 return;
31474}
31475
31476//-----------------------------------------------------------------------------
31477
31478template <MInt nDim_, class SysEqn>
31480 IF_CONSTEXPR(nDim == 2) { mTerm(1, "Only meaningful in 3D."); }
31481 else {
31482 correctBoundarySurfaces_();
31483 }
31484}
31485
31486template <MInt nDim_, class SysEqn>
31488 TRACE();
31489
31490 const MInt noCells = a_noCells();
31491 const MInt noBCCells = m_fvBndryCnd->m_bndryCells->size();
31492 const MInt noSurfaces = a_noSurfaces();
31493 const MFloat eps = c_cellLengthAtLevel(maxRefinementLevel()) * 0.00001;
31494 ScratchSpace<MFloat> area(3 * maxNoGridCells(), AT_, "area");
31495 //---
31496
31497 m_surfaces.size(m_bndrySurfacesOffset);
31498
31499 for(MInt bc = 0; bc < noBCCells; bc++) {
31500 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bc].m_cellId;
31501 for(MInt d = 0; d < nDim; d++) {
31502 area[d * noCells + cellId] = F0;
31503 }
31504 }
31505
31506 for(MInt s = 0; s < noSurfaces; s++) {
31507 MInt i = a_surfaceOrientation(s);
31508 area[i * noCells + a_surfaceNghbrCellId(s, 0)] -= a_surfaceArea(s);
31509 area[i * noCells + a_surfaceNghbrCellId(s, 1)] += a_surfaceArea(s);
31510 }
31511
31512 for(MInt bc = 0; bc < noBCCells; bc++) {
31513 if(m_fvBndryCnd->m_bndryCells->a[bc].m_linkedCellId == -1) {
31514 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bc].m_cellId;
31515
31516 if(a_isHalo(cellId)) continue;
31517
31518 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
31519
31520 if(c_noChildren(cellId) > 0) continue;
31521
31522 // check whether a refined cell is present
31523 MBool check = false;
31524 for(MInt d = 0; d < m_noDirs; d++) {
31525 if(a_hasNeighbor(cellId, d) > 0) {
31526 if(c_noChildren(c_neighborId(cellId, d)) > 0) {
31527 check = true;
31528 }
31529 }
31530 }
31531 if(check) {
31532 for(MInt d = 0; d < nDim; d++) {
31533 if(ABS(area[d * noCells + cellId]) > eps) {
31534 // correct
31535 MFloat totalArea = F0;
31536 for(MInt dd = 0; dd < nDim; dd++) {
31537 if(m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_normalVector[dd] > F0) {
31538 totalArea += POW2(ABS(m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_normalVector[dd])
31539 * m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_area
31540 + area[dd * noCells + cellId]);
31541 area[dd * noCells + cellId] = ABS(m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_normalVector[dd])
31542 * m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_area
31543 + area[dd * noCells + cellId];
31544 } else {
31545 totalArea += POW2(ABS(m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_normalVector[dd])
31546 * m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_area
31547 - area[dd * noCells + cellId]);
31548 area[dd * noCells + cellId] = -ABS(m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_normalVector[dd])
31549 * m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_area
31550 - area[dd * noCells + cellId];
31551 }
31552 }
31553 // update the surface area and the normal vector
31554 m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_area = sqrt(totalArea);
31555 for(MInt dd = 0; dd < nDim; dd++) {
31556 m_fvBndryCnd->m_bndryCells->a[bc].m_srfcs[0]->m_normalVector[dd] =
31557 area[dd * noCells + cellId] / sqrt(totalArea);
31558 }
31559 break;
31560 }
31561 }
31562 }
31563 }
31564 }
31565}
31566
31567
31568// === Azimuthal periodic concept (3D stuff) ==================================
31569
31570template <MInt nDim_, class SysEqn>
31572 IF_CONSTEXPR(nDim == 2) { mTerm(1, "Azimuthal periodicity concept meaningful only in 3D."); }
31573 else {
31574 computeRecConstPeriodic_();
31575 }
31576}
31577
31582template <MInt nDim_, class SysEqn>
31584 TRACE();
31585
31586
31587 MBool nonlinear = true; // false;
31588 MInt maxNoNghbrs = 200;
31589 MInt matrix_dim = nDim + 1;
31590 if(nonlinear) {
31591 matrix_dim = 3 * nDim + 1;
31592 }
31593
31594 MFloatScratchSpace mat(maxNoNghbrs, matrix_dim, AT_, "mat");
31595 MFloatScratchSpace matInv(matrix_dim, maxNoNghbrs, AT_, "matInv");
31596 MFloatScratchSpace weights(maxNoNghbrs, AT_, "weights");
31597 MIntScratchSpace nghbrList_(maxNoNghbrs, AT_, "nghbrList");
31598 MIntScratchSpace layerId_(maxNoNghbrs, AT_, "layerList");
31599
31600
31601 mat.fill(F0);
31602 weights.fill(F0);
31603
31604 // rec const for non bndry cells
31605 MInt n_Id = -1;
31606 MInt cell_Id = -1;
31607 MInt sortedId = -1;
31608 MInt k_ = 0;
31609 MInt offset_cell = 0;
31610 MInt off_ = 0;
31611 MInt noSendingCells = 0;
31612 MInt counter_ = 0;
31613
31614 for(MInt d = 0; d < noDomains(); d++) {
31615 noSendingCells += m_noPerCellsToSend[d];
31616 }
31617
31618
31619 mAlloc(m_reconstructionDataPeriodic, noSendingCells + 1, "m_reconstructionDataPeriodic", -1, AT_);
31620 mAlloc(m_reconstructionConstantsPeriodic, (noSendingCells * maxNoNghbrs * 2), "m_reconstructionConstantsPeriodic", F0,
31621 AT_);
31622
31623 m_reconstructionDataPeriodic[0] = 0;
31624
31625 for(MInt d = 0; d < noDomains(); d++) {
31626 for(MInt c = 0; c < m_noPerCellsToSend[d]; c++) {
31627 cell_Id = static_cast<MInt>(m_periodicDataToSend[d][6 + c * m_noPeriodicData]);
31628 sortedId = static_cast<MInt>(m_periodicDataToSend[d][5 + c * m_noPeriodicData]);
31629
31630
31631 MFloat normalizationFactor = FPOW2(a_level(cell_Id)) / c_cellLengthAtLevel(0);
31632
31633 counter_ = 0;
31634
31635 counter_ = getAdjacentLeafCells<2, true>(cell_Id, 2, nghbrList_, layerId_);
31636 k_ = 0;
31637
31638 if(counter_ > maxNoNghbrs) {
31639 mTerm(1, AT_, "raise noMaxNghbrs");
31640 }
31641
31642 /* MBool correct = false;
31643 if(a_bndryId(cell_Id)>-1 && correct)
31644 {
31645 MInt srfc=0;
31646 MFloat dn=0.0;//c_cellLengthAtCell(cell_Id)/100.0;//0.0;
31647 MInt bndryId=a_bndryId(cell_Id);
31648
31649 for( MInt i=0; i<nDim; i++ ) { dn += m_bndryCells->a[ bndryId
31650 ].m_srfcs[srfc]->m_normalVector[ i ] * ( m_periodicCellDataDom[d][i+sortedId*5] -
31651 m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_coordinates[ i ] );
31652 }
31653
31654
31655
31656 if(dn<0.0){
31657 cerr << "rotated point is outside / will be corrected" <<
31658 m_periodicCellDataDom[d][0+sortedId*5] << " " << m_periodicCellDataDom[d][1+sortedId*5] << "
31659 " << m_periodicCellDataDom[d][2+sortedId*5]<< " dn " << dn <<endl;
31660
31661 dn=fabs(dn);
31662 for ( MInt i = 0; i < nDim; i++ ) {
31663 m_periodicCellDataDom[d][i+sortedId*5] = m_periodicCellDataDom[d][i+sortedId*5]
31664 + 2.0*dn*m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_normalVector[ i ];
31665 }
31666
31667
31668 dn=0.0;
31669
31670
31671
31672 for( MInt i=0; i<nDim; i++ ) { dn += m_bndryCells->a[ bndryId
31673 ].m_srfcs[srfc]->m_normalVector[ i ] * ( m_periodicCellDataDom[d][i+sortedId*5] -
31674 m_bndryCells->a[ bndryId ].m_srfcs[srfc]->m_coordinates[ i ] );
31675 }
31676
31677 if(dn<0.0){
31678
31679 cerr << "rotated point is still outside " << m_periodicCellDataDom[d][0+sortedId*5] << "
31680 " << m_periodicCellDataDom[d][1+sortedId*5] << " " << m_periodicCellDataDom[d][2+sortedId*5]<<
31681 " dn " << dn<<endl; mTerm(1,AT_, "point still outside domain");
31682 }
31683 }
31684
31685 }
31686
31687
31688*/
31689
31690 for(MInt n = 0; n < counter_; n++) {
31691 n_Id = nghbrList_[n];
31692 if(n_Id < 0) {
31693 continue;
31694 }
31695 if(a_hasProperty(n_Id, SolverCell::IsPeriodicWithRot)) {
31696 continue;
31697 }
31698 if(!a_hasProperty(n_Id, SolverCell::IsOnCurrentMGLevel)) {
31699 continue;
31700 }
31701 if(c_noChildren(n_Id) > 0) {
31702 continue;
31703 }
31704 if(n_Id == cell_Id) {
31705 continue;
31706 }
31707
31708 m_reconstructionConstantsPeriodic[offset_cell + k_] = nghbrList_[n];
31709
31710 MInt cnt = 0;
31711
31712 mat(k_, cnt) = F1;
31713 cnt++;
31714
31715 MFloat dx = F0;
31716 for(MInt i = 0; i < nDim; i++) {
31717 mat(k_, cnt) = (a_coordinate(n_Id, i) - m_periodicCellDataDom[d][i + sortedId * m_noPeriodicCellData])
31718 * normalizationFactor;
31719 dx += POW2(a_coordinate(n_Id, i) - m_periodicCellDataDom[d][i + sortedId * m_noPeriodicCellData]);
31720 cnt++;
31721 }
31722
31723 weights(k_) = maia::math::RBF(dx, POW2(c_cellLengthAtCell(cell_Id)));
31724
31725
31726 if(nonlinear) {
31727 for(MInt i = 0; i < nDim; i++) {
31728 mat(k_, cnt) =
31729 0.5
31730 * POW2((a_coordinate(n_Id, i) - m_periodicCellDataDom[d][i + sortedId * m_noPeriodicCellData])
31731 * normalizationFactor);
31732 cnt++;
31733 }
31734
31735 for(MInt i = 0; i < nDim; i++) {
31736 for(MInt j = i + 1; j < nDim; j++) {
31737 mat(k_, cnt) = (a_coordinate(n_Id, j) - m_periodicCellDataDom[d][j + sortedId * m_noPeriodicCellData])
31738 * (a_coordinate(n_Id, i) - m_periodicCellDataDom[d][i + sortedId * m_noPeriodicCellData])
31739 * POW2(normalizationFactor);
31740 cnt++;
31741 }
31742 }
31743 }
31744 k_++;
31745 }
31746
31747
31748 if(!a_hasProperty(cell_Id, SolverCell::IsPeriodicWithRot)) // add cell for rec
31749 {
31750 m_reconstructionConstantsPeriodic[offset_cell + k_] = cell_Id;
31751 MInt cnt = 0;
31752
31753 mat(k_, cnt) = F1;
31754 cnt++;
31755
31756 MFloat dx = F0;
31757 for(MInt i = 0; i < nDim; i++) {
31758 mat(k_, cnt) = (a_coordinate(cell_Id, i) - m_periodicCellDataDom[d][i + sortedId * m_noPeriodicCellData])
31759 * normalizationFactor;
31760 dx += POW2(a_coordinate(cell_Id, i) - m_periodicCellDataDom[d][i + sortedId * m_noPeriodicCellData]);
31761 cnt++;
31762 }
31763
31764 weights(k_) = maia::math::RBF(dx, POW2(c_cellLengthAtCell(cell_Id)));
31765
31766
31767 if(nonlinear) {
31768 for(MInt i = 0; i < nDim; i++) {
31769 mat(k_, cnt) =
31770 0.5
31771 * POW2((a_coordinate(cell_Id, i) - m_periodicCellDataDom[d][i + sortedId * m_noPeriodicCellData])
31772 * normalizationFactor);
31773 cnt++;
31774 }
31775
31776
31777 for(MInt i = 0; i < nDim; i++) {
31778 for(MInt j = i + 1; j < nDim; j++) {
31779 mat(k_, cnt) =
31780 (a_coordinate(cell_Id, j) - m_periodicCellDataDom[d][j + sortedId * m_noPeriodicCellData])
31781 * (a_coordinate(cell_Id, i) - m_periodicCellDataDom[d][i + sortedId * m_noPeriodicCellData])
31782 * POW2(normalizationFactor);
31783 cnt++;
31784 }
31785 }
31786 }
31787
31788 k_++;
31789 }
31790
31791
31792 maia::math::invert(mat, weights, matInv, k_, matrix_dim);
31793
31794
31795 for(MInt l = 0; l < k_; l++) {
31796 for(MInt i = 0; i < matrix_dim - 1; i++) {
31797 matInv(1 + i, l) *= normalizationFactor;
31798 }
31799 }
31800
31801
31802 for(MInt l = 0; l < k_; l++) {
31803 m_reconstructionConstantsPeriodic[offset_cell + k_ + l] = matInv(0, l);
31804 if((offset_cell + k_ + l) > (noSendingCells * maxNoNghbrs * 2)) {
31805 mTerm(1, AT_, "raise noSendingCells");
31806 }
31807 }
31808
31809
31810 offset_cell += 2 * k_;
31811
31812 m_reconstructionDataPeriodic[off_ + c + 1] = offset_cell;
31813 }
31814
31815 off_ += m_noPerCellsToSend[d];
31816 }
31817}
31818
31819
31820template <MInt nDim_, class SysEqn>
31822 IF_CONSTEXPR(nDim == 2) { mTerm(1, "Azimuthal periodicity concept meaningful only in 3D."); }
31823 else {
31824 identPeriodicCells_();
31825 }
31826}
31827
31832template <MInt nDim_, class SysEqn>
31834 TRACE();
31835
31836 m_noPeriodicCellData = PV->noVariables;
31837 m_noPeriodicData = m_noPeriodicCellData + 2;
31838
31839 MFloat periodic_coord[2];
31840 periodic_coord[0] = 0.0;
31841 periodic_coord[1] = 0.0;
31842 if(m_periodicCells == 2 || m_periodicCells == 3) {
31843 for(MInt i = 0; i < 2; i++) {
31844 periodic_coord[i] = Context::getSolverProperty<MFloat>("periodic_coord", m_solverId, AT_, i);
31845 }
31846 }
31847 // init
31848 MInt m_maxNoPeriodicCells = 0;
31849 m_maxNoPeriodicCells = Context::getSolverProperty<MInt>("maxNoPeriodicCells", m_solverId, AT_, &m_maxNoPeriodicCells);
31850
31851 m_sortedPeriodicCells->setSize(0);
31852
31853 MFloat z_min_1, z_min_2, z_min_11, z_min_12;
31854 MFloat halfLength_1, halfLength_2;
31855
31856 MFloat xmax = -900.0;
31857 MFloat ymax = -900.0;
31858 MFloat zmax = -900.0;
31859
31860 MFloat xmin = 900.0;
31861 MFloat ymin = 900.0;
31862 MFloat zmin = 900.0;
31863
31864
31865 // domain boundaries
31866 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
31867 xmax = mMax(xmax, a_coordinate(cellId, 0));
31868 ymax = mMax(ymax, a_coordinate(cellId, 1));
31869 zmax = mMax(zmax, a_coordinate(cellId, 2));
31870 xmin = mMin(xmin, a_coordinate(cellId, 0));
31871 ymin = mMin(ymin, a_coordinate(cellId, 1));
31872 zmin = mMin(zmin, a_coordinate(cellId, 2));
31873 }
31874
31875 // m_fvBndryCnd->recorrectCellCoordinates();
31876
31877 // search cells in overlapping region and add them to m_sortedPeriodicCells (skip ghost cells)
31878 // m_periodicCells=1 --> azimuthal periodicity (with LS interpolation)
31879 // m_periodicCells=2 --> periodicity in x-direction (without LS interpolation)
31880 // m_periodicCells=3 --> periodicity in x-direction (without LS interpolation + volume forcing)
31881 if(m_periodicCells == 1) {
31882 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
31883 a_hasProperty(cellId, SolverCell::IsPeriodicWithRot) = false;
31884
31885 if(a_isBndryGhostCell(cellId) || c_noChildren(cellId) != 0
31886 || !a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
31887 continue;
31888 }
31889
31890
31891 halfLength_1 = c_cellLengthAtLevel(a_level(cellId) + 1);
31892 halfLength_2 = c_cellLengthAtLevel(maxLevel() + 1);
31893
31894 z_min_1 = -6.3137515147 * a_coordinate(cellId, 1) + 1462.750302935;
31895 z_min_2 = -0.1583844403 * a_coordinate(cellId, 1) + 231.6768880649;
31896 z_min_11 = -6.3137515147 * (a_coordinate(cellId, 1) - halfLength_1) + 1462.750302935;
31897 z_min_12 = -0.1583844403 * (a_coordinate(cellId, 1) + halfLength_1) + 231.6768880649;
31898
31899
31900 if(( // Cells between periodic Bndry
31901 a_coordinate(cellId, 1) < m_rotAxisCoord[0] && a_coordinate(cellId, 2) <= z_min_1
31902 && a_coordinate(cellId, 2) >= z_min_2)
31903 || ( // intersection Cells on left periodic Bndry
31904 a_coordinate(cellId, 1) < m_rotAxisCoord[0] && a_coordinate(cellId, 2) > z_min_1
31905 && (a_coordinate(cellId, 2) - halfLength_1) < z_min_11 //&&a_bndryId( cellId )< 0
31906 )
31907 || ( // intersection Cells on left periodic Bndry
31908 a_coordinate(cellId, 1) > (m_rotAxisCoord[0] - 4.0 * halfLength_2)
31909 && a_coordinate(cellId, 1) < m_rotAxisCoord[0] && a_coordinate(cellId, 2) < z_min_2
31910 && (a_coordinate(cellId, 2) + halfLength_1) > z_min_12 //&&a_bndryId( cellId )< 0
31911 )
31912 || ( // Cells at rotAxis
31913 (fabs(a_coordinate(cellId, 1) - m_rotAxisCoord[0]) < halfLength_1 * 2.0)
31914 && (fabs(a_coordinate(cellId, 2) - m_rotAxisCoord[1]) < halfLength_1 * 2.0))) {
31915 continue;
31916 }
31917
31918 m_sortedPeriodicCells->a[m_sortedPeriodicCells->size()] = cellId;
31919 a_hasProperty(cellId, SolverCell::IsPeriodicWithRot) = true;
31920 m_sortedPeriodicCells->append();
31921 }
31922 } else if(m_periodicCells == 2 || m_periodicCells == 3) {
31923 m_fvBndryCnd->recorrectCellCoordinates();
31924
31925 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
31926 a_hasProperty(cellId, SolverCell::IsPeriodicWithRot) = false;
31927
31928 if(a_isBndryGhostCell(cellId) || c_noChildren(cellId) != 0
31929 || !a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
31930 continue;
31931 }
31932
31933 if( // Cells between periodic Bndry
31934 a_coordinate(cellId, 0) > periodic_coord[0] && a_coordinate(cellId, 0) < periodic_coord[1]) {
31935 continue;
31936 }
31937
31938 m_sortedPeriodicCells->a[m_sortedPeriodicCells->size()] = cellId;
31939 a_hasProperty(cellId, SolverCell::IsPeriodicWithRot) = true;
31940 m_sortedPeriodicCells->append();
31941 }
31942 m_fvBndryCnd->rerecorrectCellCoordinates();
31943 }
31944
31945 if(m_maxNoPeriodicCells < m_sortedPeriodicCells->size()) {
31946 mTerm(1, AT_, "raise max periodc cells");
31947 }
31948
31949
31950 m_log << "*************************" << endl;
31951 m_log << "PeriodicCells Identified" << endl;
31952 m_log << "*************************" << endl;
31953
31954 xmax += c_cellLengthAtLevel(minLevel());
31955 ymax += c_cellLengthAtLevel(minLevel());
31956 zmax += c_cellLengthAtLevel(minLevel());
31957 xmin -= c_cellLengthAtLevel(minLevel());
31958 ymin -= c_cellLengthAtLevel(minLevel());
31959 zmin -= c_cellLengthAtLevel(minLevel());
31960
31961
31962 // m_fvBndryCnd->rerecorrectCellCoordinates();
31963 MInt noPeriodicCells; // no of Cells(in this Domain) in overlapping Region
31964 noPeriodicCells = m_sortedPeriodicCells->size();
31965
31966 // excahnge number of Cells in overlapping region for every domain
31967 mAlloc(m_noPeriodicCellsDom, noDomains(), "m_noPeriodicCellsDom", -1, AT_);
31968
31969 for(MInt i = 0; i < noDomains(); i++) {
31970 m_noPeriodicCellsDom[i] = 0;
31971 }
31972
31973 MPI_Allgather(&noPeriodicCells, 1, MPI_INT, m_noPeriodicCellsDom, 1, MPI_INT, mpiComm(), AT_, "noPeriodicCells",
31974 "m_noPeriodicCellsDom");
31975
31976
31977 // save coordinates of cutted cells and exchange them.....after rotating compare them to uncutted
31978 // cells m_periodicCellDataDom[x][y][z][cellId or -1][left=-1 right=+1] save coordinates of cutted
31979 // cells in m_noPeriodicCellsDom
31980 m_periodicCellDataDom = new MFloat*[noDomains()];
31981 for(MInt domains = 0; domains < noDomains(); domains++) {
31982 m_periodicCellDataDom[domains] = new MFloat[m_noPeriodicCellsDom[domains] * m_noPeriodicCellData];
31983 }
31984 m_log << "*************************" << endl;
31985 m_log << "Alloc Memory" << endl;
31986 m_log << "*************************" << endl;
31987
31988 MFloat z_min_45 = 0.0;
31989 MFloat x_mid = 0;
31990 x_mid = (periodic_coord[0] + periodic_coord[1]) / 2.0;
31991
31992 if(m_periodicCells == 1) {
31993 for(MInt id = 0; id < noPeriodicCells; id++) {
31994 for(MInt dim = 0; dim < 3; dim++) {
31995 m_periodicCellDataDom[domainId()][dim + m_noPeriodicCellData * id] =
31996 a_coordinate(m_sortedPeriodicCells->a[id], dim);
31997 }
31998 m_periodicCellDataDom[domainId()][3 + m_noPeriodicCellData * id] = -1; // set cellsId to copy from to -1
31999 z_min_45 = -a_coordinate(m_sortedPeriodicCells->a[id], 1) + 400 - c_cellLengthAtLevel(minLevel()) / 10.0;
32000
32001 if(a_coordinate(m_sortedPeriodicCells->a[id], 2) >= z_min_45) {
32002 m_periodicCellDataDom[domainId()][4 + m_noPeriodicCellData * id] = -1.0;
32003 } else {
32004 m_periodicCellDataDom[domainId()][4 + m_noPeriodicCellData * id] = 1.0;
32005 }
32006 }
32007 } else if(m_periodicCells == 2 || m_periodicCells == 3) {
32008 for(MInt id = 0; id < noPeriodicCells; id++) {
32009 for(MInt dim = 0; dim < 3; dim++) {
32010 m_periodicCellDataDom[domainId()][dim + m_noPeriodicCellData * id] =
32011 a_coordinate(m_sortedPeriodicCells->a[id], dim);
32012 }
32013 m_periodicCellDataDom[domainId()][3 + m_noPeriodicCellData * id] = -1; // set cellsId to copy from to -1
32014
32015 if(a_coordinate(m_sortedPeriodicCells->a[id], 2) < x_mid) {
32016 m_periodicCellDataDom[domainId()][4 + m_noPeriodicCellData * id] = -1.0; // left periodic boundary
32017 } else {
32018 m_periodicCellDataDom[domainId()][4 + m_noPeriodicCellData * id] = 1.0; // right periodic boundary
32019 }
32020 }
32021 }
32022
32023 ScratchSpace<MPI_Request> send_Req(noDomains(), AT_, "sendReq");
32024 ScratchSpace<MPI_Request> recv_Req(noDomains(), AT_, "recvReq");
32025 send_Req.fill(MPI_REQUEST_NULL);
32026 recv_Req.fill(MPI_REQUEST_NULL);
32027
32028 // exchange cell coordinates
32029 for(MInt snd = 0; snd < domainId(); snd++) {
32030 if(m_noPeriodicCellsDom[snd] > 0) {
32031 MInt bufSize = m_noPeriodicCellsDom[snd] * m_noPeriodicCellData;
32032 MPI_Irecv(m_periodicCellDataDom[snd], bufSize, MPI_DOUBLE, snd, 0, mpiComm(), &recv_Req[snd], AT_,
32033 "m_periodicCellDataDom[snd]");
32034 }
32035 }
32036 for(MInt rcv = 0; rcv < noDomains(); rcv++) {
32037 if(rcv != domainId()) {
32038 if(m_noPeriodicCellsDom[domainId()] > 0) {
32039 MInt bufSize = m_noPeriodicCellsDom[domainId()] * m_noPeriodicCellData;
32040 MPI_Isend(m_periodicCellDataDom[domainId()], bufSize, MPI_DOUBLE, rcv, 0, mpiComm(), &send_Req[rcv], AT_,
32041 "m_periodicCellDataDom[domainId()]");
32042 }
32043 }
32044 }
32045
32046 if(domainId() < noDomains() - 1) {
32047 for(MInt snd = domainId() + 1; snd < noDomains(); snd++) {
32048 if(m_noPeriodicCellsDom[snd] > 0) {
32049 MInt bufSize = m_noPeriodicCellsDom[snd] * m_noPeriodicCellData;
32050 MPI_Irecv(m_periodicCellDataDom[snd], bufSize, MPI_DOUBLE, snd, 0, mpiComm(), &recv_Req[snd], AT_,
32051 "m_periodicCellDataDom[snd]");
32052 }
32053 }
32054 }
32055
32056 MPI_Waitall(noDomains(), &recv_Req[0], MPI_STATUSES_IGNORE, AT_);
32057 MPI_Waitall(noDomains(), &send_Req[0], MPI_STATUSES_IGNORE, AT_);
32058
32059
32060 MFloat halfLength = 0;
32061 MFloat c_x, c_y, c_z, c_x_rot, c_y_rot, c_z_rot;
32062 MBool rotated = false;
32063 MBool found = false;
32064 MFloat count_found = 0;
32065 MInt rot_counter = 0;
32066
32067 // get coordinates of uncutted cells
32068 m_fvBndryCnd->recorrectCellCoordinates();
32069
32070
32071 m_log << "*************************" << endl;
32072 m_log << "Build Tree" << endl;
32073 m_log << "*************************" << endl;
32074
32075
32076 const MInt maxNoNghbrs_ = 45;
32077 MIntScratchSpace nghbrList_(maxNoNghbrs_, AT_, "nghbrList");
32078 MIntScratchSpace layerId_(maxNoNghbrs_, AT_, "layerList");
32079 MInt counter_ = 0;
32080
32081
32082 MInt noCells = noInternalCells();
32083
32084 vector<Point<3>> pts;
32085 for(MInt cellId = 0; cellId < noCells; ++cellId) {
32086 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel) && !a_isBndryGhostCell(cellId) && !a_isHalo(cellId)
32087 && c_isLeafCell(cellId)) {
32088 Point<3> a(a_coordinate(cellId, 0), a_coordinate(cellId, 1), a_coordinate(cellId, 2), cellId);
32089 pts.push_back(a);
32090 }
32091 }
32092
32093 // build up the tree
32094 KDtree<3> tree(pts);
32095 MFloat distance = -1.0;
32096 MFloat eps_ = c_cellLengthAtLevel(maxRefinementLevel()) / 100.0;
32097
32098
32099 m_log << "*************************" << endl;
32100 m_log << "Tree Built" << endl;
32101 m_log << "*************************" << endl;
32102
32103 // rotate coordinates and look for cells to copy from in each domain
32104 for(MInt domain = 0; domain < noDomains(); domain++) {
32105 for(MInt cell = 0; cell < m_noPeriodicCellsDom[domain]; cell++) {
32106 found = false;
32107 rot_counter = 0;
32108 c_x = m_periodicCellDataDom[domain][0 + m_noPeriodicCellData * cell];
32109 c_y = m_periodicCellDataDom[domain][1 + m_noPeriodicCellData * cell];
32110 c_z = m_periodicCellDataDom[domain][2 + m_noPeriodicCellData * cell];
32111
32112 // rotate until inner region reached
32113 z_min_45 = -c_y + 400 - c_cellLengthAtLevel(minLevel()) / 10.0;
32114
32115 if(m_periodicCells == 1) {
32116 if(c_z < z_min_45) {
32117 do {
32118 rot_counter++;
32119 rotated = false;
32120 c_y_rot = cos(72.0 / 180.0 * PI) * (c_y - m_rotAxisCoord[0])
32121 + sin(72.0 / 180.0 * PI) * (c_z - m_rotAxisCoord[1]) + m_rotAxisCoord[0];
32122 c_z_rot = -sin(72.0 / 180.0 * PI) * (c_y - m_rotAxisCoord[0])
32123 + cos(72.0 / 180.0 * PI) * (c_z - m_rotAxisCoord[1]) + m_rotAxisCoord[1];
32124 c_x_rot = c_x;
32125 m_periodicCellDataDom[domain][1 + m_noPeriodicCellData * cell] = c_y_rot;
32126 m_periodicCellDataDom[domain][2 + m_noPeriodicCellData * cell] = c_z_rot;
32127 c_y = c_y_rot;
32128 c_z = c_z_rot;
32129
32130 z_min_1 = -6.3137515147 * c_y + 1462.750302935;
32131 z_min_2 = -0.1583844403 * c_y + 231.6768880649;
32132
32133
32134 if((c_z >= (z_min_2 - eps_) && c_z <= (z_min_1 + eps_) && c_y <= m_rotAxisCoord[0])
32135 || rot_counter == 2 // && c_z> 200.0
32136 ) {
32137 rotated = true;
32138 }
32139 } while(!rotated);
32140 } else {
32141 do {
32142 rot_counter++;
32143 rotated = false;
32144 c_y_rot = cos(72.0 / 180.0 * PI) * (c_y - m_rotAxisCoord[0])
32145 - sin(72.0 / 180.0 * PI) * (c_z - m_rotAxisCoord[1]) + m_rotAxisCoord[0];
32146 c_z_rot = +sin(72.0 / 180.0 * PI) * (c_y - m_rotAxisCoord[0])
32147 + cos(72.0 / 180.0 * PI) * (c_z - m_rotAxisCoord[1]) + m_rotAxisCoord[0];
32148 c_x_rot = c_x;
32149 m_periodicCellDataDom[domain][1 + m_noPeriodicCellData * cell] = c_y_rot;
32150 m_periodicCellDataDom[domain][2 + m_noPeriodicCellData * cell] = c_z_rot;
32151 c_y = c_y_rot;
32152 c_z = c_z_rot;
32153
32154 z_min_1 = -6.3137515147 * c_y + 1462.750302935;
32155 z_min_2 = -0.1583844403 * c_y + 231.6768880649;
32156
32157 if((c_z >= (z_min_2 - eps_) && c_z <= (z_min_1 + eps_) && c_y <= m_rotAxisCoord[0])
32158 || rot_counter == 2 // && c_z> 200.0
32159 ) {
32160 rotated = true;
32161 }
32162 } while(!rotated);
32163 }
32164 } else if(m_periodicCells == 2 || m_periodicCells == 3) {
32165 eps_ = 0.0;
32166 if(c_x < x_mid) {
32167 rot_counter++;
32168 c_x_rot = periodic_coord[1] - (periodic_coord[0] - c_x);
32169 c_y_rot = c_y;
32170 c_z_rot = c_z;
32171 m_periodicCellDataDom[domain][0 + m_noPeriodicCellData * cell] = c_x_rot;
32172 c_x = c_x_rot;
32173 } else {
32174 rot_counter++;
32175 c_x_rot = (c_x - periodic_coord[1]) + periodic_coord[0];
32176 c_y_rot = c_y;
32177 c_z_rot = c_z;
32178 m_periodicCellDataDom[domain][0 + m_noPeriodicCellData * cell] = c_x_rot;
32179 c_x = c_x_rot;
32180 }
32181 }
32182
32183 if((c_x >= xmin && c_x <= xmax) && (c_y >= ymin) && (c_y <= ymax) && (c_z >= zmin) && (c_z <= zmax)) {
32184 distance = -1.1111;
32185 Point<3> pt(c_x, c_y, c_z);
32186 MInt cI = tree.nearest(pt, distance);
32187 MFloat delta_x = fabs(a_coordinate(cI, 0) - c_x - eps_);
32188 MFloat delta_y = fabs(a_coordinate(cI, 1) - c_y);
32189 MFloat delta_z = fabs(a_coordinate(cI, 2) - c_z);
32190
32191 halfLength = c_cellLengthAtLevel(a_level(cI) + 1);
32192
32193 if(distance < 0.0) {
32194 mTerm(1, AT_, "negative distance");
32195 }
32196 if(delta_x <= halfLength && delta_y <= halfLength && delta_z <= halfLength && distance >= 0.0) {
32197 found = true;
32198 m_periodicCellDataDom[domain][3 + m_noPeriodicCellData * cell] = cI; // store cellId to copy from
32199 m_periodicCellDataDom[domain][4 + m_noPeriodicCellData * cell] =
32200 m_periodicCellDataDom[domain][4 + m_noPeriodicCellData * cell] * rot_counter; // store number of rotations
32201
32202 if(rot_counter > 2 || rot_counter < -2) {
32203 // cout << "ROT_COUNTER " << m_periodicCellDataDom[domain][4+5*cell] << " y_rot "
32204 //<< c_y_rot << " z_rot" <<c_z_rot<<endl;
32205 }
32206 count_found++;
32207 } else if((delta_x > halfLength || delta_y > halfLength || delta_z > halfLength)
32208 && distance <= 8.0 * halfLength) {
32209 counter_ = 0;
32210 counter_ = getAdjacentLeafCells<2, false>(cI, 1, nghbrList_, layerId_);
32211
32212 for(MInt k = 0; k < counter_; k++) {
32213 MInt nghbr_Id = nghbrList_[k];
32214 if(nghbr_Id < 0) {
32215 continue;
32216 }
32217 if(!a_hasProperty(nghbr_Id, SolverCell::IsOnCurrentMGLevel)) {
32218 continue;
32219 }
32220 if(a_isBndryGhostCell(nghbr_Id)) {
32221 continue;
32222 }
32223 if(a_isHalo(nghbr_Id)) {
32224 continue;
32225 }
32226 if(c_noChildren(nghbr_Id) != 0) {
32227 continue;
32228 }
32229 delta_x = fabs(a_coordinate(nghbr_Id, 0) - c_x - eps_);
32230 delta_y = fabs(a_coordinate(nghbr_Id, 1) - c_y);
32231 delta_z = fabs(a_coordinate(nghbr_Id, 2) - c_z);
32232
32233
32234 halfLength = c_cellLengthAtLevel(a_level(nghbr_Id) + 1);
32235 if(delta_x <= halfLength && delta_y <= halfLength && delta_z <= halfLength) {
32236 found = true;
32237 m_periodicCellDataDom[domain][3 + m_noPeriodicCellData * cell] = nghbr_Id; // store cellId to copy from
32238 m_periodicCellDataDom[domain][4 + m_noPeriodicCellData * cell] =
32239 m_periodicCellDataDom[domain][4 + m_noPeriodicCellData * cell]
32240 * rot_counter; // store number of rotations
32241
32242 if(rot_counter > 2 || rot_counter < -2) {
32243 // cout << "ROT_COUNTER " <<
32244 // m_periodicCellDataDom[domain][4+5*cell] << " y_rot "
32245 // << c_y_rot << " z_rot" <<c_z_rot<<endl;
32246 }
32247 count_found++;
32248 break;
32249 }
32250 }
32251 }
32252 }
32253 if(!found) {
32254 m_periodicCellDataDom[domain][3 + m_noPeriodicCellData * cell] = -1;
32255 m_periodicCellDataDom[domain][4 + m_noPeriodicCellData * cell] =
32256 m_periodicCellDataDom[domain][4 + m_noPeriodicCellData * cell] * rot_counter; // store number of rotations
32257 if(noDomains() == 1) {
32258 cout << "nothing found: " << domainId() << " cx: " << c_x << " cy: " << c_y << " cz: " << c_z
32259 << " cx_r: " << c_x << " cy_r: " << c_y << " cz_r: " << c_z << endl;
32260 mTerm(1, AT_, "NOTHING FOUND");
32261 }
32262 }
32263 }
32264 }
32265
32266
32267 // correct cell coordinates back
32268 m_fvBndryCnd->rerecorrectCellCoordinates();
32269
32270
32271 MPI_Status status;
32272
32273 // array with information how many cells data to send/receive to/from wich domain
32274 m_noPerCellsToSend = new MInt[noDomains()];
32275 m_noPerCellsToReceive = new MInt[noDomains()];
32276
32277
32278 for(MInt dom = 0; dom < noDomains(); dom++) {
32279 m_noPerCellsToSend[dom] = 0;
32280 for(MInt c = 0; c < m_noPeriodicCellsDom[dom]; c++) {
32281 if(m_periodicCellDataDom[dom][3 + m_noPeriodicCellData * c] >= 0) {
32282 m_noPerCellsToSend[dom] = m_noPerCellsToSend[dom] + 1;
32283 }
32284 }
32285 }
32286
32287 m_noPerCellsToReceive[domainId()] = m_noPerCellsToSend[domainId()];
32288
32289 for(MInt dom = 0; dom < noDomains(); dom++) {
32290 // cout<< "DOMAIN; " << domainId() << " has to send " << m_noPerCellsToSend[dom] << " to
32291 // Domain " << dom << endl;
32292 }
32293
32294
32295 // exchange information how many cell data to send/receive
32296
32297 for(MInt snd = 0; snd < domainId(); snd++) {
32298 MPI_Recv(&m_noPerCellsToReceive[snd], 1, MPI_INT, snd, 0, mpiComm(), &status, AT_, "m_noPerCellsToReceive[snd]");
32299 }
32300 for(MInt rcv = 0; rcv < noDomains(); rcv++) {
32301 if(rcv != domainId()) {
32302 MPI_Send(&m_noPerCellsToSend[rcv], 1, MPI_INT, rcv, 0, mpiComm(), AT_, "m_noPerCellsToSend[rcv]");
32303 }
32304 }
32305
32306 if(domainId() < noDomains() - 1) {
32307 for(MInt snd = domainId() + 1; snd < noDomains(); snd++) {
32308 MPI_Recv(&m_noPerCellsToReceive[snd], 1, MPI_INT, snd, 0, mpiComm(), &status, AT_, "m_noPerCellsToReceive[snd]");
32309 }
32310 }
32311
32312
32313 for(MInt dom = 0; dom < noDomains(); dom++) {
32314 // cout<< "DOMAIN; " << domainId() << " has to receive " << m_noPerCellsToReceive[dom] << "
32315 // from Domain " << dom << endl;
32316 }
32317
32318
32319 m_log << "*************************" << endl;
32320 m_log << "AllocateMemory 2" << endl;
32321 m_log << "*************************" << endl;
32322
32323
32324 // memory for storage of conservative variables + sortedId + cellId to copy from
32325 m_periodicDataToSend = new MFloat*[noDomains()];
32326
32327 m_noPeriodicCellData = PV->noVariables;
32328 m_noPeriodicData = m_noPeriodicCellData + 2;
32329
32330
32331 // RANS Azimuthal
32332 for(MInt dom = 0; dom < noDomains(); dom++) {
32333 m_periodicDataToSend[dom] = new MFloat[m_noPerCellsToSend[dom] * m_noPeriodicData];
32334 }
32335
32336 // memory for storage of received cell data
32337 m_periodicDataToReceive = new MFloat*[noDomains()];
32338
32339 for(MInt dom = 0; dom < noDomains(); dom++) {
32340 m_periodicDataToReceive[dom] = new MFloat[m_noPerCellsToReceive[dom] * m_noPeriodicData];
32341 }
32342
32343 MInt counting;
32344
32345 for(MInt dom = 0; dom < noDomains(); dom++) {
32346 counting = 0;
32347 for(MInt c = 0; c < m_noPeriodicCellsDom[dom]; c++) {
32348 if(m_periodicCellDataDom[dom][3 + m_noPeriodicCellData * c] >= 0) { // ACHTUNG int -- float conversion
32349
32350 m_periodicDataToSend[dom][5 + counting * m_noPeriodicData] = c;
32351 m_periodicDataToSend[dom][6 + counting * m_noPeriodicData] =
32352 m_periodicCellDataDom[dom][3 + m_noPeriodicCellData * c];
32353 counting++;
32354 }
32355 }
32356 }
32357
32358 m_log << "*************************" << endl;
32359 m_log << "Connectivity Matrix created" << endl;
32360 m_log << "*************************" << endl;
32361}
32362
32363// === Azimuthal periodic concept ends ========================================
32364
32365// check cells
32366template <MInt nDim_, class SysEqn>
32368 TRACE();
32369
32370 IF_CONSTEXPR(nDim == 2)
32371 mTerm(1, "By now only used in 3D. If you want to use it in 2D,"
32372 " just remove this warning.");
32373
32374 MBool bndNghbr;
32375 // MBool invalidCells = false;
32376 MBool noNghbr;
32377 MInt nghbrId;
32378 MInt noCells = noInternalCells();
32379 //---
32380
32381 for(MInt id = 0; id < noCells; id++) {
32382 // edit claudia: do not reset property 8 (cell is valid) here!
32383 // invalid cells may also be detected during boundary cell preprocessing - this information
32384 // should not be lost!
32385 bndNghbr = false;
32386 noNghbr = false;
32387 if(a_bndryId(id) == -1) {
32388 for(MInt dir = 0; dir < m_noDirs; dir++) {
32389 if(a_hasNeighbor(id, dir) > 0) {
32390 nghbrId = c_neighborId(id, dir);
32391 if(a_bndryId(nghbrId) > -1) {
32392 bndNghbr = true;
32393 }
32394 } else {
32395 if(c_parentId(id) == -1) {
32396 noNghbr = true;
32397 } else if(a_hasNeighbor(c_parentId(id), dir) == 0) {
32398 noNghbr = true;
32399 }
32400 }
32401 }
32402 if(noNghbr && bndNghbr && !a_isPeriodic(id) && !a_hasProperty(id, SolverCell::IsCutOff)
32403 && !a_hasProperty(id, SolverCell::IsNotGradient) && c_noChildren(id) == 0) {
32404 a_hasProperty(id, SolverCell::IsInvalid) = true;
32405 // invalidCells = true;
32406 m_log << id << " is invalid";
32407 for(MInt spaceId = 0; spaceId < nDim; spaceId++)
32408 m_log << " " << a_coordinate(id, spaceId);
32409 m_log << endl;
32410 m_log << a_isInterface(id) << " " << a_isPeriodic(id) << " " << a_hasProperty(id, SolverCell::IsCutOff) << endl;
32411 for(MInt dir = 0; dir < m_noDirs; dir++) {
32412 if(a_hasNeighbor(id, dir) > 0) {
32413 m_log << "direction " << dir << " " << c_neighborId(id, dir) << " " << a_bndryId(c_neighborId(id, dir))
32414 << endl;
32415 }
32416 }
32417 a_variable(id, CV->RHO) = 2.0;
32418 }
32419 }
32420 }
32421 // if( invalidCells ) {
32422 // saveSolverSolution(1);
32423 // mTerm(1,AT_, "Invalid cells found, see log file for details - writing
32424 // output file");
32425 //
32426 // }
32427}
32428
32429//-----------------------------------------------------------------------------
32430
32431
32439template <MInt nDim_, class SysEqn>
32441 TRACE();
32442
32443 MFloat& Strouhal = m_static_crankAngle_Strouhal;
32444 MFloat& initialCad = m_static_crankAngle_initialCad;
32445
32446 if(initialCad < 0) {
32447 Strouhal = Context::getSolverProperty<MFloat>("Strouhal", m_solverId, AT_, &Strouhal);
32448 initialCad = 0;
32449 initialCad = Context::getSolverProperty<MFloat>("initialCrankAngle", m_solverId, AT_, &initialCad);
32450 }
32451
32452 return maia::math::crankAngle(elapsedTime, Strouhal, initialCad, mode);
32453}
32454
32455//---------------------------------------------------------------------------
32456
32457template <MInt nDim_, class SysEqn>
32459 IF_CONSTEXPR(nDim == 3) { mTerm(1, "Only available in 2D."); }
32460 else {
32461 computeSamplingTimeStep_();
32462 }
32463}
32464
32471template <MInt nDim_, class SysEqn>
32473 TRACE();
32474
32475 if(m_timeStepMethod != 17511 && !m_combustion) {
32476 mTerm(1, AT_,
32477 "this function should only be called with timeStepMethod 17511 "
32478 "and combustion enabled");
32479 }
32480
32481 if(!m_combustion) {
32482 stringstream errorMessage;
32483 errorMessage << "ERROR: combustion is turned off, this time step method is especially written "
32484 "for combustion cases ... exiting";
32485 mTerm(1, AT_, errorMessage.str());
32486 }
32487
32488 MInt bcSpId;
32489 MFloat cycleTime, sampleTime; //,sample;
32490 // MFloat inletTubeAreaRatio = 2.002/0.412;
32491 const MFloat slOverU = m_flameSpeed / m_MaFlameTube;
32492 const MFloat Lf = m_realRadiusFlameTube * tan(acos(slOverU)); // nominal flame length
32493 MFloat Af = F2 * sqrt(POW2(Lf) + POW2(m_realRadiusFlameTube));
32494 const MFloat slantLength = Af * F1B2; // slant flame length (2D)
32495 const MFloat rLaminarFlameThickness = 1. / m_laminarFlameThickness;
32496 MFloat rFlameSpeed = 1. / m_flameSpeed;
32497 MFloat DInfinityFlameTube = SUTHERLANDLAW(m_temperatureFlameTube);
32498 MFloat ReFl = m_rPr * rLaminarFlameThickness * DInfinityFlameTube * m_MaFlameTube
32499 * rFlameSpeed;
32501 MFloat sigma = m_subfilterVariance * c_cellLengthAtLevel(maxRefinementLevel());
32502 MFloat flameStr = -1.0;
32503 // MFloat calcMarksteinLength = 1./ReFl*m_rPr*1./m_flameSpeed* DInfinityFlameTube; ///<
32504 // calculated Markstein length referred to the flame properties MFloat calcMarksteinLengthTR
32505 // = 1./ReFl*1./(F2*m_realRadiusFlameTube)*m_rPr*1./m_flameSpeed*DInfinityFlameTube; ///<
32506 // calculated Markstein length referred to the flame properties and the flame tube radius
32507 //---
32508
32509 // compute the cycle time and the cycle
32510 cycleTime = (F2 * PI) / m_flameStrouhal;
32511 sampleTime = cycleTime / m_samplesPerCycle;
32512
32513 m_log << endl;
32514 m_log << "*****************************" << endl;
32515 m_log << "2D Flame test case properties" << endl;
32516 m_log << "*****************************" << endl << endl;
32517 m_log << "flame tube radius (used for levelSet BC): " << m_radiusFlameTube << endl;
32518 m_log << "flame tube real radius: " << m_realRadiusFlameTube << endl;
32519 m_log << "nominal flame length L_f: " << Lf << endl;
32520 m_log << "nominal slant flame length: " << slantLength << endl;
32521 m_log << "nominal flame surface area: " << Af << endl;
32522 m_log << "uncurved flame tip angle in Grad: " << atan(m_realRadiusFlameTube / Lf) * 180. / PI << endl;
32523 m_log << "laminar flame speed: " << m_flameSpeed << endl;
32524 m_log << "laminar flame thickness: " << m_laminarFlameThickness << endl;
32525 m_log << "subfilter variance sigma: " << sigma << endl;
32526 m_log << "******************************" << endl;
32527 m_log << "Corrugated Flamelet regime:" << endl;
32528 m_log << "lf < l_kolmogorov -> Ka_F < 1" << endl;
32529 m_log << "******************************" << endl;
32530 if(domainId() == 0) {
32531 cerr << "*****************************" << endl;
32532 cerr << "2D Flame test case properties" << endl;
32533 cerr << "*****************************" << endl << endl;
32534 cerr << "flame tube radius (used for levelSet BC): " << m_radiusFlameTube << endl;
32535 cerr << "flame tube real radius: " << m_realRadiusFlameTube << endl;
32536 cerr << "nominal flame length L_f: " << Lf << endl;
32537 cerr << "nominal slant flame length: " << slantLength << endl;
32538 cerr << "nominal flame surface area: " << Af << endl;
32539 cerr << "uncurved flame tip angle in Grad: " << atan(m_realRadiusFlameTube / Lf) * 180. / PI << endl;
32540 cerr << "laminar flame speed: " << m_flameSpeed << endl;
32541 cerr << "laminar flame thickness: " << m_laminarFlameThickness << endl;
32542 cerr << "subfilter variance sigma: " << sigma << endl;
32543 }
32544
32545 if((m_subfilterVariance < m_laminarFlameThickness)) {
32546 m_log << "+Case 1: sigma (=filter size) < laminar flame thickness" << endl;
32547 m_log << " *Conclusion: flame is resolved -> filtered flame thickness = laminar flame thickness" << endl;
32548 m_log << " *Conclusion: no turbulent contribution" << endl;
32549 m_log << " *Info: filtered flame speed s_F = s_l laminar flame speed" << endl;
32550 m_log << " *Info: Dth_turb,F (subfilter eddy diffusivity) = Dth_lam (laminar diffusivity) " << endl;
32551 } else {
32552 m_log << "+Case 2: sigma (=filter size) > laminar flame thickness" << endl;
32553 m_log << " *Conclusion: sub-filter flame front wrinkling increases the resolved burning velocity" << endl;
32554 m_log << " *Conclusion: filtered flame speed s_F > s_l (laminar flame speed)" << endl;
32555 m_log << " *Info: if the flame front is not altered by turbulence," << endl;
32556 m_log << " the chemical time scale of the turbulent flame time_c_F" << endl;
32557 m_log << " remains the same as the laminar one time_c" << endl;
32558 }
32559 m_log << endl;
32560 m_log << "mach number inlet: " << m_Ma << endl;
32561 m_log << "mach number in flame tube: " << m_MaFlameTube << endl;
32562 m_log << "Re (ref. to stagnation point): " << sysEqn().m_Re0 << endl;
32563 m_log << "Re (ref. to infinity values): " << m_Re << endl;
32564 m_log << "Re (ref. to the flame properties): " << ReFl << endl;
32565 if((ReFl < (m_Re - 10.0)) || (ReFl > (m_Re + 10.0))) {
32566 if(domainId() == 0) {
32567 cerr << "Warning: Your Reynolds number should be Re= " << ReFl << " , but it is chosen to Re= " << m_Re << endl;
32568 }
32569 m_log << "Warning: Your Reynolds number should be Re= " << ReFl << " , but it is chosen to Re= " << m_Re << endl;
32570 }
32571 m_log << "Re (ref. to the flame properties and to the flame tube diameter): " << ReFl * F2 * m_realRadiusFlameTube
32572 << endl;
32573 m_log << "markstein length (controls the flame curvature): " << m_marksteinLength << endl;
32574 /*
32575if((calcMarksteinLength < (m_marksteinLength - 0.002)) || (calcMarksteinLength >
32576(calcMarksteinLength + 0.002)) ) { cerr << "Instability Warning: Markstein number should be
32577marksteinLength= " << calcMarksteinLength << " , but it is chosen to marksteinLength= " <<
32578m_marksteinLength << endl; m_log << "Instability Warning: Markstein number should be
32579marksteinLength= " << calcMarksteinLength << " , but it is chosen to marksteinLength= " <<
32580m_marksteinLength << endl;
32581}
32582 */
32583 m_log << "CFL number: " << m_cfl << endl;
32584 m_log << "smallest Cell distance according to max refinement Level: " << c_cellLengthAtLevel(maxRefinementLevel())
32585 << endl;
32586 m_log.precision(16);
32587 m_log << "reference time (=u_0): " << m_timeRef << endl;
32588 m_log << "time step according to the CFL condition: " << timeStep(true) * m_timeRef << endl;
32589 m_log.precision(9);
32590
32591 m_log << "cycleTime (nondim): " << cycleTime << endl;
32592 m_log << "sampleTime (nondim): " << sampleTime << endl;
32593 if(m_structuredFlameOutput || m_forcing) {
32594 m_noTimeStepsBetweenSamples = 0;
32595 for(MInt n = 1; n < 10000000; n++) {
32596 if(sampleTime / (MFloat)(n) < timeStep(true)) {
32597 forceTimeStep(sampleTime / (MFloat)(n));
32598 m_noTimeStepsBetweenSamples = n;
32599 break;
32600 }
32601 }
32602 sampleTime = m_noTimeStepsBetweenSamples * timeStep(true);
32603 cycleTime = sampleTime * m_samplesPerCycle;
32604
32605 if(m_noTimeStepsBetweenSamples == 0) {
32606 mTerm(1, AT_, "Time step calculation error");
32607 }
32608
32609 if(m_neutralFlameStrouhal > 0) {
32610 flameStr = m_neutralFlameStrouhal * Lf / (F2 * PI);
32611 if(domainId() == 0) {
32612 cerr << "Be careful, strouhal number is based on length one, not on flame length (for "
32613 "neutral markstein length computation) "
32614 << endl;
32615 cerr << "time step due to sampling (depends on the Strouhal number) (phys): " << timeStep(true) * m_timeRef
32616 << endl;
32617 cerr << "Excitation frequency f = " << m_neutralFlameStrouhal / (F2 * PI) << endl;
32618 cerr << "Excitation frequency f (phys) = " << m_neutralFlameStrouhal / (F2 * PI * m_timeRef) << endl;
32619 cerr << "flame Strouhal number Stf (based on Lf) = " << flameStr << endl;
32620 cerr << "flame Strouhal number Stf (based on Lf phys) = " << flameStr / m_timeRef << endl;
32621 cerr << "check flame Strouhal number Stf = 1/t * Lf / u_mean = " << 1. / cycleTime * Lf << endl;
32622 }
32623 m_log << "time step due to sampling (depends on the Strouhal number) (phys): " << timeStep(true) * m_timeRef
32624 << endl;
32625 m_log << "Excitation frequency f = " << m_neutralFlameStrouhal / (F2 * PI) << endl;
32626 m_log << "Excitation frequency f (phys) = " << m_neutralFlameStrouhal / (F2 * PI * m_timeRef) << endl;
32627 m_log << "flame Strouhal number Stf (based on Lf) = " << flameStr << endl;
32628 m_log << "flame Strouhal number Stf (based on Lf phys) = " << flameStr / m_timeRef << endl;
32629 m_log << "check flame Strouhal number Stf = 1/t * Lf / u_mean= " << 1. / cycleTime * Lf << endl;
32630 if(((flameStr < (1. / cycleTime * Lf - 0.05)) || (flameStr > (1. / cycleTime * Lf + 0.05))) && domainId() == 0) {
32631 cerr << "Warning: Your flame strouhal is = " << flameStr << " , but it is checked to = " << 1. / cycleTime * Lf
32632 << endl;
32633 }
32634 m_log << "wave number (based on length one!!) omega=St/1.0: " << m_flameStrouhal
32635 << endl; // equals neutralFlameStrouhal
32636 m_log << "wave number (based on length one!!) omega=St/1.0 (phys): " << m_flameStrouhal / m_timeRef
32637 << endl; // equals neutralFlameStrouhal
32638 if(domainId() == 0) {
32639 cerr << "wave number (based on length one!!) omega=St/1.0: " << m_flameStrouhal
32640 << endl; // equals neutralFlameStrouhal
32641 cerr << "wave number (based on length one!!) omega=St/1.0 (phys): " << m_flameStrouhal / m_timeRef
32642 << endl; // equals neutralFlameStrouhal
32643 }
32644 } else {
32645 flameStr = m_flameStrouhal / (F2 * PI);
32646 m_log << "time step due to sampling (depends on the Strouhal number) (phys): " << timeStep(true) * m_timeRef
32647 << endl;
32648 m_log << "Excitation frequency f = " << m_strouhal / (F2 * PI) << endl;
32649 m_log << "flame Strouhal number Stf (based on Lf) = " << flameStr << endl;
32650 m_log << "check flame Strouhal number Stf = 1/t * Lf / u_mean = " << 1. / cycleTime * Lf << endl;
32651 m_log << "wave number (based on flame length!!) omega=St/L_f: " << m_flameStrouhal << endl;
32652
32653 if(domainId() == 0) {
32654 cerr << "time step due to sampling (depends on the Strouhal number) (phys): " << timeStep(true) * m_timeRef
32655 << endl;
32656 cerr << "Excitation frequency f = " << m_strouhal / (F2 * PI) << endl;
32657 cerr << "flame Strouhal number Stf (based on Lf) = " << flameStr << endl;
32658 cerr << "check flame Strouhal number Stf = 1/t * Lf / u_mean = " << 1. / cycleTime * Lf << endl;
32659 cerr << "wave number (based on flame length!!) omega=St/L_f: " << m_flameStrouhal << endl;
32660 }
32661 }
32662 }
32663
32664 m_log << "excitation amplitude at the inlet: " << m_forcingAmplitude * m_VInfinity << endl;
32665 m_log << "excitation amplitude in the flame tube: " << m_forcingAmplitude * m_VInfinity * m_inletTubeAreaRatio
32666 << endl;
32667 m_log << "excitation amplitude in the flame tube in % (ref. to the laminar flame speed): "
32668 << m_forcingAmplitude * m_VInfinity * m_inletTubeAreaRatio / m_flameSpeed * 100.0 << " %" << endl;
32669 m_log << "excitation amplitude in the flame tube in % (ref. to inflow velocity): "
32670 << m_forcingAmplitude * m_VInfinity * m_inletTubeAreaRatio * 100.0 << " %" << endl;
32671
32672 if(domainId() == 0) {
32673 cerr << "excitation amplitude at the inlet: " << m_forcingAmplitude * m_VInfinity << endl;
32674 cerr << "excitation amplitude in the flame tube: " << m_forcingAmplitude * m_VInfinity * m_inletTubeAreaRatio
32675 << endl;
32676 cerr << "excitation amplitude in the flame tube in % (ref. to the laminar flame speed): "
32677 << m_forcingAmplitude * m_VInfinity * m_inletTubeAreaRatio / m_flameSpeed * 100.0 << " %" << endl;
32678 cerr << "excitation amplitude in the flame tube in % (ref. to inflow velocity): "
32679 << m_forcingAmplitude * m_inletTubeAreaRatio * 100.0 << " %" << endl;
32680
32681 if(m_samplingStartIteration < 0) {
32682 cerr << "ERROR: set samplingStartIteration to some value" << endl;
32683 }
32684 }
32685 m_samplingStartCycle = (MInt)(m_samplingStartIteration / (m_samplesPerCycle * m_noTimeStepsBetweenSamples));
32686
32687 // if(m_samplesPerCycle *
32688 // m_noTimeStepsBetweenSamples*m_samplingStartCycle<m_samplingStartIteration)
32689 // m_samplingStartCycle += 1;
32690
32691 m_samplingEndCycle = m_samplingStartCycle + m_noSamplingCycles;
32692
32693 if(m_structuredFlameOutput && m_forcing) {
32694 switch(m_structuredFlameOutputLevel) {
32695 default:
32696 m_log << "Warning: structured Output on finest level because unknown "
32697 "structuredFlameOutputLevel"
32698 << endl;
32699 if(domainId() == 0) {
32700 cerr << "Warning: structured Output on finest level because unknown "
32701 "structuredFlameOutputLevel"
32702 << endl;
32703 }
32704 break;
32705 case 0:
32706 if(domainId() == 0) {
32707 cerr << "Warning: structuredFlameOutput is on, but structuredOuputLevel is set to "
32708 << m_structuredFlameOutputLevel << endl;
32709 cerr << "Warning: no structured Output" << endl;
32710 }
32711 m_log << "Warning: structuredFlameOutput is on, but structuredOuputLevel is set to "
32712 << m_structuredFlameOutputLevel << endl;
32713 m_log << "Warning: no structured Output" << endl;
32714 break;
32715 case 1:
32716 m_log << "structured Output for single flame (old version): " << endl;
32717 break;
32718 case 2:
32719 m_log << "structured Output for single flame (optimized version): " << endl;
32720 break;
32721 case 3:
32722 m_log << "structured Output for single flame with plenum (optimized version): " << endl;
32723 break;
32724 case 4:
32725 m_log << "structured Output for single flame with plenum, ascii output of whole domain "
32726 "(optimized version): "
32727 << endl;
32728 break;
32729 case 40:
32730 m_log << "structured Output for single flame with plenum, ascii output of whole domain + "
32731 "dPdT source tem (optimized version): "
32732 << endl;
32733 break;
32734 case 5:
32735 m_log << "unstructured Output for single flame, netcdf output of whole domain: " << endl;
32736 break;
32737 }
32738 m_log << "cycleTime (nondim, adapted): " << cycleTime << endl;
32739 m_log << "sampleTime (nondim, adapted): " << sampleTime << endl;
32740 m_log << "number of timesteps between samples: " << m_noTimeStepsBetweenSamples << endl;
32741 m_log << "sampling Start cycle: " << m_samplingStartCycle << endl;
32742 m_log << " start flameSurfaceArea - Output at Iteration: "
32743 << m_samplingStartCycle * m_samplesPerCycle * m_noTimeStepsBetweenSamples << endl;
32744 m_log << " end flameSurfaceArea - Output at Iteration: "
32745 << m_samplingEndCycle * m_samplesPerCycle * m_noTimeStepsBetweenSamples << endl;
32746
32747 if(domainId() == 0) {
32748 cerr << "cycleTime (nondim): " << cycleTime << endl;
32749 cerr << "sampleTime (nondim): " << sampleTime << endl;
32750 cerr << "number of timesteps between samples: " << m_noTimeStepsBetweenSamples << endl;
32751 cerr << "sampling Start cycle: " << m_samplingStartCycle << endl;
32752 cerr << " start flameSurfaceArea - Output at Iteration: "
32753 << m_samplingStartCycle * m_samplesPerCycle * m_noTimeStepsBetweenSamples << endl;
32754 cerr << " end flameSurfaceArea - Output at Iteration: "
32755 << m_samplingEndCycle * m_samplesPerCycle * m_noTimeStepsBetweenSamples << endl;
32756 }
32757
32758 if((g_timeSteps + m_restartTimeStep) < m_samplingEndCycle * m_samplesPerCycle * m_noTimeStepsBetweenSamples) {
32759 if(!m_forceNoTimeSteps) {
32760 m_log << "WARNING: timeSteps changed from : " << g_timeSteps;
32761 if(domainId() == 0) {
32762 cerr << "WARNING: timeSteps changed from : " << g_timeSteps;
32763 }
32764 g_timeSteps = m_samplingEndCycle * m_samplesPerCycle * m_noTimeStepsBetweenSamples + 5000 - m_restartTimeStep;
32765 if(domainId() == 0) {
32766 cerr << " to " << g_timeSteps << endl;
32767 }
32768 m_log << " to " << g_timeSteps << endl;
32769 }
32770 } else {
32771 m_log << "WARNING: timeSteps are NOT adapted to the required number of time steps (used "
32772 "for reference testcases)";
32773 if(domainId() == 0) {
32774 cerr << "WARNING: timeSteps are NOT adapted to the required number of time steps (used for "
32775 "reference testcases)";
32776 }
32777 }
32778
32779 } else {
32780 if(m_structuredFlameOutput && !m_forcing) {
32781 if(domainId() == 0) {
32782 cerr << "Warning: Forcing ist turned off, but structuredFlameOutput is on" << endl;
32783 }
32784 m_log << "Warning: Forcing ist turned off, but structuredFlameOutput is on" << endl;
32785 switch(m_structuredFlameOutputLevel) {
32786 default:
32787 m_log << "Warning: structured Output on finest level because unknown "
32788 "structuredFlameOutputLevel"
32789 << endl;
32790 if(domainId() == 0) {
32791 cerr << "Warning: structured Output on finest level because unknown "
32792 "structuredFlameOutputLevel"
32793 << endl;
32794 }
32795 break;
32796 case 0:
32797 if(domainId() == 0) {
32798 cerr << "Warning: structuredFlameOutput is on, but structuredOuputLevel is set to "
32799 << m_structuredFlameOutputLevel << endl;
32800 cerr << "Warning: no structured Output" << endl;
32801 }
32802 m_log << "Warning: structuredFlameOutput is on, but structuredOuputLevel is set to "
32803 << m_structuredFlameOutputLevel << endl;
32804 m_log << "Warning: no structured Output" << endl;
32805 break;
32806 case 1:
32807 m_log << "structured Output for single flame (old version): " << endl;
32808 break;
32809 case 2:
32810 m_log << "structured Output for single flame (optimized version): " << endl;
32811 break;
32812 case 3:
32813 m_log << "structured Output for single flame with plenum (optimized version): " << endl;
32814 break;
32815 case 4:
32816 m_log << "structured Output for single flame, ascii output of whole domain (optimized "
32817 "version): "
32818 << endl;
32819 break;
32820 case 40:
32821 m_log << "structured Output for single flame with plenum, ascii output of whole domain "
32822 "+ dPdT source tem (optimized version): "
32823 << endl;
32824 break;
32825 case 5:
32826 m_log << "unstructured Output for single flame, netcdf output of whole domain: " << endl;
32827 break;
32828 }
32829 m_log << "cycleTime: " << cycleTime << endl;
32830 m_log << "sampleTime: " << sampleTime << endl;
32831 m_log << "number of timesteps between samples: " << m_noTimeStepsBetweenSamples << endl;
32832 m_log << "sampling Start cycle: " << m_samplingStartCycle << endl;
32833 m_log << " start flameSurfaceArea - Output at Iteration: "
32834 << m_samplingStartCycle * m_samplesPerCycle * m_noTimeStepsBetweenSamples << endl;
32835
32836 if(m_noTimeStepsBetweenSamples == -1) {
32837 mTerm(1, AT_,
32838 "Error no time steps between samples is not calculated, prbably wron "
32839 "structuredFlameOutput");
32840 }
32841 if(domainId() == 0) {
32842 cerr << "cycleTime: " << cycleTime << endl;
32843 cerr << "sampleTime: " << sampleTime << endl;
32844 cerr << "number of timesteps between samples: " << m_noTimeStepsBetweenSamples << endl;
32845 cerr << "sampling Start cycle: " << m_samplingStartCycle << endl;
32846 cerr << " start flameSurfaceArea - Output at Iteration: "
32847 << m_samplingStartCycle * m_samplesPerCycle * m_noTimeStepsBetweenSamples << endl;
32848 }
32849 } else {
32850 if(!m_structuredFlameOutput && m_forcing) {
32851 if(domainId() == 0) {
32852 cerr << "Warning: Forcing ist turned on, but structuredFlameOutput is off" << endl;
32853 cerr << "Warning: There will be no structured Output and no flameSurfaceArea - Output" << endl;
32854 }
32855 m_log << "Warning: Forcing ist turned on, but structuredFlameOutput is off" << endl;
32856 m_log << "Warning: There will be no structured Output and no flameSurfaceArea - Output" << endl;
32857
32858 } else {
32859 m_log << "no structured Output, structuredFlameOutput= " << m_structuredFlameOutput << endl;
32860 }
32861 }
32862 }
32863 for(MInt bcId = 0; bcId < m_noSpongeBndryCndIds; bcId++) {
32864 bcSpId = m_spongeBndryCndIds[bcId];
32865 // calculate time dependent sigma sponge
32866 if(m_spongeTimeDependent[bcId]) {
32867 m_log << endl;
32868 m_log << "*************************************************************" << endl;
32869 m_log << "Additional Information for time dependent sponge boundary Id: " << bcSpId << endl;
32870 m_log << "*************************************************************" << endl;
32871 m_log << "sponge end iteration= " << m_spongeEndIteration[bcId] << endl;
32872 m_log << "sigma_max(t=" << m_spongeEndIteration[bcId] << ") = "
32873 << m_sigmaSpongeBndryId[bcId] / tanh(F1)
32874 * (tanh(F1
32875 - (m_spongeEndIteration[bcId] - m_spongeStartIteration[bcId])
32876 / (m_spongeEndIteration[bcId] - m_spongeStartIteration[bcId])))
32877 << endl;
32878 m_log << "sponge end time = " << m_spongeEndIteration[bcId] * (timeStep(true) * m_timeRef) << endl << endl;
32879 // m_sigmaSpongeBndryId[bcId] = m_sigmaSpongeBndryId[bcId]*(F1-tanh(
32880 // F4*m_time/m_spongeEndTime[bcId]));
32881 }
32882 }
32883 if(m_forcing && approx(flameStr, -1.0, MFloatEps)) {
32884 mTerm(1, AT_, "Error flame strouhal number based on Lf not determined");
32885 }
32886 if(domainId() == 0) {
32887 FILE* datei;
32888 datei = fopen("flameLog", "a+");
32889 fprintf(datei, " %-10.10f", sampleTime);
32890 fprintf(datei, " %-10.10f", m_realRadiusFlameTube);
32891 fprintf(datei, " %-10.10f", m_flameSpeed);
32892 fprintf(datei, " %-10.10f", m_MaFlameTube);
32893 fprintf(datei, " %-10.10f", m_timeRef);
32894 fprintf(datei, " %-10.10f", flameStr);
32895 fprintf(datei, " %-10.10f", m_forcingAmplitude);
32896 fprintf(datei, " %-10.10f", m_rhoFlameTube);
32897 fprintf(datei, " %-10.10f", m_Ma);
32898 fprintf(datei, " %d", m_samplingStartCycle);
32899 fprintf(datei, " %d", m_samplingEndCycle);
32900 fprintf(datei, " %d", (MInt)m_samplesPerCycle);
32901 fprintf(datei, " %-10.10f", m_marksteinLength);
32902 fprintf(datei, " %-10.10f", m_laminarFlameThickness);
32903 fprintf(datei, " %-10.10f", ReFl);
32904 fprintf(datei, " %-10.10f", m_burntUnburntTemperatureRatio);
32905 fprintf(datei, " %-10.10f", m_flameStrouhal);
32906 fprintf(datei, "\n");
32907 fclose(datei);
32908 }
32909}
32910
32911// -----------------------------------------------------------
32912
32922template <MInt nDim_, class SysEqn>
32924 IF_CONSTEXPR(nDim == 3) mTerm(1, "Not available in 3D.");
32925 TRACE();
32926 if(!m_divergenceTreatment) {
32927 viscousFlux();
32928 return;
32929 }
32930 constexpr MInt index0[2] = {1, 0};
32931 const MInt noPVars = PV->noVariables;
32932 const MInt noData = m_surfaceVarMemory;
32933 const MInt noSurfaces = a_noSurfaces();
32934 const MInt slopeMemory = m_slopeMemory;
32935 const MFloat gammaMinusOne = m_gamma - 1.0;
32936 const MFloat FgammaMinusOne = F1 / gammaMinusOne;
32937 const MFloat gFGMO = m_gamma * FgammaMinusOne;
32938 MInt* nghbrs = (MInt*)(&(a_surfaceNghbrCellId(0, 0)));
32939 MFloatScratchSpace tau(nDim, AT_, "tau");
32940 MFloat* area = &a_surfaceArea(0);
32941 MFloat* slope = (MFloat*)(&(a_slope(0, 0, 0)));
32942 MFloat* var = (MFloat*)(&(a_surfaceVariable(0, 0, 0)));
32943 // --- end of initialization
32944
32945 // assuming m_TInfinity is the temperature of the unburnt gas
32946 // Dth = mue^u / ( rho^u *Pr ) = const, rhoU = m_rhoInfinity (density of the unburnt gas)
32947
32948 // changed: because gives solution independent from rhoInfinity which is useful if rhoInfinity is
32949 // changing at a thermal inlet boundary condition
32950 const MFloat rhoUDth = sysEqn().m_muInfinity * m_rPr; // = m_DthInfinity * m_rhoInfinity;
32951
32952 for(MInt srfcId = 0; srfcId < noSurfaces; srfcId++) {
32953 // calculate the primitve variables on the surface u,v,rho,p
32954 // LR
32955 const MInt i = srfcId * noData;
32956 const MFloat u = F1B2 * (var[i] + var[i + noPVars]);
32957 const MFloat v = F1B2 * (var[i + 1] + var[i + noPVars + 1]);
32958 const MFloat rho = F1B2 * (var[i + 2] + var[i + noPVars + 2]);
32959 const MFloat Frho = F1 / rho;
32960 const MFloat p = F1B2 * (var[i + 3] + var[i + noPVars + 3]);
32961
32962 // compute the temperature on the surface p = rho * T * 1.0/gamma
32963 const MFloat T = sysEqn().temperature_ES(rho, p);
32964
32965 // indices for the orientation
32966 const MInt id0 = a_surfaceOrientation(srfcId);
32967 const MInt id1 = index0[id0];
32968
32969 // Compute A / Re0
32970 const MFloat dAOverRe0 = area[srfcId] * m_rRe0;
32971
32972 // calculate the viscosity with the sutherland law mue = T^3/2 * (1+S/T_0)(T + S/T_0)
32973 const MFloat mue = SUTHERLANDLAW(T);
32974 // calculate the thermal conductivity
32975 const MFloat lambda = m_rPr * mue;
32976
32977 // calculate the heat flux (T_x = gamma*(p_x/rho - p/rho^2 * rho_x))
32978 const MFloat q =
32979 lambda * gFGMO * Frho
32980 * ((a_surfaceFactor(srfcId, 0) * slope[nghbrs[2 * srfcId] * slopeMemory + PV->P * nDim + id0]
32981 + a_surfaceFactor(srfcId, 1) * slope[nghbrs[2 * srfcId + 1] * slopeMemory + PV->P * nDim + id0])
32982 - p * Frho
32983 * (a_surfaceFactor(srfcId, 0) * slope[nghbrs[2 * srfcId] * slopeMemory + PV->RHO * nDim + id0]
32984 + a_surfaceFactor(srfcId, 1) * slope[nghbrs[2 * srfcId + 1] * slopeMemory + PV->RHO * nDim + id0]));
32985
32986 //------------------------------------------------------------------------
32987 // tau_ij:
32988 // (matrix entries
32989 // stored in tau[ ? ]: id0,id1,id2
32990 //
32991 // { 0 1 2 } 0 1 2 -> u*tau[0]+v*tau[1]+w*tau[3]
32992 // { 0 1 2 } 1 2 0 -> u*tau[0]+v*tau[1]+w*tau[2]
32993 // { 0 1 2 } 2 0 1 -> u*tau[0]+v*tau[1]+w*tau[2]
32994
32995 if(m_divergenceTreatment) {
32996 if(a_surfaceCoordinate(srfcId, 1) < 0.0341) {
32997 tau.p[id0] =
32998 mue
32999 * (a_surfaceFactor(srfcId, 0) * (F2 * slope[nghbrs[2 * srfcId] * slopeMemory + id0 * nDim + id0])
33000 + a_surfaceFactor(srfcId, 1) * (F2 * slope[nghbrs[2 * srfcId + 1] * slopeMemory + id0 * nDim + id0]));
33001
33002 tau.p[id1] = mue
33003 * (a_surfaceFactor(srfcId, 0)
33004 * (slope[nghbrs[2 * srfcId] * slopeMemory + id0 * nDim + id1]
33005 + slope[nghbrs[2 * srfcId] * slopeMemory + id1 * nDim + id0])
33006 + a_surfaceFactor(srfcId, 1)
33007 * (slope[nghbrs[2 * srfcId + 1] * slopeMemory + id0 * nDim + id1]
33008 + slope[nghbrs[2 * srfcId + 1] * slopeMemory + id1 * nDim + id0]));
33009
33010 } else {
33011 // Compute the stress terms
33012 tau.p[id0] = mue
33013 * (a_surfaceFactor(srfcId, 0)
33014 * (F4B3 * slope[nghbrs[2 * srfcId] * slopeMemory + id0 * nDim + id0]
33015 - F2B3 * (slope[nghbrs[2 * srfcId] * slopeMemory + id1 * nDim + id1]))
33016 + a_surfaceFactor(srfcId, 1)
33017 * (F4B3 * slope[nghbrs[2 * srfcId + 1] * slopeMemory + id0 * nDim + id0]
33018 - F2B3 * (slope[nghbrs[2 * srfcId + 1] * slopeMemory + id1 * nDim + id1])));
33019
33020 tau.p[id1] = mue
33021 * (a_surfaceFactor(srfcId, 0)
33022 * (slope[nghbrs[2 * srfcId] * slopeMemory + id0 * nDim + id1]
33023 + slope[nghbrs[2 * srfcId] * slopeMemory + id1 * nDim + id0])
33024 + a_surfaceFactor(srfcId, 1)
33025 * (slope[nghbrs[2 * srfcId + 1] * slopeMemory + id0 * nDim + id1]
33026 + slope[nghbrs[2 * srfcId + 1] * slopeMemory + id1 * nDim + id0]));
33027 }
33028 } else {
33029 // Compute the stress terms
33030 tau.p[id0] = mue
33031 * (a_surfaceFactor(srfcId, 0)
33032 * (F4B3 * slope[nghbrs[2 * srfcId] * slopeMemory + id0 * nDim + id0]
33033 - F2B3 * (slope[nghbrs[2 * srfcId] * slopeMemory + id1 * nDim + id1]))
33034 + a_surfaceFactor(srfcId, 1)
33035 * (F4B3 * slope[nghbrs[2 * srfcId + 1] * slopeMemory + id0 * nDim + id0]
33036 - F2B3 * (slope[nghbrs[2 * srfcId + 1] * slopeMemory + id1 * nDim + id1])));
33037
33038 tau.p[id1] = mue
33039 * (a_surfaceFactor(srfcId, 0)
33040 * (slope[nghbrs[2 * srfcId] * slopeMemory + id0 * nDim + id1]
33041 + slope[nghbrs[2 * srfcId] * slopeMemory + id1 * nDim + id0])
33042 + a_surfaceFactor(srfcId, 1)
33043 * (slope[nghbrs[2 * srfcId + 1] * slopeMemory + id0 * nDim + id1]
33044 + slope[nghbrs[2 * srfcId + 1] * slopeMemory + id1 * nDim + id0]));
33045 }
33046 /*
33047 if( !(dAOverRe0 <=0) && !(dAOverRe0 >=0) ) {
33048 cerr << "dAOverRe0" << dAOverRe0 << endl;
33049 saveSolverSolution(1);
33050 mTerm(1, AT_);
33051 }
33052 */
33053
33054 // Compute the fluxes
33055 a_surfaceFlux(srfcId, FV->RHO_U) -= dAOverRe0 * tau.p[0];
33056 a_surfaceFlux(srfcId, FV->RHO_V) -= dAOverRe0 * tau.p[1];
33057 IF_CONSTEXPR(hasE<SysEqn>)
33058 a_surfaceFlux(srfcId, FV->RHO_E) -= dAOverRe0 * (u * tau.p[0] + v * tau.p[1] + q);
33059
33060 // progress variable
33061 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
33062 a_surfaceFlux(srfcId, FV->RHO_C) -=
33063 dAOverRe0 * rhoUDth
33064 * (a_surfaceFactor(srfcId, 0) * slope[nghbrs[2 * srfcId] * slopeMemory + PV->C * nDim + id0]
33065 + a_surfaceFactor(srfcId, 1) * slope[nghbrs[2 * srfcId + 1] * slopeMemory + PV->C * nDim + id0]);
33066 }
33067}
33068
33075template <MInt nDim_, class SysEqn>
33077 IF_CONSTEXPR(nDim == 3) mTerm(1, "Not available in 3D.");
33078 TRACE();
33079
33080 MInt id0, id1, i;
33081 MInt index0[2] = {1, 0};
33082 const MInt noPVars = PV->noVariables;
33083 const MInt noData = m_surfaceVarMemory;
33084 const MInt noSurfaces = a_noSurfaces();
33085 const MInt slopeMemory = m_slopeMemory;
33086 MFloat T, u, v;
33087 MFloat q, mue, lambda;
33088 MFloat dAOverRe0;
33089 const MFloat gammaMinusOne = m_gamma - 1.0;
33090 const MFloat FgammaMinusOne = F1 / gammaMinusOne;
33091 const MFloat gFGMO = m_gamma * FgammaMinusOne;
33092 MFloat Frho, rho, p;
33093 MFloat rhoUDth;
33094 MInt* nghbrs = (MInt*)(&(a_surfaceNghbrCellId(0, 0)));
33095 MFloatScratchSpace tau(nDim, AT_, "tau");
33096 MFloat* area = &a_surfaceArea(0);
33097 MFloat* slope = (MFloat*)(&(a_slope(0, 0, 0)));
33098 MFloat* var = (MFloat*)(&(a_surfaceVariable(0, 0, 0)));
33099 // --- end of initialization
33100
33101 // assuming m_TInfinity is the temperature of the unburnt gas
33102 // Dth = mue^u / ( rho^u *Pr ) = const, rhoU = m_rhoInfinity (density of the unburnt gas)
33103 rhoUDth = m_DthInfinity * m_rhoFlameTube;
33104
33105 for(MInt srfcId = 0; srfcId < noSurfaces; srfcId++) {
33106 // calculate the primitve variables on the surface u,v,rho,p
33107 // LR
33108 i = srfcId * noData;
33109 u = F1B2 * (var[i] + var[i + noPVars]);
33110 v = F1B2 * (var[i + 1] + var[i + noPVars + 1]);
33111 rho = F1B2 * (var[i + 2] + var[i + noPVars + 2]);
33112 Frho = F1 / rho;
33113 p = F1B2 * (var[i + 3] + var[i + noPVars + 3]);
33114
33115 // compute the temperature on the surface p = rho * T * 1.0/gamma
33116 T = sysEqn().temperature_ES(rho, p);
33117
33118 // indices for the orientation
33119 id0 = a_surfaceOrientation(srfcId);
33120 id1 = index0[id0];
33121
33122 // Compute A / Re0
33123 dAOverRe0 = area[srfcId] * m_rRe0;
33124
33125 // calculate the viscosity with the sutherland law mue = T^3/2 * (1+S/T_0)(T + S/T_0)
33126 mue = SUTHERLANDLAW(T);
33127 // calculate the thermal conductivity
33128 lambda = m_rPr * mue;
33129
33130 // calculate the heat flux (T_x = gamma*(p_x/rho - p/rho^2 * rho_x))
33131 q = lambda * gFGMO * Frho
33132 * ((a_surfaceFactor(srfcId, 0) * slope[nghbrs[2 * srfcId] * slopeMemory + PV->P * nDim + id0]
33133 + a_surfaceFactor(srfcId, 1) * slope[nghbrs[2 * srfcId + 1] * slopeMemory + PV->P * nDim + id0])
33134 - p * Frho
33135 * (a_surfaceFactor(srfcId, 0) * slope[nghbrs[2 * srfcId] * slopeMemory + PV->RHO * nDim + id0]
33136 + a_surfaceFactor(srfcId, 1) * slope[nghbrs[2 * srfcId + 1] * slopeMemory + PV->RHO * nDim + id0]));
33137
33138 //------------------------------------------------------------------------
33139 // tau_ij:
33140 // (matrix entries
33141 // stored in tau[ ? ]: id0,id1,id2
33142 //
33143 // { 0 1 2 } 0 1 2 -> u*tau[0]+v*tau[1]+w*tau[3]
33144 // { 0 1 2 } 1 2 0 -> u*tau[0]+v*tau[1]+w*tau[2]
33145 // { 0 1 2 } 2 0 1 -> u*tau[0]+v*tau[1]+w*tau[2]
33146
33147 // Compute the stress terms
33148 tau.p[id0] = mue
33149 * (a_surfaceFactor(srfcId, 0)
33150 * (F4B3 * slope[nghbrs[2 * srfcId] * slopeMemory + id0 * nDim + id0]
33151 - F2B3 * (slope[nghbrs[2 * srfcId] * slopeMemory + id1 * nDim + id1]))
33152 + a_surfaceFactor(srfcId, 1)
33153 * (F4B3 * slope[nghbrs[2 * srfcId + 1] * slopeMemory + id0 * nDim + id0]
33154 - F2B3 * (slope[nghbrs[2 * srfcId + 1] * slopeMemory + id1 * nDim + id1])));
33155
33156 tau.p[id1] = mue
33157 * (a_surfaceFactor(srfcId, 0)
33158 * (slope[nghbrs[2 * srfcId] * slopeMemory + id0 * nDim + id1]
33159 + slope[nghbrs[2 * srfcId] * slopeMemory + id1 * nDim + id0])
33160 + a_surfaceFactor(srfcId, 1)
33161 * (slope[nghbrs[2 * srfcId + 1] * slopeMemory + id0 * nDim + id1]
33162 + slope[nghbrs[2 * srfcId + 1] * slopeMemory + id1 * nDim + id0]));
33163
33164 // Compute the fluxes
33165 a_surfaceFlux(srfcId, FV->RHO_U) -= dAOverRe0 * tau.p[0];
33166 a_surfaceFlux(srfcId, FV->RHO_V) -= dAOverRe0 * tau.p[1];
33167 IF_CONSTEXPR(hasE<SysEqn>)
33168 a_surfaceFlux(srfcId, FV->RHO_E) -= dAOverRe0 * (u * tau.p[0] + v * tau.p[1] + q);
33169
33170 // progress variable
33171 IF_CONSTEXPR(hasPV_C<SysEqn>::value)
33172 a_surfaceFlux(srfcId, FV->RHO_C) -=
33173 dAOverRe0 * rhoUDth
33174 * (a_surfaceFactor(srfcId, 0) * slope[nghbrs[2 * srfcId] * slopeMemory + PV->C * nDim + id0]
33175 + a_surfaceFactor(srfcId, 1) * slope[nghbrs[2 * srfcId + 1] * slopeMemory + PV->C * nDim + id0]);
33176 }
33177}
33178
33179// ------------------------------------------------------------------------------------------
33180
33181template <MInt nDim_, class SysEqn>
33183 TRACE();
33184
33185 IF_CONSTEXPR(nDim == 3) mTerm(-1, "Info: untested in 3D. By now only used in 2D.");
33186
33187 // filter the conservative variables
33188 // MBool coarseInterface0,coarseInterface1,coarseInterface2,coarseInterface3;
33189 // MBool fineOrNoInterface0,fineOrNoInterface1,fineOrNoInterface2,fineOrNoInterface3;
33190 // MBool filter0,filter1;
33191 //---
33192
33193 // remove the u component
33194 if(m_force1DFiltering) {
33195 for(MInt id = 0; id < m_noActiveCells; id++) {
33196 const MInt cellId = m_activeCellIds[id];
33197 a_variable(cellId, 0) = F0;
33198 }
33199 }
33200
33201 // new
33202 for(MInt id = 0; id < m_noActiveCells; id++) {
33203 const MInt cellId = m_activeCellIds[id];
33204 // select parents
33205 if(c_noChildren(cellId) == 0) {
33206 continue;
33207 }
33208 MBool grandparent = false;
33209 for(MInt ch = 0; ch < IPOW2(nDim); ch++) {
33210 if(c_childId(cellId, ch) == -1) {
33211 continue;
33212 }
33213 if(c_noChildren(c_childId(cellId, ch)) > 0) {
33214 grandparent = true;
33215 break;
33216 }
33217 }
33218 if(grandparent) {
33219 continue;
33220 }
33221 // filter
33222 for(MInt varId = 0; varId < CV->noVariables; varId++) {
33223 a_variable(cellId, varId) = F0;
33224 }
33225 for(MInt ch = 0; ch < IPOW2(nDim); ch++) {
33226 if(c_childId(cellId, ch) == -1) {
33227 continue;
33228 }
33229 for(MInt varId = 0; varId < CV->noVariables; varId++) {
33230 a_variable(cellId, varId) += a_variable(c_childId(cellId, ch), varId);
33231 }
33232 }
33233 for(MInt varId = 0; varId < CV->noVariables; varId++) {
33234 a_variable(cellId, varId) /= (MFloat)c_noChildren(cellId);
33235 }
33236 // copy the filtered variables to the child cells
33237 for(MInt ch = 0; ch < IPOW2(nDim); ch++) {
33238 if(c_childId(cellId, ch) == -1) {
33239 continue;
33240 }
33241 for(MInt varId = 0; varId < CV->noVariables; varId++) {
33242 a_variable(c_childId(cellId, ch), varId) =
33243 F1B2 * (a_variable(c_childId(cellId, ch), varId) + a_variable(cellId, varId));
33244 }
33245 }
33246 }
33247
33248 /*
33249
33250 // copy all CV to &a_pvariable(0,0)for( MInt id = 0; id < m_noActiveCells; id++ ) {
33251 cellId = m_activeCellIds[ id ];
33252 for( MInt var=0; var<CV->noVariables; var++ ) {
33253 a_pvariable( cellId , var ) = a_variable( cellId , var );
33254 }
33255 }
33256
33257 for( MInt id = 0; id < m_noActiveCells; id++ ) {
33258 cellId = m_activeCellIds[ id ];
33259 filter0 = false;
33260 filter1 = false;
33261 // check if coarser or finer grid in the -x-direction
33262 coarseInterface0 = false;
33263 fineOrNoInterface0 = false;
33264 if( a_hasNeighbor( cellId , 0 ) == 0 ) {
33265 if( c_parentId( cellId ) > -1 ) {
33266 if( a_hasNeighbor( c_parentId( cellId ) , 0 ) > 0 )
33267 coarseInterface0 = true;
33268 else
33269 fineOrNoInterface0 = true;
33270 } else
33271 fineOrNoInterface0 = true;
33272 } else {
33273 if( c_noChildren( c_neighborId( cellId , 0 ) ) > 0 )
33274 fineOrNoInterface0 = true;
33275 }
33276 // check if coarser or finer grid in the +x-direction
33277 coarseInterface1 = false;
33278 fineOrNoInterface1 = false;
33279 if( a_hasNeighbor( cellId , 1 ) == 0 ) {
33280 if( c_parentId( cellId ) > -1 ) {
33281 if( a_hasNeighbor( c_parentId( cellId ) , 1 ) > 0 )
33282 coarseInterface1 = true;
33283 else
33284 fineOrNoInterface1 = true;
33285 } else
33286 fineOrNoInterface1 = true;
33287 } else {
33288 if( c_noChildren( c_neighborId( cellId , 1 ) ) > 0 )
33289 fineOrNoInterface1 = true;
33290 }
33291 // check if coarser or finer grid in the -y-direction
33292 coarseInterface2 = false;
33293 fineOrNoInterface2 = false;
33294 if( a_hasNeighbor( cellId , 2 ) == 0 ) {
33295 if( c_parentId( cellId ) > -1 ) {
33296 if( a_hasNeighbor( c_parentId( cellId ) , 2 ) > 0 )
33297 coarseInterface2 = true;
33298 else
33299 fineOrNoInterface2 = true;
33300 } else
33301 fineOrNoInterface2 = true;
33302 } else {
33303 if( c_noChildren( c_neighborId( cellId , 2 ) ) > 0 )
33304 fineOrNoInterface2 = true;
33305 }
33306 // check if coarser or finer grid in the +y-direction
33307 coarseInterface3 = false;
33308 fineOrNoInterface3 = false;
33309 if( a_hasNeighbor( cellId , 3 ) == 0 ) {
33310 if( c_parentId( cellId ) > -1 ) {
33311 if( a_hasNeighbor( c_parentId( cellId ) , 3 ) > 0 )
33312 coarseInterface3 = true;
33313 else
33314 fineOrNoInterface3 = true;
33315 } else
33316 fineOrNoInterface3 = true;
33317 } else {
33318 if( c_noChildren( c_neighborId( cellId , 3 ) ) > 0 )
33319 fineOrNoInterface3 = true;
33320 }
33321
33322 if( !fineOrNoInterface0 && !fineOrNoInterface1 && !fineOrNoInterface2 && !fineOrNoInterface3 ) {
33323 if( ( coarseInterface0 || coarseInterface1 ) &&
33324 !( coarseInterface2 || coarseInterface3 ) )
33325 filter1 = true;
33326 if( !( coarseInterface0 || coarseInterface1 ) &&
33327 ( coarseInterface2 || coarseInterface3 ) )
33328 filter0 = true;
33329 }
33330
33331 if( filter0 ) {
33332 for( MInt var=0; var<CV->noVariables; var++ ) {
33333 a_variable( cellId , var ) *= F1B2;
33334 a_variable( cellId , var ) += F1B4 *
33335 (a_pvariable( c_neighborId( cellId , 0 ) , var ) +
33336 a_pvariable( c_neighborId( cellId , 1 ) , var ) );
33337 }
33338 } else {
33339 if( filter1 ) {
33340 for( MInt var=0; var<CV->noVariables; var++ ) {
33341 a_variable( cellId , var ) *= F1B2;
33342 a_variable( cellId , var ) += F1B4 *
33343 (a_pvariable( c_neighborId( cellId , 2 ) , var ) +
33344 a_pvariable( c_neighborId( cellId , 3 ) , var ) );
33345 }
33346 }
33347 }
33348 }
33349*/
33350}
33351
33352
33356template <MInt nDim_, class SysEqn>
33358 TRACE();
33359
33360 // only relevant for fvmb!
33361 std::ignore = mode;
33362
33363 // init property IsInvalid - cell is invalid (MGC)
33364 // init property IsPeriodicWithRot - periodic cell (azimuthal periodicity concept)
33365 // will be set false during initSolutionStep if necessary
33366 // cannot be done in setCellProperties as that routine is called more than once
33367 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
33368 a_hasProperty(cellId, SolverCell::IsInvalid) = false;
33369 a_hasProperty(cellId, SolverCell::IsPeriodicWithRot) = false;
33370 }
33371
33372 grid().updateGridInfo();
33373
33374 setCellProperties();
33375
33376 // NOTE: this is/can be a major time consumer during init/DLB
33377 generateBndryCells();
33378
33379 IF_CONSTEXPR(nDim == 3) {
33380 if(m_fvBndryCnd->m_multipleGhostCells) {
33381 // shiftHaloAndSplitCells(); //commented out since otherwise split cells are written out as
33382 // regular cells, while no mechanisms exists to detect these cells upon restart. Thus multiple
33383 // cells at the same location will appear, each of which will then be split again into new
33384 // cells, and so forth... Also domainOffsets needs to be updated correspondingly. (Lennart)
33385 }
33386
33387 // deactivates wrong cells when periodic bc is used (azimuthal periodicity concept)
33388 if(m_periodicCells == 0) {
33389 checkCells();
33390 }
33391 }
33392
33393 // shift cell center of boundary cells
33394 m_fvBndryCnd->correctCellCoordinates();
33395
33396 // MULTILEVEL
33397 // correct (xyz)cc and body surfaces of coarse boundary cells
33398 // requires that small and master cells are not yet merged!
33399 // for MGC formulation, this does not provide the correct result!
33400 // do not use multilevel with MGC formulation
33401 m_fvBndryCnd->correctCoarseBndryCells();
33402
33403 IF_CONSTEXPR(nDim == 3) {
33404 // identifies cells to copy PV from (using kd tree, azimuthal periodicity concept)
33405 // m_periodicCells=1 --> azimuthal periodicity (with LS interpolation)
33406 // m_periodicCells=2 --> special case: periodicity in x-direction (without LS interpolation)
33407 // m_periodicCells=3 --> special case: periodicity in x-direction (without LS interpolation +
33408 // volume forcing)
33409 if(m_periodicCells == 1 || m_periodicCells == 2 || m_periodicCells == 3) identPeriodicCells();
33410
33411 // set the neighbor arrays storeNghbrIds, identNghbrIds
33412 if(m_fvBndryCnd->m_multipleGhostCells) findNghbrIdsMGC();
33413 }
33414
33415 if(m_fvBndryCnd->m_cellMerging) {
33416 // detects small cells and identifies a master cell for each
33417 // merges master and small cell(s)
33418 IF_CONSTEXPR(nDim == 2) {
33419 m_fvBndryCnd->detectSmallBndryCells();
33420 m_log << "Connecting master and slave cells...";
33421 m_fvBndryCnd->mergeCells();
33422 }
33423 else IF_CONSTEXPR(nDim == 3) {
33424 if(m_fvBndryCnd->m_multipleGhostCells)
33425 m_fvBndryCnd->detectSmallBndryCellsMGC();
33426 else
33427 m_fvBndryCnd->detectSmallBndryCells();
33428 m_log << "Connecting master and slave cells...";
33429
33430 if(m_fvBndryCnd->m_multipleGhostCells)
33431 m_fvBndryCnd->mergeCellsMGC();
33432 else
33433 m_fvBndryCnd->mergeCells();
33434 }
33435 m_log << " found " << m_fvBndryCnd->m_smallBndryCells->size() << "small cells." << endl;
33436 } else {
33437 // flux-redistribution method
33438 m_fvBndryCnd->setBCTypes();
33439 computeCellVolumes();
33440 m_fvBndryCnd->setNearBoundaryRecNghbrs();
33441 m_fvBndryCnd->computeImagePointRecConst();
33442 if(m_fvBndryCnd->m_smallCellRHSCorrection) {
33443 m_fvBndryCnd->initSmallCellRHSCorrection();
33444 } else {
33445 m_fvBndryCnd->initSmallCellCorrection();
33446 }
33447 }
33448
33449 // write out centerline data
33450 if(m_writeOutData) {
33451 cerr << "Writing out center line and boundary data" << endl;
33452 applyInitialCondition();
33453 writeCenterLineVel();
33454 mTerm(0, AT_);
33455 }
33456
33457 // set the neighbor arrays storeNghbrIds, identNghbrIds
33458 IF_CONSTEXPR(nDim == 2) { findNghbrIds(); }
33459 else IF_CONSTEXPR(nDim == 3) {
33460 if(!m_fvBndryCnd->m_multipleGhostCells) findNghbrIds();
33461 }
33462
33463 m_log << "Creating surfaces...";
33464 // create surfaces
33465 m_bndryCellSurfacesOffset = a_noSurfaces();
33466 IF_CONSTEXPR(nDim == 2) {
33467 checkForSrfcsMGC(); // small cell must already be extracted
33468 }
33469 else IF_CONSTEXPR(nDim == 3) {
33470 if(m_fvBndryCnd->m_multipleGhostCells)
33471 checkForSrfcsMGC_2(); // small cell must already be extracted
33472 else
33473 checkForSrfcsMGC();
33474 }
33475
33476 // correct all surfaces which were built between two boundary cells
33477 m_fvBndryCnd->correctMasterSlaveSurfaces();
33478 m_log << "ok" << endl;
33479
33480
33481 // adds one ghost cell for each boundary cell
33482 m_log << "Creating ghost cells...";
33483 m_bndryGhostCellsOffset = a_noCells();
33484 IF_CONSTEXPR(nDim == 2) { m_fvBndryCnd->computeGhostCells(); }
33485 else IF_CONSTEXPR(nDim == 3) {
33486 if(m_fvBndryCnd->m_multipleGhostCells)
33487 m_fvBndryCnd->computeGhostCellsMGC();
33488 else
33489 m_fvBndryCnd->computeGhostCells();
33490 }
33491 m_log << "ok" << endl;
33492
33493 // update the cell properties
33494 setCellProperties();
33495
33496 IF_CONSTEXPR(nDim == 2) {
33497 m_log << "Setting the neighbor arrays...";
33498 // set the neighbor arrays storeNghbrIds, identNghbrIds
33499 findNghbrIds();
33500 m_log << "ok" << endl;
33501 }
33502 else IF_CONSTEXPR(nDim == 3) {
33503 if(!m_fvBndryCnd->m_multipleGhostCells) {
33504 m_log << "Setting the neighbor arrays...";
33505 // set the neighbor arrays storeNghbrIds, identNghbrIds
33506 findNghbrIds();
33507 m_log << "ok" << endl;
33508 }
33509 }
33510
33511 // creates boundary surfaces
33512 // requires ghost and small cells
33513 m_log << "Adding body surfaces...";
33514 m_bndrySurfacesOffset = a_noSurfaces();
33515 IF_CONSTEXPR(nDim == 2) { m_fvBndryCnd->addBoundarySurfaces(); }
33516 else IF_CONSTEXPR(nDim == 3) {
33517 if(m_fvBndryCnd->m_multipleGhostCells) {
33518 m_fvBndryCnd->addBoundarySurfacesMGC();
33519 } else {
33520 m_fvBndryCnd->addBoundarySurfaces();
33521 // adds a correction part the boundary surface on interface boundary cells
33522 correctBoundarySurfaces();
33523 m_fvBndryCnd->addBoundarySurfaces();
33524 }
33525 }
33526
33527 m_log << "ok" << endl;
33528 m_log << " *** All surfaces created" << endl;
33529
33530 m_log << "Tagging cells needed for the surface flux computation...";
33531 tagCellsNeededForSurfaceFlux();
33532 m_log << "ok" << endl;
33533
33534 // second part of the initialisation of the manual limiter
33535 if(string2enum(m_surfaceValueReconstruction) == HOCD_LIMITED_SLOPES_MAN) initComputeSurfaceValuesLimitedSlopesMan2();
33536
33537 m_log << "Fill nghbrInterface...";
33538 setNghbrInterface();
33539 m_log << "ok" << endl;
33540
33541 m_log << "Filling cell surface mapping...";
33542 cellSurfaceMapping();
33543 m_log << "ok" << endl;
33544
33545 m_log << "Setting upwind coefficient...";
33546 setUpwindCoefficient();
33547 m_log << "ok" << endl;
33548
33549
33550 m_log << "Computing plane vectors...";
33551 m_fvBndryCnd->computePlaneVectors();
33552 m_log << "ok" << endl;
33553
33554
33555 m_log << "Initializing the least-squares reconstruction...";
33556 // builds the least-squares stencil and computes the LS constants
33557 // MGC stencil works bad for refined grids. More research necessary!
33558 buildLeastSquaresStencilSimple();
33559 m_log << "ok" << endl;
33560
33561
33562 m_log << "Initializing the viscous flux computation...";
33563 initViscousFluxComputation();
33564 m_log << "ok" << endl;
33565
33566 if(grid().azimuthalPeriodicity()) {
33567 initAzimuthalReconstruction();
33568 computeAzimuthalReconstructionConstants();
33569 }
33570
33571 m_log << "Initializing boundary conditions...";
33572 // initialize the reconstruction scheme for the boundary and ghost cells
33573 m_fvBndryCnd->initBndryCnds();
33574
33575 initCutOffBoundaryCondition();
33576
33577 IF_CONSTEXPR(nDim == 3) {
33578 if(m_fvBndryCnd->m_multipleGhostCells) m_fvBndryCnd->computeReconstructionConstants_interpolation();
33579 }
33580 m_log << "ok" << endl;
33581
33582 m_log << "Computing reconstruction constants...";
33583 // Computes the reconstruction constants for each cell
33584 if(m_fvBndryCnd->m_cellMerging)
33585 computeReconstructionConstants();
33586 else
33587 computeReconstructionConstantsSVD();
33588 m_log << "ok" << std::endl;
33589
33590 IF_CONSTEXPR(nDim == 3) {
33591 // computes reconstruction constants for LS reconstruction (azimuthal periodicity concept)
33592 if(m_periodicCells == 1) computeRecConstPeriodic();
33593 }
33594
33595 if(m_checkCellSurfaces) checkCellSurfaces();
33596
33597 // compute dx between surfaces and their neighbor cells
33598 computeCellSurfaceDistanceVectors();
33599
33600
33601 // multigrid: set all taus to zero
33602 // deleteTau();
33603
33604
33605 // compute all volumes of the cells inside the integration domain
33606 computeCellVolumes();
33607
33608 // Add cut-cell information to grid file if enabled in properties
33609 if(m_writeCutCellsToGridFile) {
33610 m_log << "Writing cut cells to grid file...";
33611 m_fvBndryCnd->recorrectCellCoordinates();
33612 writeCutCellsToGridFile();
33613 m_fvBndryCnd->rerecorrectCellCoordinates();
33614 m_log << "ok" << endl;
33615 }
33616
33617 // count internal master cells
33618 MInt countFMC = 0;
33619 MInt smallCell;
33620 for(MInt smallId = 0; smallId < m_fvBndryCnd->m_smallBndryCells->size(); smallId++) {
33621 smallCell = m_fvBndryCnd->m_smallBndryCells->a[smallId];
33622 if(a_bndryId(m_fvBndryCnd->m_bndryCells->a[smallCell].m_linkedCellId) == -1) {
33623 countFMC++;
33624 }
33625 }
33626 MLong smallCells = m_fvBndryCnd->m_smallBndryCells->size();
33627 MPI_Allreduce(MPI_IN_PLACE, &smallCells, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE", "smallCells");
33628
33629 checkGhostCellIntegrity();
33630
33631 // @felix cellMaterialNo needs to be updated in size to be equal to the total number of cells
33632 // including all bndry/ghost/... cells, else this the code will access the memory after the
33633 // currently allocated array, which will lead to segmentation faults in certain cases (i.e. due to
33634 // values of some other allocated variable
33635 // !=0 in memory) / ansgar
33636 IF_CONSTEXPR(nDim == 3) { updateMaterialNo(); }
33637
33638 // Reset interpolation data structures used for sampling data
33639 m_cellInterpolationIndex.resize(a_noCells());
33640 std::fill(m_cellInterpolationIndex.begin(), m_cellInterpolationIndex.end(), -1);
33641 m_cellInterpolationMatrix.clear();
33642 m_cellInterpolationIds.clear();
33643
33644 if(m_wmLES) {
33645 if(m_restart) {
33646 restartWMSurfaces();
33647 }
33648 initWMExchange();
33649 exchangeWMVars();
33650
33651 if(m_wmSurfaceProbeInterval > 0) {
33652 initWMSurfaceProbes();
33653 }
33654 }
33655
33656 if(m_saSrfcProbeInterval > 0) {
33657 initSpanAvgSrfcProbes();
33658 }
33659
33660 if(m_wallNormalOutput && m_normalOutputInterval) {
33661 computeWallNormalPointCoords();
33662 findWallNormalCellIds();
33663 }
33664
33665 if(m_useSandpaperTrip) {
33666 initSandpaperTrip();
33667 }
33668
33669 if(m_useChannelForce) {
33670 initChannelForce();
33671 }
33672 if(m_isEEGas) {
33673 // Set implicit coefficient to zero
33674 resetImplicitCoefficients();
33675 }
33676
33677 // if ( m_restart ) m_restart = false;
33678
33679 m_log << "_________________________________________________________________" << endl << endl;
33680 m_log << "Grid summary at time step " << globalTimeStep << endl;
33681 m_log << "_________________________________________________________________" << endl << endl;
33682 m_log << setfill(' ');
33683 m_log << "number of cells " << setw(7) << a_noCells() << endl;
33684 m_log << "number of surfaces " << setw(7) << a_noSurfaces() << endl;
33685 m_log << "total number of small cells on all process " << setw(7) << smallCells << endl;
33686 m_log << "number of internal master cells " << setw(7) << countFMC << endl;
33687 m_log << "minimum grid level " << setw(7) << minLevel() << endl;
33688 m_log << "maximum grid level " << setw(7) << maxLevel() << endl << endl;
33689 m_log << "level | total no cells | no of leaf cells | ghost cells | bndry cells" << endl;
33690 for(MInt level = maxLevel(); level >= minLevel(); level--) {
33691 MInt total = 0;
33692 MInt leaf = 0;
33693 MInt ghost = 0;
33694 MInt bnd = 0;
33695 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
33696 if(a_isBndryGhostCell(cellId)) {
33697 if(a_level(cellId) == level) {
33698 total++;
33699 leaf++;
33700 ghost++;
33701 }
33702 } else if(a_level(cellId) == level) {
33703 total++;
33704 if(a_hasProperty(cellId, SolverCell::IsSplitClone)) continue;
33705 if(c_isLeafCell(cellId)) {
33706 leaf++;
33707 }
33708 if(a_bndryId(cellId) > -1) {
33709 bnd++;
33710 }
33711 }
33712 }
33713 m_log << setfill(' ');
33714 m_log << setw(3) << level << " " << setw(12) << total << " " << setw(16) << leaf << " " << setw(14) << ghost
33715 << " " << setw(14) << bnd << endl;
33716 }
33717
33718 // check domain boundaries
33719 MFloat maxC[] = {-10000.0, -10000.0, -10000.0};
33720 MFloat minC[] = {10000.0, 10000.0, 10000.0};
33721 for(MInt c = 0; c < noInternalCells(); c++) {
33722 if(!a_hasProperty(c, SolverCell::IsOnCurrentMGLevel)) {
33723 continue;
33724 }
33725 if(a_isHalo(c)) {
33726 continue;
33727 }
33728 if(a_isPeriodic(c)) {
33729 continue;
33730 }
33731 const MFloat cellLength = c_cellLengthAtCell(c);
33732 for(MInt i = 0; i < nDim; i++) {
33733 maxC[i] = mMax(maxC[i], a_coordinate(c, i) + F1B2 * cellLength);
33734 minC[i] = mMin(minC[i], a_coordinate(c, i) - F1B2 * cellLength);
33735 }
33736 }
33737 m_log << "_________________________________________________________________" << endl << endl;
33738
33739 m_log << "Physical domain boundaries: " << endl;
33740 m_log << "min (x,y" << (nDim == 3 ? ",z): (" : "): (") << minC[0] << "," << minC[1];
33741 IF_CONSTEXPR(nDim == 3) m_log << "," << minC[2];
33742 m_log << ")" << endl;
33743 m_log << "max (x,y" << (nDim == 3 ? ",z): (" : "): (") << maxC[0] << "," << maxC[1];
33744 IF_CONSTEXPR(nDim == 3) m_log << "," << maxC[2];
33745 m_log << ")" << endl;
33746
33747 m_log << "_________________________________________________________________" << endl << endl;
33748
33749 m_log << "Process " << domainId() << " finished initialization" << endl;
33750
33751 /*
33752 if( globalTimeStep == m_restartTimeStep ) {
33753 // patch for restart from explicit solution
33754 for( MInt cellId = 0 ; cellId < a_noCells(); cellId++ ) {
33755 for( MInt varId = 0; varId < CV->noVariables; varId ++ ) {
33756 a_dt1Variable( cellId , varId ) =
33757 a_variable( cellId , varId );
33758 a_dt2Variable( cellId , varId ) =
33759 a_variable( cellId , varId );
33760 }
33761 }
33762 }
33763 */
33764}
33765
33766template <MInt nDim_, class SysEqn>
33768 TRACE();
33769
33770 m_log << "Initializing Sandpaper Trip... ";
33771
33772 IF_CONSTEXPR(nDim == 2) {
33773 cerr << "Tripping not implemented for 2D" << endl;
33774 return;
33775 }
33776
33777 IF_CONSTEXPR(nDim == 3) {
33778 m_tripAirfoil = false;
33779
33780 if(Context::propertyExists("tripAirfoil", m_solverId)) {
33781 m_tripAirfoil = Context::getSolverProperty<MBool>("tripAirfoil", m_solverId, AT_, &m_tripAirfoil);
33782 }
33783
33784 m_tripNoTrips = Context::propertyLength("tripDelta1", m_solverId);
33785
33786 mAlloc(m_tripDelta1, m_tripNoTrips, "m_tripDelta1", 1.0, AT_);
33787 mAlloc(m_tripXOrigin, m_tripNoTrips, "m_tripXOrigin", 0.0, AT_);
33788 mAlloc(m_tripXLength, m_tripNoTrips, "m_tripXLength", 4.0, AT_);
33789 mAlloc(m_tripYOrigin, m_tripNoTrips, "m_tripYOrigin", 0.0, AT_);
33790 mAlloc(m_tripYHeight, m_tripNoTrips, "m_tripYHeight", 1.0, AT_);
33791 mAlloc(m_tripCutoffZ, m_tripNoTrips, "m_tripCutoffZ", 1.7, AT_);
33792 mAlloc(m_tripMaxAmpSteady, m_tripNoTrips, "m_tripMaxAmpSteady", 0.0, AT_);
33793 mAlloc(m_tripMaxAmpFluc, m_tripNoTrips, "m_tripMaxAmpFluc", 0.005, AT_);
33794 mAlloc(m_tripDeltaTime, m_tripNoTrips, "m_tripDeltaTime", 4.0, AT_);
33795 mAlloc(m_tripTimeStep, m_tripNoTrips, "m_tripTimeStep", 0, AT_);
33796 mAlloc(m_tripNoCells, m_tripNoTrips, "m_tripNoCells", 0, AT_);
33797 mAlloc(m_tripCellOffset, m_tripNoTrips, "m_tripCellOffset", 0, AT_);
33798
33799 for(MInt i = 0; i < m_tripNoTrips; i++) {
33800 m_tripDelta1[i] = Context::getSolverProperty<MFloat>("tripDelta1", m_solverId, AT_, &m_tripDelta1[i], i);
33801
33802 if(!m_tripAirfoil) {
33803 m_tripXOrigin[i] = Context::getSolverProperty<MFloat>("tripXOrigin", m_solverId, AT_, &m_tripXOrigin[i], i);
33804 if(Context::propertyExists("tripYOrigin", m_solverId)) {
33805 m_tripYOrigin[i] = Context::getSolverProperty<MFloat>("tripYOrigin", m_solverId, AT_, &m_tripYOrigin[i], i);
33806 }
33807 }
33808
33809 MFloat tripX = 4.0;
33810 if(Context::propertyExists("tripXLength", m_solverId)) {
33811 tripX = Context::getSolverProperty<MFloat>("tripXLength", m_solverId, AT_, &tripX);
33812 }
33813 m_tripXLength[i] = m_tripDelta1[i] * tripX;
33814
33815
33816 MFloat tripY = 1.0;
33817 if(Context::propertyExists("tripYHeight", m_solverId)) {
33818 tripY = Context::getSolverProperty<MFloat>("tripYHeight", m_solverId, AT_, &tripY);
33819 }
33820 m_tripYHeight[i] = m_tripDelta1[i] * tripY;
33821
33822 MFloat tripZ = 1.7;
33823 if(Context::propertyExists("tripCutoffZ", m_solverId)) {
33824 tripZ = Context::getSolverProperty<MFloat>("tripCutoffZ", m_solverId, AT_, &tripZ);
33825 }
33826 m_tripCutoffZ[i] = m_tripDelta1[i] * tripZ;
33827
33828 m_tripMaxAmpSteady[i] =
33829 Context::getSolverProperty<MFloat>("tripMaxAmpSteady", m_solverId, AT_, &m_tripMaxAmpSteady[i], i);
33830
33831 m_tripMaxAmpFluc[i] =
33832 Context::getSolverProperty<MFloat>("tripMaxAmpFluc", m_solverId, AT_, &m_tripMaxAmpFluc[i], i);
33833
33834 m_tripNoModes = 100;
33835
33836 MFloat timeCutoff = 4.0;
33837 if(Context::propertyExists("tripDeltaTime", m_solverId)) {
33838 timeCutoff = Context::getSolverProperty<MFloat>("tripDeltaTime", m_solverId, AT_, &timeCutoff);
33839 }
33840 m_tripDeltaTime[i] = timeCutoff * m_tripDelta1[i] / m_UInfinity;
33841 m_tripTimeStep[i] = (MInt)(m_time / m_tripDeltaTime[i]);
33842 }
33843
33844 if(Context::propertyExists("RNGSeed") || Context::propertyExists("seedRNGWithTime"))
33845 mTerm(1, "Properties RNGSeed or seedRNGWithTime not compatible with SandpaperTrip!");
33846 m_tripSeed = 70;
33847 srand(m_tripSeed);
33848 m_tripDomainWidth = 0.0;
33849
33850 m_tripUseRestart = false;
33851 if(Context::propertyExists("tripUseRestart", m_solverId)) {
33852 m_tripUseRestart = Context::getSolverProperty<MBool>("tripUseRestart", m_solverId, AT_, &m_tripUseRestart);
33853 }
33854
33855 if(m_tripAirfoil) {
33856 mAlloc(m_tripAirfoilBndryId, m_tripNoTrips, "m_tripAirfoilBndryId", 0, AT_);
33857 mAlloc(m_tripAirfoilSide, m_tripNoTrips, "m_tripAirfoilSide", 0, AT_);
33858 mAlloc(m_tripAirfoilChordPos, m_tripNoTrips, "m_tripAirfoilChordPos", 0.0, AT_);
33859 mAlloc(m_tripAirfoilNosePos, nDim, "m_tripAirfoilNoisePos", 0.0, AT_);
33860 mAlloc(m_tripAirfoilForceDir, nDim * m_tripNoTrips, "m_tripAirfoilForceDir", 0.0, AT_);
33861
33862 m_tripAirfoilChordLength =
33863 Context::getSolverProperty<MFloat>("tripAirfoilChordLength", m_solverId, AT_, &m_tripAirfoilChordLength);
33864 m_tripAirfoilAOA = Context::getSolverProperty<MFloat>("tripAirfoilAOA", m_solverId, AT_, &m_tripAirfoilAOA);
33865 for(MInt dim = 0; dim < nDim; dim++) {
33866 m_tripAirfoilNosePos[dim] =
33867 Context::getSolverProperty<MFloat>("tripAirfoilNosePos", m_solverId, AT_, &m_tripAirfoilNosePos[dim], dim);
33868 }
33869 for(MInt i = 0; i < m_tripNoTrips; i++) {
33870 m_tripAirfoilBndryId[i] =
33871 Context::getSolverProperty<MInt>("tripAirfoilBndryId", m_solverId, AT_, &m_tripAirfoilBndryId[i], i);
33872 m_tripAirfoilSide[i] =
33873 Context::getSolverProperty<MInt>("tripAirfoilSide", m_solverId, AT_, &m_tripAirfoilSide[i], i);
33874 m_tripAirfoilChordPos[i] =
33875 Context::getSolverProperty<MFloat>("tripAirfoilChordPos", m_solverId, AT_, &m_tripAirfoilChordPos[i], i);
33876 if(m_tripAirfoilChordPos[i] < 0.0 || m_tripAirfoilChordPos[i] > 1.0)
33877 mTerm(-1, "tripAirfoilChordPos not within the allowed range of 0.0 to 1.0");
33878 }
33879 }
33880
33881 // find cells that belong to the trip zone
33882 for(MInt i = 0; i < m_tripNoTrips; i++) {
33883 if(m_tripAirfoil) {
33884 // finds the center of the tripping region on the airfoil surface with respect to a specified chord position and
33885 // angle of attack get x-position within the domain find bndryCells with minimum distance to the x-position to
33886 // define the x-y center of the tripping region
33887 MInt avgWeight = 0;
33888 for(MInt bCellId = 0; bCellId < m_fvBndryCnd->m_bndryCells->size(); bCellId++) {
33889 MInt bc = m_tripAirfoilBndryId[i];
33890 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bCellId].m_cellId;
33891 MFloat eta = (a_coordinate(cellId, 0) - m_tripAirfoilNosePos[0]) * cos(m_tripAirfoilAOA * PI / 180.0)
33892 - (a_coordinate(cellId, 1) - m_tripAirfoilNosePos[1]) * sin(m_tripAirfoilAOA * PI / 180.0);
33893 MFloat zeta = (a_coordinate(cellId, 0) - m_tripAirfoilNosePos[0]) * sin(m_tripAirfoilAOA * PI / 180.0)
33894 + (a_coordinate(cellId, 1) - m_tripAirfoilNosePos[1]) * cos(m_tripAirfoilAOA * PI / 180.0);
33895 MFloat dEta = abs(eta - (m_tripAirfoilChordPos[i] * m_tripAirfoilChordLength));
33896 if(dEta <= 0.5 * c_cellLengthAtLevel(maxRefinementLevel())) {
33897 if((m_tripAirfoilSide[i] > 0 && zeta > 0.0) || (m_tripAirfoilSide[i] < 0 && zeta < 0.0)) {
33898 for(MInt srfc = 0; srfc < m_fvBndryCnd->m_bndryCells->a[bCellId].m_noSrfcs; srfc++) {
33899 // find the normal vector of the surface to determine the force direction
33900 // this is ambiguous if the cell has multiple surfaces with the same bc, I dont have a better solution
33901 // yet
33902 if(m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcs[srfc]->m_bndryCndId == bc) {
33903 for(MInt dim = 0; dim < nDim; dim++) {
33904 m_tripAirfoilForceDir[i * nDim + dim] =
33905 m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcs[srfc]->m_normalVector[dim];
33906 m_tripXOrigin[i] = m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcs[srfc]->m_coordinates[0];
33907 m_tripYOrigin[i] = m_fvBndryCnd->m_bndryCells->a[bCellId].m_srfcs[srfc]->m_coordinates[1];
33908 }
33909 avgWeight = 1;
33910 break;
33911 }
33912 }
33913 break;
33914 }
33915 }
33916 }
33917 // weights are summed to avoid incorporating domains which do not contain any tripping cells into the averaging
33918 MPI_Allreduce(&avgWeight, &avgWeight, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "avgWeight", "avgWeight");
33919 MPI_Allreduce(&m_tripXOrigin[i], &m_tripXOrigin[i], 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "m_tripXOrigin",
33920 "m_tripXOrigin");
33921 MPI_Allreduce(&m_tripYOrigin[i], &m_tripYOrigin[i], 1, MPI_DOUBLE, MPI_SUM, mpiComm(), AT_, "m_tripYOrigin",
33922 "m_tripYOrigin");
33923 for(MInt dim = 0; dim < nDim; dim++) {
33924 MPI_Allreduce(&m_tripAirfoilForceDir[i * nDim + dim], &m_tripAirfoilForceDir[i * nDim + dim], 1, MPI_DOUBLE,
33925 MPI_SUM, mpiComm(), AT_, "m_tripAirfoilForceDir", "m_tripAirfoilForceDir");
33926 m_tripAirfoilForceDir[i * nDim + dim] /= avgWeight;
33927 }
33928 m_tripXOrigin[i] /= avgWeight;
33929 m_tripYOrigin[i] /= avgWeight;
33930
33931 if(avgWeight > 0) {
33932 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
33933 MFloat maxR2 = POW2(2 * m_tripXLength[i]) + POW2(2 * m_tripYHeight[i]);
33934 MFloat cellR2 =
33935 POW2(a_coordinate(cellId, 0) - m_tripXOrigin[i]) + POW2(a_coordinate(cellId, 1) - m_tripYOrigin[i]);
33936 if(cellR2 < maxR2) {
33937 m_tripCellIds.push_back(cellId);
33938 m_tripCoords.push_back(a_coordinate(cellId, 2));
33939 a_isSandpaperTripCell(cellId) = true;
33940 }
33941 }
33942 }
33943 m_tripNoCells[i] = m_tripCellIds.size() - m_tripCellOffset[i];
33944 } else {
33945 if(i > 0) {
33946 m_tripCellOffset[i] = m_tripCellOffset[i - 1] + m_tripNoCells[i - 1];
33947 }
33948 // all cellIds in the tripping zone will be collected in m_tripCellIds
33949 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
33950 MFloat maxR2 = POW2(2 * m_tripXLength[i]) + POW2(2 * m_tripYHeight[i]);
33951 MFloat cellR2 =
33952 POW2(a_coordinate(cellId, 0) - m_tripXOrigin[i]) + POW2(a_coordinate(cellId, 1) - m_tripYOrigin[i]);
33953 if(cellR2 < maxR2) {
33954 m_tripCellIds.push_back(cellId);
33955 m_tripCoords.push_back(a_coordinate(cellId, 2));
33956 a_isSandpaperTripCell(cellId) = true;
33957 }
33958 }
33959 m_tripNoCells[i] = m_tripCellIds.size() - m_tripCellOffset[i];
33960 }
33961 }
33962 MInt tripTotalNoCells = m_tripCellIds.size();
33963
33964 MFloat bbox[6];
33965 geometry().getBoundingBox(&bbox[0]);
33966 m_tripDomainWidth = bbox[5] - bbox[2];
33967
33968 m_log << "=================================================" << endl
33969 << " SANDPAPER TRIP PROPERTIES " << endl
33970 << "=================================================" << endl;
33971 for(MInt i = 0; i < m_tripNoTrips; ++i) {
33972 m_log << "######### TRIP NUMBER " << i << " ###########" << endl
33973 << "tripXOrigin: " << m_tripXOrigin[i] << endl
33974 << "tripXLength: " << m_tripXLength[i] << endl
33975 << "tripYOrigin: " << m_tripYOrigin[i] << endl
33976 << "tripYHeight: " << m_tripYHeight[i] << endl
33977 << "tripMaxAmpFluc: " << m_tripMaxAmpFluc[i] << endl
33978 << "tripNoModes: " << m_tripNoModes << endl
33979 << "tripDeltaTime: " << m_tripDeltaTime[i] << endl
33980 << "tripTimeStep: " << m_tripTimeStep[i] << endl
33981 << "tripDomainWidth: " << m_tripDomainWidth << endl
33982 << "###########################################" << endl;
33983 }
33984 m_log << "=================================================" << endl;
33985
33986 if(tripTotalNoCells > 0) {
33987 mAlloc(m_tripG, m_tripNoTrips * tripTotalNoCells, "m_tripG", F0, AT_);
33988 mAlloc(m_tripH1, m_tripNoTrips * tripTotalNoCells, "m_tripH1", F0, AT_);
33989 mAlloc(m_tripH2, m_tripNoTrips * tripTotalNoCells, "m_tripH2", F0, AT_);
33990 }
33991 mAlloc(m_tripModesG, m_tripNoTrips * 2 * m_tripNoModes, "m_tripModesG", F0, AT_);
33992 mAlloc(m_tripModesH1, m_tripNoTrips * 2 * m_tripNoModes, "m_tripModesH1", F0, AT_);
33993 mAlloc(m_tripModesH2, m_tripNoTrips * 2 * m_tripNoModes, "m_tripModesH2", F0, AT_);
33994
33995 if(m_restart && m_tripUseRestart) {
33996 m_log << "Reading Sandpaper Trip Vars... ";
33997
33998 stringstream fileName;
33999 if(m_useNonSpecifiedRestartFile) {
34000 fileName << restartDir() << "tripRestart" << ParallelIo::fileExt();
34001 } else {
34002 if(!isMultilevel()) {
34003 fileName << restartDir() << "tripRestart_" << m_restartTimeStep << ParallelIo::fileExt();
34004 } else {
34005 mTerm(-1, "loading Sandpaper trip variables not implemented for multiLevel");
34006 }
34007 }
34008
34009 using namespace maia::parallel_io;
34010 ParallelIo parallelIo(fileName.str(), PIO_READ, mpiComm());
34011
34012 ParallelIo::size_type dataSize = m_tripNoTrips * 2 * m_tripNoModes;
34013
34014 parallelIo.setOffset(dataSize, 0);
34015 parallelIo.readArray(&m_tripModesG[0], "tripModesG");
34016 parallelIo.readArray(&m_tripModesH1[0], "tripModesH1");
34017 parallelIo.readArray(&m_tripModesH2[0], "tripModesH2");
34018
34019 m_log << "ok." << endl;
34020
34021 } else {
34022 for(MInt i = 0; i < m_tripNoTrips; ++i) {
34023 const MInt offsetModes = i * 2 * m_tripNoModes;
34024 tripFourierCoefficients(&m_tripModesG[offsetModes], m_tripNoModes, m_tripDomainWidth, m_tripCutoffZ[i]);
34025 tripFourierCoefficients(&m_tripModesH1[offsetModes], m_tripNoModes, m_tripDomainWidth, m_tripCutoffZ[i]);
34026 tripFourierCoefficients(&m_tripModesH2[offsetModes], m_tripNoModes, m_tripDomainWidth, m_tripCutoffZ[i]);
34027 }
34028 }
34029
34030 for(MInt i = 0; i < m_tripNoTrips; ++i) {
34031 const MInt offset = m_tripCellOffset[i];
34032 const MInt offsetModes = i * 2 * m_tripNoModes;
34033 tripForceCoefficients(&m_tripModesG[offsetModes], &m_tripG[offset], &m_tripCoords[0], m_tripNoCells[i],
34034 m_tripNoModes);
34035 tripForceCoefficients(&m_tripModesH1[offsetModes], &m_tripH1[offset], &m_tripCoords[0], m_tripNoCells[i],
34036 m_tripNoModes);
34037 tripForceCoefficients(&m_tripModesH2[offsetModes], &m_tripH2[offset], &m_tripCoords[0], m_tripNoCells[i],
34038 m_tripNoModes);
34039 }
34040 }
34041}
34042
34043template <MInt nDim_, class SysEqn>
34045 TRACE();
34046
34047 for(MInt ii = 0; ii < m_tripNoTrips; ii++) {
34048 const MFloat t = m_time + m_timeStep * m_RKalpha[m_RKStep];
34049 const MInt tripTime = (MInt)(t / m_tripDeltaTime[ii]);
34050 const MFloat p = t / m_tripDeltaTime[ii] - tripTime;
34051 const MFloat b = 3 * pow(p, 2) - 2 * pow(p, 3);
34052 const MInt offset = m_tripCellOffset[ii];
34053 const MInt offsetModes = ii * 2 * m_tripNoModes;
34054
34055 if(tripTime > m_tripTimeStep[ii]) {
34056 m_tripTimeStep[ii] = tripTime;
34057
34058 // copy old values from H1 to H2
34059 for(MInt k = 0; k < m_tripNoCells[ii]; k++) {
34060 if(m_tripNoCells[ii] > 0) m_tripH1[offset + k] = m_tripH2[offset + k];
34061 }
34062 // copy old mode coefficients
34063 for(MInt n = 0; n < m_tripNoModes; n++) {
34064 m_tripModesH1[offsetModes + n] = m_tripModesH2[offsetModes + n];
34065 }
34066
34067 // compute new fourier coefficients
34068 tripFourierCoefficients(&m_tripModesH2[offsetModes], m_tripNoModes, m_tripDomainWidth, m_tripCutoffZ[ii]);
34069 // if(m_tripNoCells[ii] > 0) {
34070 tripForceCoefficients(&m_tripModesH2[offsetModes], &m_tripH2[offset], &m_tripCoords[0], m_tripNoCells[ii],
34071 m_tripNoModes);
34072 //}
34073 }
34074
34075 for(MInt cell = 0; cell < m_tripNoCells[ii]; cell++) {
34076 //
34077 const MFloat forceStrength =
34078 (m_tripMaxAmpSteady[ii] * m_tripG[offset + cell]
34079 + m_tripMaxAmpFluc[ii] * ((1.0 - b) * m_tripH1[offset + cell] + b * m_tripH2[offset + cell]));
34080 const MInt cellId = m_tripCellIds[cell];
34081 const MFloat x = a_coordinate(cellId, 0);
34082 const MFloat y = a_coordinate(cellId, 1);
34083
34084 MInt force =
34085 exp(-POW2((x - m_tripXOrigin[ii]) / m_tripXLength[ii]) - POW2((y - m_tripYOrigin[ii]) / m_tripYHeight[ii]))
34086 * forceStrength;
34087 if(!m_tripAirfoil) {
34088 // assuming the surface is +y-normal
34089 a_rightHandSide(cellId, CV->RHO_V) -= force * a_pvariable(cellId, PV->RHO) * a_cellVolume(cellId);
34090 // should this be an absolute?
34091 IF_CONSTEXPR(hasE<SysEqn>)
34092 a_rightHandSide(cellId, CV->RHO_E) -=
34093 force * a_pvariable(cellId, PV->RHO) * a_pvariable(cellId, PV->V) * a_cellVolume(cellId);
34094 } else {
34095 const MFloat nx = m_tripAirfoilForceDir[ii * nDim + 0];
34096 const MFloat ny = m_tripAirfoilForceDir[ii * nDim + 1];
34097 a_rightHandSide(cellId, CV->RHO_U) -= force * a_pvariable(cellId, PV->RHO) * a_cellVolume(cellId) * nx;
34098 a_rightHandSide(cellId, CV->RHO_V) -= force * a_pvariable(cellId, PV->RHO) * a_cellVolume(cellId) * ny;
34099 // should i get a total velocity aligned with the force here
34100 IF_CONSTEXPR(hasE<SysEqn>)
34101 a_rightHandSide(cellId, CV->RHO_E) -= force * a_pvariable(cellId, PV->RHO)
34102 * (a_pvariable(cellId, PV->U) * nx + a_pvariable(cellId, PV->V) * ny)
34103 * a_cellVolume(cellId);
34104 }
34105 }
34106 }
34107}
34108
34109template <MInt nDim_, class SysEqn>
34111 m_log << "writing Sandpaper Trip Vars... ";
34112
34113 stringstream fileName;
34114 if(m_useNonSpecifiedRestartFile) {
34115 fileName << restartDir() << "tripRestart" << ParallelIo::fileExt();
34116 } else {
34117 if(!isMultilevel()) {
34118 fileName << restartDir() << "tripRestart_" << globalTimeStep << ParallelIo::fileExt();
34119 } else {
34120 mTerm(-1, "writing Sandpaper trip variables not implemented for multiLevel");
34121 }
34122 }
34123
34124 using namespace maia::parallel_io;
34125 ParallelIo parallelIo(fileName.str(), PIO_REPLACE, mpiComm());
34126
34127 MInt dataSize = m_tripNoModes * 2 * m_tripNoTrips;
34128
34129 parallelIo.defineArray(PIO_FLOAT, "tripModesG", dataSize);
34130 parallelIo.defineArray(PIO_FLOAT, "tripModesH1", dataSize);
34131 parallelIo.defineArray(PIO_FLOAT, "tripModesH2", dataSize);
34132
34133 if(domainId() == 0) {
34134 parallelIo.setOffset(dataSize, 0);
34135 parallelIo.writeArray(&m_tripModesG[0], "tripModesG");
34136 parallelIo.writeArray(&m_tripModesH1[0], "tripModesH1");
34137 parallelIo.writeArray(&m_tripModesH2[0], "tripModesH2");
34138
34139 } else {
34140 parallelIo.setOffset(0, 0);
34141 parallelIo.writeArray(&m_tripModesG[0], "tripModesG");
34142 parallelIo.writeArray(&m_tripModesH1[0], "tripModesH1");
34143 parallelIo.writeArray(&m_tripModesH2[0], "tripModesH2");
34144 }
34145 m_log << " ok." << endl;
34146}
34147
34148template <MInt nDim_, class SysEqn>
34150 MInt noCells, MInt noModes) {
34151 MFloat maxLocalValue = -999999.0;
34152 MFloat minLocalValue = 999999.0;
34153 MFloat* ak = &modes[0];
34154 MFloat* phik = &modes[noModes];
34155
34156 for(MInt k = 0; k < noCells; k++) {
34157 const MFloat z = coords[k];
34158 for(MInt n = 0; n < noModes; n++) {
34159 forceCoef[k] += sin(z * ak[n] + phik[n]);
34160 }
34161
34162 maxLocalValue = mMax(maxLocalValue, forceCoef[k]);
34163 minLocalValue = mMin(minLocalValue, forceCoef[k]);
34164 }
34165
34166 // find out min and max to normalize coefficients to interval [-1,1]
34167 MFloat maxGlobalValue = 0.0;
34168 MFloat minGlobalValue = 0.0;
34169 MPI_Allreduce(&maxLocalValue, &maxGlobalValue, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "maxLocalValue",
34170 "maxGlobalValue");
34171 MPI_Allreduce(&minLocalValue, &minGlobalValue, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "minLocalValue",
34172 "minGlobalValue");
34173
34174 // normalize the series
34175 for(MInt k = 0; k < noCells; k++) {
34176 forceCoef[k] = 2 * (forceCoef[k] - minGlobalValue) / (maxGlobalValue - minGlobalValue) - 1.0;
34177 }
34178}
34179
34180template <MInt nDim_, class SysEqn>
34182 MFloat minWaveLength) {
34183 const MFloat minWavenumber = 2 * PI / maxWaveLength;
34184 const MFloat maxWavenumber = 2 * PI / minWaveLength;
34185
34186 MFloat* ak = &modes[0];
34187 MFloat* phik = &modes[noModes];
34188 if(domainId() == 0) {
34189 for(MInt n = 0; n < noModes; n++) {
34190 ak[n] = (maxWavenumber - minWavenumber) * (rand() / MFloat(RAND_MAX)) + minWavenumber;
34191 phik[n] = 2 * PI * rand() / MFloat(RAND_MAX);
34192 }
34193 }
34194
34195 MPI_Bcast(&ak[0], noModes, MPI_DOUBLE, 0, mpiComm(), AT_, "ak[0]");
34196 MPI_Bcast(&phik[0], noModes, MPI_DOUBLE, 0, mpiComm(), AT_, "phik[0]");
34197}
34198
34199template <MInt nDim_, class SysEqn>
34201 TRACE();
34202 // only for channels for a height of 2*referenceLength
34203 const MFloat channelReTau = Context::getSolverProperty<MFloat>("channelReTau", m_solverId, AT_, &channelReTau);
34204 // Both forumlations give mostly identical results
34205 // m_channelVolumeForce = m_rhoInfinity / m_referenceLength * POW2(channelReTau / m_Re * m_UInfinity);
34206 m_channelVolumeForce = POW2(channelReTau / sysEqn().m_Re0);
34207}
34208
34209template <MInt nDim_, class SysEqn>
34211 TRACE();
34212 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
34213 a_rightHandSide(cellId, CV->RHO_U) -= m_channelVolumeForce * a_pvariable(cellId, PV->RHO) * a_cellVolume(cellId);
34214 a_rightHandSide(cellId, CV->RHO_E) -=
34215 m_channelVolumeForce * a_pvariable(cellId, PV->RHO) * a_pvariable(cellId, PV->U) * a_cellVolume(cellId);
34216 }
34217}
34218
34219// only for y-normal surface
34220template <MInt nDim_, class SysEqn>
34222 TRACE();
34223
34224 const MInt noVars = 16;
34225
34226 m_saNoSrfcProbes = Context::propertyLength("saSrfcProbesX", m_solverId);
34227
34228 MInt probeBcId = 3399;
34229 probeBcId = Context::getSolverProperty<MInt>("saSrfcBcId", m_solverId, AT_, &probeBcId);
34230
34231 m_saSrfcProbeStart = Context::getSolverProperty<MInt>("saSrfcProbeStart", m_solverId, AT_, &m_saSrfcProbeStart);
34232
34233 if(m_saNoSrfcProbes != Context::propertyLength("saSrfcProbesSide", m_solverId))
34234 mTerm(1, "length of saSrfcProbesX and length of saSrfcProbesSide must match!");
34235
34236 m_saSrfcProbeIds.resize(m_saNoSrfcProbes);
34237 m_saSrfcProbeSrfcs.resize(m_saNoSrfcProbes);
34238
34239 for(MInt p = 0; p < m_saNoSrfcProbes; p++) {
34240 m_saSrfcProbeIds[p].clear();
34241 m_saSrfcProbeSrfcs[p].clear();
34242
34243 const MFloat probeCoord = Context::getSolverProperty<MFloat>("saSrfcProbesX", m_solverId, AT_, &probeCoord, p);
34244 const MInt probeSide = Context::getSolverProperty<MInt>("saSrfcProbesSide", m_solverId, AT_, &probeSide, p);
34245
34246 for(MInt bCellId = 0; bCellId < m_bndryCells->size(); bCellId++) {
34247 MInt cellId = m_bndryCells->a[bCellId].m_cellId;
34248 if(!a_isHalo(cellId)) {
34249 if(abs(a_coordinate(cellId, 0) - probeCoord) < F1B2 * c_cellLengthAtLevel(maxRefinementLevel()) + m_eps) {
34250 for(MInt srfc = 0; srfc < m_bndryCells->a[bCellId].m_noSrfcs; srfc++) {
34251 if(m_bndryCells->a[bCellId].m_srfcs[srfc]->m_bndryCndId == probeBcId) {
34252 const MFloat ny = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_normalVector[1];
34253 if(ny * (MFloat)probeSide > 0) {
34254 m_saSrfcProbeIds[p].push_back(cellId);
34255 m_saSrfcProbeSrfcs[p].push_back(srfc);
34256 break;
34257 }
34258 }
34259 }
34260 }
34261 }
34262 }
34263 }
34264
34265
34266 mAlloc(m_saSrfcProbeBuffer, m_saNoSrfcProbes * noVars, "m_saSrfcProbeBuffer", 0.0, AT_);
34267
34268 MIntScratchSpace localNoSamples(m_saNoSrfcProbes, AT_, "localNoSamples");
34269 for(MInt p = 0; p < m_saNoSrfcProbes; p++) {
34270 localNoSamples[p] = m_saSrfcProbeIds[p].size();
34271 }
34272
34273 if(domainId() == 0) {
34274 mAlloc(m_saSrfcProbeNoSamples, m_saNoSrfcProbes, "m_saSrfcProbeNoSamples", 0, AT_);
34275 }
34276 MPI_Reduce(&localNoSamples[0], &m_saSrfcProbeNoSamples[0], m_saNoSrfcProbes, MPI_INT, MPI_SUM, 0, mpiComm(), AT_,
34277 "&localNoSamples[0]", "&m_saSrfcProbeNoSamples[0]");
34278}
34279
34280template <MInt nDim_, class SysEqn>
34282 TRACE();
34283
34284 const MInt noVars = 16;
34285
34286 // reset buffer
34287 memset(&(m_saSrfcProbeBuffer[0]), 0.0, m_saNoSrfcProbes * noVars * sizeof(MFloat));
34288
34289 // collect local data
34290 for(MInt p = 0; p < m_saNoSrfcProbes; p++) {
34291 for(MUint s = 0; s < m_saSrfcProbeIds[p].size(); s++) {
34292 const MInt cellId = m_saSrfcProbeIds[p][s];
34293 const MInt srfc = m_saSrfcProbeSrfcs[p][s];
34294 const MInt bCellId = a_bndryId(cellId);
34295 const MInt wmSrfcId = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_wmSrfcId;
34296
34297 MFloat pSrfc = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_primVars[PV->P];
34298 MFloat rhoSrfc = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_primVars[PV->RHO];
34299 MFloat uSrfc = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_primVars[PV->U];
34300 MFloat vSrfc = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_primVars[PV->V];
34301 MFloat wSrfc = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_primVars[PV->W];
34302 MFloat TSrfc = sysEqn().temperature_ES(rhoSrfc, pSrfc);
34303 MFloat mueSrfc = SUTHERLANDLAW(TSrfc);
34304
34305 MFloat nx = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_normalVector[0];
34306 MFloat ny = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_normalVector[1];
34307 MFloat nz = m_bndryCells->a[bCellId].m_srfcs[srfc]->m_normalVector[2];
34308
34309 MFloat dudn = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_normalDeriv[PV->U];
34310 MFloat dvdn = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_normalDeriv[PV->V];
34311 MFloat dwdn = m_bndryCells->a[bCellId].m_srfcVariables[srfc]->m_normalDeriv[PV->W];
34312
34313 MFloat tau_w = mueSrfc * (dudn * ny - dvdn * nx) / sysEqn().m_Re0;
34314 MFloat mue_wm = F0;
34315 MFloat tau_wm = F0;
34316
34317 if(m_wmLES) {
34318 if(wmSrfcId > -1) {
34319 mue_wm += m_wmSurfaces[wmSrfcId].m_wmMUEWM;
34320 tau_wm += (mueSrfc + mue_wm) * (dudn * ny - dvdn * nx) / sysEqn().m_Re0;
34321 }
34322 }
34323
34324 m_saSrfcProbeBuffer[noVars * p + 0] += m_bndryCells->a[bCellId].m_srfcs[srfc]->m_coordinates[0];
34325 m_saSrfcProbeBuffer[noVars * p + 1] += nx;
34326 m_saSrfcProbeBuffer[noVars * p + 2] += ny;
34327 m_saSrfcProbeBuffer[noVars * p + 3] += nz;
34328 m_saSrfcProbeBuffer[noVars * p + 4] += uSrfc;
34329 m_saSrfcProbeBuffer[noVars * p + 5] += vSrfc;
34330 m_saSrfcProbeBuffer[noVars * p + 6] += wSrfc;
34331 m_saSrfcProbeBuffer[noVars * p + 7] += rhoSrfc;
34332 m_saSrfcProbeBuffer[noVars * p + 8] += pSrfc;
34333 m_saSrfcProbeBuffer[noVars * p + 9] += mueSrfc;
34334 m_saSrfcProbeBuffer[noVars * p + 10] += dudn;
34335 m_saSrfcProbeBuffer[noVars * p + 11] += dvdn;
34336 m_saSrfcProbeBuffer[noVars * p + 12] += dwdn;
34337 m_saSrfcProbeBuffer[noVars * p + 13] += tau_w;
34338 m_saSrfcProbeBuffer[noVars * p + 14] += mue_wm;
34339 m_saSrfcProbeBuffer[noVars * p + 15] += tau_wm;
34340 }
34341 }
34342
34343 if(domainId() == 0) {
34344 MPI_Reduce(MPI_IN_PLACE, &m_saSrfcProbeBuffer[0], noVars * m_saNoSrfcProbes, MPI_DOUBLE, MPI_SUM, 0, mpiComm(), AT_,
34345 "MPI_IN_PLACE", "&m_saSrfcProbeBuffer[0]");
34346 } else {
34347 MPI_Reduce(&m_saSrfcProbeBuffer[0], &m_saSrfcProbeBuffer[0], noVars * m_saNoSrfcProbes, MPI_DOUBLE, MPI_SUM, 0,
34348 mpiComm(), AT_, "&m_saSrfcProbeBuffer[0]", "&m_saSrfcProbeBuffer[0]");
34349 }
34350
34351 if(domainId() == 0) {
34352 for(MInt p = 0; p < m_saNoSrfcProbes; p++) {
34353 // write output
34354 FILE* datei;
34355 stringstream filename;
34356 filename << outputDir() << m_saSrfcProbeDir << "/"
34357 << "spanAvgSrfcProbes_" << p;
34358 datei = fopen(filename.str().c_str(), "a");
34359
34360 // print head
34361 if(globalTimeStep == m_saSrfcProbeStart) {
34362 fprintf(datei, "0: globalTimeStep");
34363 fprintf(datei, " 1: x");
34364 fprintf(datei, " 2: nx");
34365 fprintf(datei, " 3: ny");
34366 fprintf(datei, " 4: nz");
34367 fprintf(datei, " 5: u_srfc");
34368 fprintf(datei, " 6: v_srfc");
34369 fprintf(datei, " 7: w_srfc");
34370 fprintf(datei, " 8: rho_srfc");
34371 fprintf(datei, " 9: p_srfc");
34372 fprintf(datei, " 10: mue_srfc");
34373 fprintf(datei, " 11: dudn");
34374 fprintf(datei, " 12: dvdn");
34375 fprintf(datei, " 13: dwdn");
34376 fprintf(datei, " 14: tau_w");
34377 fprintf(datei, " 15: mue_wm");
34378 fprintf(datei, " 16: tau_wm");
34379 fprintf(datei, "\n");
34380 }
34381
34382 fprintf(datei, "%d ", globalTimeStep);
34383
34384 for(MInt v = 0; v < noVars; v++) {
34385 fprintf(datei, "%f ", m_saSrfcProbeBuffer[noVars * p + v] / m_saSrfcProbeNoSamples[p]);
34386 }
34387 fprintf(datei, "\n");
34388 fclose(datei);
34389 }
34390 }
34391}
34392
34393template <MInt nDim_, class SysEqn>
34395 MFloat timerValue[3];
34396 timerValue[0] = RETURN_TIMER_TIME(m_timers[Timers::WMExchange]);
34397 timerValue[1] = RETURN_TIMER_TIME(m_timers[Timers::WMSurfaceLoop]);
34398 timerValue[2] = RETURN_TIMER_TIME(m_timers[Timers::WMFluxCorrection]);
34399
34400 for(MInt i = 0; i < 3; i++) {
34401 if(domainId() == 0) {
34402 MPI_Reduce(MPI_IN_PLACE, &timerValue[i], 1, MPI_DOUBLE, MPI_MAX, 0, mpiComm(), AT_, "MPI_IN_PLACE",
34403 "&timerValue[i]");
34404 } else {
34405 MPI_Reduce(&timerValue[i], &timerValue[i], 1, MPI_DOUBLE, MPI_MAX, 0, mpiComm(), AT_, "&timerValue[i]",
34406 "&timerValue[i]");
34407 }
34408 }
34409
34410 if(domainId() == 0) {
34411 MPI_Reduce(MPI_IN_PLACE, &m_wmIterator, 1, MPI_INT, MPI_MAX, 0, mpiComm(), AT_, "MPI_IN_PLACE", "&m_wmIterator");
34412 } else {
34413 MPI_Reduce(&m_wmIterator, &m_wmIterator, 1, MPI_INT, MPI_MAX, 0, mpiComm(), AT_, "&m_wmIterator", "&m_wmIterator");
34414 }
34415
34416
34417 if(domainId() == 0) {
34418 FILE* datei;
34419 stringstream filename;
34420 filename << outputDir() << "wmTimers";
34421 datei = fopen(filename.str().c_str(), "a");
34422
34423 fprintf(datei, "WMExchange: %f ", timerValue[0]);
34424 fprintf(datei, "WMSurfaceLoop: %f ", timerValue[1]);
34425 fprintf(datei, "WMFluxCorrection: %f ", timerValue[2]);
34426 fprintf(datei, "WMIterator: %d ", m_wmIterator);
34427 fprintf(datei, "\n");
34428
34429 fclose(datei);
34430 }
34431}
34432
34433// Project Thesis: Wall Normal Output Work by Karlis Vagalis and Simon Cremer
34434// Supervisor: Thomas Luerkens
34435// Description:
34436// Provides a line output of cell centered values on wall normals of a
34437// specified boundary condition
34438// TODO:
34439// - enable interpolation within cells to allow proper computation of gradients in postprocessing
34440// - allow online averaging to allow quick calculation of turbulent statistics in postprocessing
34441template <MInt nDim_, class SysEqn>
34443 TRACE();
34444
34445 m_log << "Computing Wall Normal Point Coordinates ... " << endl;
34446
34447 MInt noSegments = m_normalNoPoints - 1;
34448 MFloat segmentLength = m_normalLength / noSegments;
34449
34450 MInt size = m_bndryCells->size();
34451 MInt k = m_normalSamplingSide.size();
34452
34453 ScratchSpace<MInt> sampleUsage(k, AT_, "sampleUsage");
34454 sampleUsage.fill(0);
34455
34456 for(MInt i = 0; i < size; i++) {
34457 MInt cellId = m_bndryCells->a[i].m_cellId;
34458 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
34459 if(!a_hasProperty(cellId, SolverCell::IsHalo)) {
34460 for(MInt srfc = 0; srfc < m_bndryCells->a[i].m_noSrfcs; srfc++) {
34461 MInt cellCnd = m_bndryCells->a[i].m_srfcs[srfc]->m_bndryCndId;
34462 if(cellCnd == m_normalBcId) {
34463 MFloat dist = c_cellLengthAtCell(cellId) / 2;
34464 MFloat x = (a_coordinate(cellId, 0) - m_bndryCells->a[i].m_coordinates[0]);
34465 MFloat xUpper = x + dist;
34466 MFloat xLower = x - dist;
34467 MFloat z = 0;
34468 MFloat zUpper = 0;
34469 MFloat zLower = 0;
34470
34471 if(nDim == 3) {
34472 z = (a_coordinate(cellId, 2) - m_bndryCells->a[i].m_coordinates[2]);
34473 zUpper = z + dist;
34474 zLower = z - dist;
34475 }
34476
34477 for(MInt o = 0; o < k; o++) {
34478 if(sampleUsage[o] == 0) {
34479 MFloat xCompare = m_normalSamplingCoords[o * 2];
34480 MFloat zCompare = 0;
34481 if(nDim == 3) {
34482 zCompare = m_normalSamplingCoords[o * 2 + 1];
34483 }
34484
34485 if((xCompare <= xUpper) && (xCompare >= xLower) && (zCompare <= zUpper) && (zCompare >= zLower)) {
34486 MInt side = m_normalSamplingSide[o];
34487 MFloat ny = m_bndryCells->a[i].m_srfcs[srfc]->m_normalVector[1];
34488
34489 if(((side < 0) && (ny < 0)) || ((side > 0) && (ny > 0))) {
34490 sampleUsage[o] = 1;
34491 m_wallSetupOrigin.push_back(xCompare);
34492 m_wallSetupOrigin.push_back(zCompare);
34493 m_wallSetupOriginSide.push_back(side);
34494
34495 MFloat initCoordx = m_bndryCells->a[i].m_srfcs[srfc]->m_coordinates[0];
34496 MFloat initCoordy = m_bndryCells->a[i].m_srfcs[srfc]->m_coordinates[1];
34497 MFloat initCoordz = 0;
34498
34499 MFloat nx = m_bndryCells->a[i].m_srfcs[srfc]->m_normalVector[0];
34500 MFloat nz = 0;
34501
34502 m_wallNormalVectors.push_back(nx);
34503 m_wallNormalVectors.push_back(ny);
34504
34505 if(nDim == 3) {
34506 initCoordz = m_bndryCells->a[i].m_srfcs[srfc]->m_coordinates[2];
34507 nz = m_bndryCells->a[i].m_srfcs[srfc]->m_normalVector[2];
34508 }
34509
34510 MFloat r = sqrt(nx * nx + ny * ny + nz * nz);
34511 MFloat scalingFactor = segmentLength / r;
34512
34513 MFloat stepX = nx * scalingFactor;
34514 MFloat stepY = ny * scalingFactor;
34515 MFloat stepZ = nz * scalingFactor;
34516
34517 for(MInt step = 0; step <= noSegments; step++) {
34518 MFloat coordX = initCoordx + (step * stepX);
34519 MFloat coordY = initCoordy + (step * stepY);
34520
34521 m_wallNormalPointCoords.push_back(coordX);
34522 m_wallNormalPointCoords.push_back(coordY);
34523
34524 if(nDim == 3) {
34525 MFloat coordZ = initCoordz + (step * stepZ);
34526 m_wallNormalPointCoords.push_back(coordZ);
34527 }
34528 }
34529 m_noWallNormals++;
34530 }
34531 }
34532 }
34533 }
34534 }
34535 }
34536 }
34537 }
34538 }
34539 m_log << "done." << endl;
34540}
34541
34542
34543template <MInt nDim_, class SysEqn>
34545 TRACE();
34546
34547 MPI_Barrier(mpiComm(), AT_);
34548
34549 m_log << "Finding Wall Normal Cell Ids ... " << endl;
34550
34551 ScratchSpace<MInt> localNoWallNormalPointCoords(noDomains(), AT_, "localNoWallNormalPointCoords");
34552 localNoWallNormalPointCoords.fill(0);
34553
34554 ScratchSpace<MInt> localNoWallNormalPoints(noDomains(), AT_, "localNoWallNormalPoints");
34555 localNoWallNormalPoints.fill(0);
34556
34557 localNoWallNormalPointCoords[domainId()] = m_wallNormalPointCoords.size();
34558
34559 localNoWallNormalPoints[domainId()] = (m_wallNormalPointCoords.size() / nDim);
34560
34561 MPI_Allgather(&localNoWallNormalPointCoords[domainId()], 1, MPI_INT, &localNoWallNormalPointCoords[0], 1, MPI_INT,
34562 mpiComm(), AT_, "localNoWallNormalPointCoords", "localNoWallNormalPointCoords");
34563 MPI_Allgather(&localNoWallNormalPoints[domainId()], 1, MPI_INT, &localNoWallNormalPoints[0], 1, MPI_INT, mpiComm(),
34564 AT_, "localNoWallNormalPoints", "localNoWallNormalPoints");
34565
34566 // Output vector for domainId to which point belongs to
34567 m_wallNormalPointDomains.resize(localNoWallNormalPoints[domainId()]);
34568 std::fill(m_wallNormalPointDomains.begin(), m_wallNormalPointDomains.end(), -1);
34569
34570 // Output vector for cellId in which point lies
34571 m_wallNormalPointCellIDs.resize(localNoWallNormalPoints[domainId()]);
34572 std::fill(m_wallNormalPointCellIDs.begin(), m_wallNormalPointCellIDs.end(), -1);
34573 // temporary vector containing the neighbors cell Ids
34574 std::vector<MInt> tempNeghbrIds;
34575 tempNeghbrIds.clear();
34576
34577 // Output vector for neghbrIds of cellId in which point lies
34578 m_neighborPointIds.resize(localNoWallNormalPoints[domainId()]);
34579 std::fill(m_neighborPointIds.begin(), m_neighborPointIds.end(), tempNeghbrIds);
34580
34581 for(MInt dom = 0; dom < noDomains(); dom++) {
34582 MInt noCoords = localNoWallNormalPointCoords[dom];
34583 MInt noPoints = localNoWallNormalPoints[dom];
34584
34585 if(noPoints > 0) {
34586 // temporary vector containing found cell's domainId
34587 std::vector<MInt> domainContainingCell;
34588 domainContainingCell.clear();
34589 // temporary vector containing found cellId
34590 std::vector<MInt> normalPointCellId;
34591 normalPointCellId.clear();
34592 // temporary vector containing the index of point (order, e.g first point, etc)
34593 std::vector<MInt> placement;
34594 placement.clear();
34595
34596 // temporary vector containing the neighbors cell Ids
34597 std::vector<MInt> neghbrIds;
34598 neghbrIds.clear();
34599
34600 // vector collecting the vectors containing the neighbors cellIds
34601 std::vector<std::vector<MInt>> neghbrIdsofId;
34602 neghbrIdsofId.clear();
34603
34604 // neighbor ids as one dimensional array for communication
34605 std::vector<MInt> oneDimNeghbrs;
34606 oneDimNeghbrs.clear();
34607
34608 std::vector<MInt> noOfNeghbrs;
34609 noOfNeghbrs.clear();
34610 // temporary coord array for croodinate distribution to other domains
34611 ScratchSpace<MFloat> sendCoordsBuffer(noCoords, AT_, "sendCoordsBuffer");
34612 sendCoordsBuffer.fill(0.0);
34613
34614 // array for all domainIds for gathering
34615 ScratchSpace<MInt> allDomainsContainingCell(noPoints, AT_, "allDomainsContainingCell");
34616 allDomainsContainingCell.fill(-1);
34617 // array for all point cellIds for gathering
34618 ScratchSpace<MInt> allNormalPointCellIds(noPoints, AT_, "allNormalPointCellIds");
34619 allNormalPointCellIds.fill(-1);
34620
34621 ScratchSpace<MInt> noNeighbors(noPoints, AT_, "noNeighbors");
34622 noNeighbors.fill(-1);
34623
34624 ScratchSpace<MInt> allNeighbors(noPoints * ((pow(3, nDim) - 1) * pow(2, nDim) + 1), AT_, "allNeighbors");
34625 allNeighbors.fill(-1);
34626
34627 // array fpr all neighbrIds for gathering
34628 std::vector<std::vector<MInt>> allNeghbrIdsofId;
34629 allNeghbrIdsofId.clear();
34630
34631 // array for determining, which point index from distributed coords array responds to which calculated cellId
34632 ScratchSpace<MInt> allPlacements(noPoints, AT_, "allPlacements");
34633 allPlacements.fill(-1);
34634
34635 // number of points for the send/recv buffer count
34636 ScratchSpace<MInt> bufferNoWallNormalPoints(noDomains(), AT_, "bufferNoWallNormalPoints");
34637 bufferNoWallNormalPoints.fill(0);
34638
34639 ScratchSpace<MInt> bufferNoNeighbor(noDomains(), AT_, "bufferNoNeighborOffsets");
34640 bufferNoNeighbor.fill(0);
34641
34642 // point offsets for displacement in the recombined list
34643 ScratchSpace<MInt> bufferPointOffsets(noDomains(), AT_, "bufferPointOffsets");
34644 bufferPointOffsets.fill(0);
34645
34646 ScratchSpace<MInt> bufferNeighborOffsets(noDomains(), AT_, "bufferNeighborOffsets");
34647 bufferNeighborOffsets.fill(0);
34648
34649 // copy localNormalPointCoords to coordBuffer for broadcasting
34650 if(domainId() == dom) {
34651 for(MInt c = 0; c < noCoords; c++) {
34652 sendCoordsBuffer[c] = m_wallNormalPointCoords[c];
34653 }
34654 }
34655
34656 // boradcast point coords from one working domain to all domains
34657 MPI_Bcast(&sendCoordsBuffer[0], noCoords, MPI_DOUBLE, dom, mpiComm(), AT_, "sendCoordsBuffer");
34658
34659 // take coords from the localWallPointCoords list to run findContainingLeafCell
34660 for(MInt p = 0; p < noPoints; p++) {
34661 MInt tmpId = -1;
34662 MFloat pointCoords[nDim];
34663
34664 pointCoords[0] = sendCoordsBuffer[nDim * p];
34665 pointCoords[1] = sendCoordsBuffer[nDim * p + 1];
34666
34667 if(nDim == 3) {
34668 pointCoords[2] = sendCoordsBuffer[nDim * p + 2];
34669 }
34670
34671 // checking coordinates with findContainingLeafCell
34672 tmpId = grid().raw().findContainingLeafCell(pointCoords);
34673
34674 // checking wether the cell is a part of the domain and wether it is not halo
34675 if(tmpId != -1 && !a_hasProperty(tmpId, SolverCell::IsHalo)) {
34676 // make a list of all neighbors
34677 neghbrIds = findWallNormalNeighbors(tmpId);
34678 // distance criteria: make sure only direct neighbors are included:
34679 std::vector<MInt> deleteElements;
34680 deleteElements.clear();
34681
34682 for(MInt i = 0; i < MInt(neghbrIds.size()); i++) {
34683 MFloat distance = 0.0;
34684 // initialize cut off factor to biggest value
34685 MFloat dist_factor = 2.4;
34686 MFloat dist_x = a_coordinate(neghbrIds[i], 0) - a_coordinate(tmpId, 0);
34687 MFloat dist_y = a_coordinate(neghbrIds[i], 1) - a_coordinate(tmpId, 1);
34688 MFloat dist_z = 0.0;
34689 // reference distance
34690 MFloat dist_ref = grid().cellLengthAtLevel(a_level(tmpId));
34691
34692 if(nDim == 3) {
34693 dist_z = a_coordinate(neghbrIds[i], 2) - a_coordinate(tmpId, 2);
34694 }
34695
34696 if(abs(dist_x) < 0.05 * dist_ref || abs(dist_y) < 0.05 * dist_ref || abs(dist_z) < 0.05 * dist_ref) {
34697 dist_factor = 1.9;
34698 }
34699
34700 if((abs(dist_x) < 0.05 * dist_ref && abs(dist_y) < 0.05 * dist_ref)
34701 || (abs(dist_x) < 0.05 * dist_ref && abs(dist_z) < 0.05 * dist_ref)
34702 || (abs(dist_y) < 0.05 * dist_ref && abs(dist_z) < 0.05 * dist_ref)) {
34703 dist_factor = 1.33;
34704 }
34705
34706 distance = sqrt(dist_x * dist_x + dist_y * dist_y + dist_z * dist_z);
34707 if(distance > dist_factor * grid().cellLengthAtLevel(a_level(tmpId))) {
34708 deleteElements.push_back(i);
34709 }
34710 }
34711
34712 for(MInt i = 0; i < MInt(deleteElements.size()); i++) {
34713 MInt eraseElement = deleteElements.end()[-1 - i];
34714 neghbrIds.erase(neghbrIds.begin() + eraseElement);
34715 }
34716
34717
34718 MInt d = domainId();
34719 // add domain to the list
34720 domainContainingCell.push_back(d);
34721 // add cellId if to the list
34722 normalPointCellId.push_back(tmpId);
34723 // add placement of the point
34724 placement.push_back(p);
34725 // collect neighbrIds for every Id
34726 neghbrIdsofId.push_back(neghbrIds);
34727
34728 // clear temporary vectors
34729 neghbrIds.clear();
34730 }
34731 }
34732
34733 // transform 2D neighbor id array into one dimensional array for communication
34734 oneDimNeghbrs.clear();
34735 for(MInt i = 0; i < MInt(neghbrIdsofId.size()); i++) {
34736 noOfNeghbrs.push_back(MInt(neghbrIdsofId[i].size()));
34737 for(MInt j = 0; j < MInt(neghbrIdsofId[i].size()); j++) {
34738 oneDimNeghbrs.push_back(neghbrIdsofId[i][j]);
34739 }
34740 }
34741
34742 bufferNoWallNormalPoints[domainId()] = normalPointCellId.size();
34743
34744 for(MInt i = 0; i < MInt(neghbrIdsofId.size()); i++) {
34745 bufferNoNeighbor[domainId()] += neghbrIdsofId[i].size();
34746 }
34747
34748 MPI_Allgather(&bufferNoNeighbor[domainId()], 1, MPI_INT, &bufferNoNeighbor[0], 1, MPI_INT, mpiComm(), AT_,
34749 "bufferNoNeighbor", "bufferNoNeighbor");
34750
34751 MPI_Allgather(&bufferNoWallNormalPoints[domainId()], 1, MPI_INT, &bufferNoWallNormalPoints[0], 1, MPI_INT,
34752 mpiComm(), AT_, "bufferNoWallNormalPoints", "bufferNoWallNormalPoints");
34753
34754
34755 for(MInt d = 0; d < noDomains(); d++) {
34756 if(d > 0) {
34757 bufferPointOffsets[d] = bufferPointOffsets[d - 1] + bufferNoWallNormalPoints[d - 1];
34758 bufferNeighborOffsets[d] = bufferNeighborOffsets[d - 1] + bufferNoNeighbor[d - 1];
34759 }
34760 }
34761
34762 // gather domainIds
34763 MPI_Gatherv(&domainContainingCell[0], bufferNoWallNormalPoints[domainId()], MPI_INT, &allDomainsContainingCell[0],
34764 &bufferNoWallNormalPoints[0], &bufferPointOffsets[0], MPI_INT, dom, mpiComm(), AT_,
34765 "domainContainingCell", "allDomainsContainingCell");
34766
34767 // gather cellIds
34768 MPI_Gatherv(&normalPointCellId[0], bufferNoWallNormalPoints[domainId()], MPI_INT, &allNormalPointCellIds[0],
34769 &bufferNoWallNormalPoints[0], &bufferPointOffsets[0], MPI_INT, dom, mpiComm(), AT_,
34770 "normalPointCellId", "allNormalPointCellIds");
34771
34772 // gather placements
34773 MPI_Gatherv(&placement[0], bufferNoWallNormalPoints[domainId()], MPI_INT, &allPlacements[0],
34774 &bufferNoWallNormalPoints[0], &bufferPointOffsets[0], MPI_INT, dom, mpiComm(), AT_, "placement",
34775 "allPlacements");
34776
34777 // gather neighbors
34778 MPI_Gatherv(&oneDimNeghbrs[0], bufferNoNeighbor[domainId()], MPI_INT, &allNeighbors[0], &bufferNoNeighbor[0],
34779 &bufferNeighborOffsets[0], MPI_INT, dom, mpiComm(), AT_, "oneDimNeghbrs", "allNeighbors");
34780
34781 // gather number of neighbors per point
34782 MPI_Gatherv(&noOfNeghbrs[0], bufferNoWallNormalPoints[domainId()], MPI_INT, &noNeighbors[0],
34783 &bufferNoWallNormalPoints[0], &bufferPointOffsets[0], MPI_INT, dom, mpiComm(), AT_, "noOfNeghbrs",
34784 "noNeighbors");
34785
34786 if(domainId() == dom) {
34787 MInt count = 0;
34788 MInt count_next = 0;
34789 std::vector<MInt> tempVec;
34790 tempVec.clear();
34791 for(MInt k = 0; k < noPoints; k++) {
34792 count_next = count_next + noNeighbors[k];
34793 for(MInt j = count; j < count_next; j++) {
34794 tempVec.push_back(allNeighbors[j]);
34795 }
34796
34797 allNeghbrIdsofId.push_back(tempVec);
34798 count = count_next;
34799 tempVec.clear();
34800 }
34801
34802 for(MInt c = 0; c < noPoints; c++) {
34803 MInt p = allPlacements[c];
34804 if(p != -1) {
34805 m_wallNormalPointDomains[p] = allDomainsContainingCell[c];
34806 m_wallNormalPointCellIDs[p] = allNormalPointCellIds[c];
34807 m_neighborPointIds[p] = allNeghbrIdsofId[c];
34808 }
34809 }
34810 }
34811 }
34812 }
34813}
34814
34815template <MInt nDim_, class SysEqn>
34817 TRACE();
34818
34819 m_log << "Find Neighbor Points of Wall Normal Point" << endl;
34820
34821 const MInt tmpId = pointId;
34822 MInt tempNeghbrId = 0;
34823
34824 // temporary vector containing the neighbors cell Ids
34825 std::vector<MInt> neghbrIds;
34826 neghbrIds.clear();
34827 // temporary vector containing the directions in which neighbors were found
34828 std::vector<MInt> dirOfNeghbrIds;
34829 dirOfNeghbrIds.clear();
34830 // temporary vector containing the diagonal neighbor cellIds
34831 std::vector<MInt> diagNeghbrIds;
34832 diagNeghbrIds.clear();
34833 // temporary vector containing the directions in which diaganol neighbors were found
34834 std::vector<std::vector<MInt>> dirOfDiagNeghbrIds;
34835 dirOfDiagNeghbrIds.clear();
34836
34837 // checking wether the cell is a part of the domain and wether it is not halo
34838 if(tmpId != -1 && !a_hasProperty(tmpId, SolverCell::IsHalo)) {
34839 // make a list of all neighbors
34840 if(!a_isBndryGhostCell(tmpId)) {
34841 if(a_hasProperty(tmpId, SolverCell::IsOnCurrentMGLevel)) {
34842 for(MInt dir = 0; dir < m_noDirs; dir++) {
34843 if(a_hasNeighbor(tmpId, dir) > 0 && checkNeighborActive(tmpId, dir)) {
34844 tempNeghbrId = c_neighborId(tmpId, dir);
34845 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
34846 neghbrIds.push_back(tempNeghbrId);
34847 dirOfNeghbrIds.push_back(dir);
34848 } else {
34849 // investigate neighbor children
34850 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
34851 if(c_childId(tempNeghbrId, childId) == -1) {
34852 continue;
34853 }
34854 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
34855 dirOfNeghbrIds.push_back(dir);
34856 }
34857 }
34858 }
34859 }
34860
34861 // 2D case find all neighbors in xy plane
34862 for(MInt dir = 0; dir < 2; dir++) {
34863 if(a_hasNeighbor(neghbrIds[dir], 2) > 0 && checkNeighborActive(neghbrIds[dir], 2)) {
34864 tempNeghbrId = c_neighborId(neghbrIds[dir], 2);
34865 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
34866 diagNeghbrIds.push_back(tempNeghbrId);
34867 dirOfDiagNeghbrIds.push_back({dir, 2});
34868 } else {
34869 // investigate neighbor children
34870 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
34871 if(c_childId(tempNeghbrId, childId) == -1) {
34872 continue;
34873 }
34874 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
34875 dirOfDiagNeghbrIds.push_back({dir, 2});
34876 }
34877 }
34878 }
34879
34880 if(a_hasNeighbor(neghbrIds[dir], 3) > 0 && checkNeighborActive(neghbrIds[dir], 3)) {
34881 tempNeghbrId = c_neighborId(neghbrIds[dir], 3);
34882 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
34883 diagNeghbrIds.push_back(tempNeghbrId);
34884 dirOfDiagNeghbrIds.push_back({dir, 3});
34885 } else {
34886 // investigate neighbor children
34887 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
34888 if(c_childId(tempNeghbrId, childId) == -1) {
34889 continue;
34890 }
34891 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
34892 dirOfDiagNeghbrIds.push_back({dir, 3});
34893 }
34894 }
34895 }
34896 }
34897
34898 // search in all orthogonal directions of the neighbor you just found
34899 if(nDim == 3) {
34900 for(MInt i = 0; i < MInt(neghbrIds.size()); i++) {
34901 MInt tempDir[4];
34902 if(dirOfNeghbrIds[i] == 0 || dirOfNeghbrIds[i] == 1) {
34903 tempDir[0] = 2;
34904 tempDir[1] = 3;
34905 tempDir[2] = 4;
34906 tempDir[3] = 5;
34907 }
34908 if(dirOfNeghbrIds[i] == 2 || dirOfNeghbrIds[i] == 3) {
34909 tempDir[0] = 0;
34910 tempDir[1] = 1;
34911 tempDir[2] = 4;
34912 tempDir[3] = 5;
34913 }
34914 if(dirOfNeghbrIds[i] == 4 || dirOfNeghbrIds[i] == 5) {
34915 tempDir[0] = 0;
34916 tempDir[1] = 1;
34917 tempDir[2] = 2;
34918 tempDir[3] = 3;
34919 }
34920
34921 for(MInt j = 0; j < 4; j++) {
34922 if(a_hasNeighbor(neghbrIds[i], tempDir[j]) > 0 && checkNeighborActive(neghbrIds[i], tempDir[j])) {
34923 tempNeghbrId = c_neighborId(neghbrIds[i], tempDir[j]);
34924 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
34925 diagNeghbrIds.push_back(tempNeghbrId);
34926 dirOfDiagNeghbrIds.push_back({dirOfNeghbrIds[i], tempDir[j]});
34927 } else {
34928 // investigate neighbor children
34929 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
34930 if(c_childId(tempNeghbrId, childId) == -1) {
34931 continue;
34932 }
34933 diagNeghbrIds.push_back(c_childId(tempNeghbrId, childId));
34934 dirOfDiagNeghbrIds.push_back({dirOfNeghbrIds[i], tempDir[j]});
34935 }
34936 }
34937 }
34938 }
34939 }
34940 }
34941
34942 if(nDim == 3) {
34943 if(neghbrIds.size() > 5) {
34944 for(MInt dir = 1; dir < nDim; dir++) {
34945 MInt dirOfNeghbr = 2 * dir + 2;
34946 if(dirOfNeghbr == 6) {
34947 dirOfNeghbr -= 6;
34948 }
34949 if(a_hasNeighbor(neghbrIds[2 * dir], dirOfNeghbr) > 0
34950 && checkNeighborActive(neghbrIds[2 * dir], dirOfNeghbr)) {
34951 tempNeghbrId = c_neighborId(neghbrIds[2 * dir], dirOfNeghbr);
34952 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
34953 diagNeghbrIds.push_back(tempNeghbrId);
34954 } else {
34955 // investigate neighbor children
34956 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
34957 if(c_childId(tempNeghbrId, childId) == -1) {
34958 continue;
34959 }
34960 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
34961 }
34962 }
34963 }
34964
34965 if(a_hasNeighbor(neghbrIds[2 * dir], dirOfNeghbr + 1) > 0
34966 && checkNeighborActive(neghbrIds[2 * dir], dirOfNeghbr + 1)) {
34967 tempNeghbrId = c_neighborId(neghbrIds[2 * dir], dirOfNeghbr + 1);
34968 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
34969 diagNeghbrIds.push_back(tempNeghbrId);
34970 } else {
34971 // investigate neighbor children
34972 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
34973 if(c_childId(tempNeghbrId, childId) == -1) {
34974 continue;
34975 }
34976 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
34977 }
34978 }
34979 }
34980
34981 if(a_hasNeighbor(neghbrIds[2 * dir + 1], dirOfNeghbr) > 0
34982 && checkNeighborActive(neghbrIds[2 * dir + 1], dirOfNeghbr)) {
34983 tempNeghbrId = c_neighborId(neghbrIds[2 * dir + 1], dirOfNeghbr);
34984 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
34985 diagNeghbrIds.push_back(tempNeghbrId);
34986 // cout << "found diag neighbr three"<<endl;
34987 } else {
34988 // investigate neighbor children
34989 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
34990 if(c_childId(tempNeghbrId, childId) == -1) {
34991 continue;
34992 }
34993 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
34994 }
34995 }
34996 }
34997
34998 if(a_hasNeighbor(neghbrIds[2 * dir + 1], dirOfNeghbr + 1) > 0
34999 && checkNeighborActive(neghbrIds[2 * dir + 1], dirOfNeghbr + 1)) {
35000 tempNeghbrId = c_neighborId(neghbrIds[2 * dir + 1], dirOfNeghbr + 1);
35001 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
35002 diagNeghbrIds.push_back(tempNeghbrId);
35003 } else {
35004 // investigate neighbor children
35005 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
35006 if(c_childId(tempNeghbrId, childId) == -1) {
35007 continue;
35008 }
35009 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
35010 }
35011 }
35012 }
35013 }
35014 }
35015
35016 // find all tridiagonal neighbors
35017 if(diagNeghbrIds.size() > 3) {
35018 for(MInt dir = 0; dir < 4; dir++) {
35019 if(a_hasNeighbor(diagNeghbrIds[dir], 4) > 0 && checkNeighborActive(diagNeghbrIds[dir], 4)) {
35020 tempNeghbrId = c_neighborId(diagNeghbrIds[dir], 4);
35021 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
35022 diagNeghbrIds.push_back(tempNeghbrId);
35023 } else {
35024 // investigate neighbor children
35025 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
35026 if(c_childId(tempNeghbrId, childId) == -1) {
35027 continue;
35028 }
35029 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
35030 }
35031 }
35032 }
35033
35034 if(a_hasNeighbor(diagNeghbrIds[dir], 5) > 0 && checkNeighborActive(diagNeghbrIds[dir], 5)) {
35035 tempNeghbrId = c_neighborId(diagNeghbrIds[dir], 5);
35036 if(a_hasProperty(tempNeghbrId, SolverCell::IsOnCurrentMGLevel)) {
35037 diagNeghbrIds.push_back(tempNeghbrId);
35038 } else {
35039 // investigate neighbor children
35040 for(MInt childId = 0; childId < IPOW2(nDim); childId++) {
35041 if(c_childId(tempNeghbrId, childId) == -1) {
35042 continue;
35043 }
35044 neghbrIds.push_back(c_childId(tempNeghbrId, childId));
35045 }
35046 }
35047 }
35048 }
35049 }
35050 }
35051 }
35052 }
35053 }
35054
35055 // combine the two neighbor vectors and erase elements that were found multiple times
35056 neghbrIds.insert(neghbrIds.end(), diagNeghbrIds.begin(), diagNeghbrIds.end());
35057 sort(neghbrIds.begin(), neghbrIds.end());
35058 neghbrIds.erase(unique(neghbrIds.begin(), neghbrIds.end()), neghbrIds.end());
35059 // include the actual cell after sorting to have it in the last place of the vector
35060 neghbrIds.push_back(tmpId);
35061 m_log << "done" << endl;
35062 return neghbrIds;
35063}
35064
35065
35066template <MInt nDim_, class SysEqn>
35068 std::vector<MInt> neighborList) {
35069 TRACE();
35070
35071 m_log << "Interpolate Wall Normal Point Variables ... " << endl;
35072
35073 MFloat result = -99999999.9;
35074 const MInt tmpId = localId;
35075 MFloat pointCoords[nDim];
35076 // inizialize interpolation matrix
35077 MFloatTensor LMatrix(nDim + 1, nDim + 1);
35078 MFloatTensor InverseMatrix(nDim + 1, nDim + 1);
35079
35080 LMatrix.set(0.0);
35081 InverseMatrix.set(0.0);
35082 MFloat originX = 0.0;
35083 MFloat originY = 0.0;
35084 MFloat originZ = 0.0;
35085
35086 std::vector<MInt> neghbrIds;
35087 neghbrIds.clear();
35088 neghbrIds = neighborList;
35089 const MInt noNeghbrs = neghbrIds.size();
35090
35091 // if list is to short for interpolation just return variable value
35092 if(noNeghbrs < ((nDim + 1) * 2)) {
35093 return a_pvariable(tmpId, variable);
35094 }
35095 // when the wrong list is identified, search for neighbors again
35096 if(!neghbrIds.empty() && neghbrIds.back() != tmpId) {
35097 cout << "WrongList " << endl;
35098 neghbrIds = findWallNormalNeighbors(tmpId);
35099 }
35100
35101 originX = a_coordinate(tmpId, 0);
35102 originY = a_coordinate(tmpId, 1);
35103 pointCoords[0] = coords[0];
35104 pointCoords[1] = coords[1];
35105
35106 if(nDim == 3) {
35107 originZ = a_coordinate(tmpId, 2);
35108 pointCoords[2] = coords[2];
35109 }
35110
35111 // setup interpolation matrix and vector
35112 if(tmpId != -1) {
35113 MFloat sumX = 0.0;
35114 MFloat sumY = 0.0;
35115 MFloat sumZ = 0.0;
35116 MFloat sumXY = 0.0;
35117 MFloat sumXZ = 0.0;
35118 MFloat sumYZ = 0.0;
35119 MFloat sumX2 = 0.0;
35120 MFloat sumY2 = 0.0;
35121 MFloat sumZ2 = 0.0;
35122 MFloat sumVar = 0.0;
35123 MFloat sumVarX = 0.0;
35124 MFloat sumVarY = 0.0;
35125 MFloat sumVarZ = 0.0;
35126
35127 for(MInt nId = 0; nId < noNeghbrs; nId++) {
35128 MFloat x = 0.0;
35129 MFloat y = 0.0;
35130 MFloat z = 0.0;
35131
35132 const MInt tmpNeghbrId = neghbrIds[nId];
35133 if(tmpNeghbrId < 0) {
35134 mTerm(1, "neighborId < 0 during normal point interpolation");
35135 }
35136
35137 x = a_coordinate(tmpNeghbrId, 0) - originX;
35138 y = a_coordinate(tmpNeghbrId, 1) - originY;
35139 if(nDim == 3) {
35140 z = a_coordinate(tmpNeghbrId, 2) - originZ;
35141 }
35142
35143 const MFloat var = a_pvariable(tmpNeghbrId, variable);
35144 sumX += x;
35145 sumY += y;
35146 sumZ += z;
35147 sumXY += x * y;
35148 sumXZ += x * z;
35149 sumYZ += y * z;
35150 sumX2 += x * x;
35151 sumY2 += y * y;
35152 sumZ2 += z * z;
35153 sumVar += var;
35154 sumVarX += var * x;
35155 sumVarY += var * y;
35156 sumVarZ += var * z;
35157 }
35158
35159 // fill matrix
35160 if(nDim == 2) {
35161 LMatrix(0, 0) = noNeghbrs;
35162 LMatrix(1, 1) = sumX2;
35163 LMatrix(2, 2) = sumY2;
35164
35165 LMatrix(0, 1) = LMatrix(1, 0) = sumX;
35166 LMatrix(0, 2) = LMatrix(2, 0) = sumY;
35167
35168 LMatrix(1, 2) = LMatrix(2, 1) = sumXY;
35169 } else {
35170 LMatrix(0, 0) = noNeghbrs;
35171 LMatrix(1, 1) = sumX2;
35172 LMatrix(2, 2) = sumY2;
35173 LMatrix(3, 3) = sumZ2;
35174
35175 LMatrix(0, 1) = LMatrix(1, 0) = sumX;
35176 LMatrix(0, 2) = LMatrix(2, 0) = sumY;
35177 LMatrix(0, 3) = LMatrix(3, 0) = sumZ;
35178
35179 LMatrix(1, 2) = LMatrix(2, 1) = sumXY;
35180 LMatrix(1, 3) = LMatrix(3, 1) = sumXZ;
35181
35182 LMatrix(2, 3) = LMatrix(3, 2) = sumYZ;
35183 }
35184
35185 MFloat normFactor = FPOW2(2 * a_level(tmpId)) / grid().cellLengthAtLevel(0);
35186
35187 for(MInt i = 0; i < nDim + 1; i++) {
35188 for(MInt j = 0; j < nDim + 1; j++) {
35189 LMatrix(i, j) *= normFactor;
35190 }
35191 }
35192
35193 maia::math::invert(LMatrix, InverseMatrix, nDim + 1, nDim + 1);
35194
35195
35196 // setup right hand side vector
35197 MFloat rightVector[4];
35198 MFloat coeffVector[4];
35199 std::fill_n(&rightVector[0], nDim + 1, 0.0);
35200 std::fill_n(&coeffVector[0], nDim + 1, 0.0);
35201
35202 rightVector[0] = sumVar;
35203 rightVector[1] = sumVarX;
35204 rightVector[2] = sumVarY;
35205 if(nDim == 3) {
35206 rightVector[3] = sumVarZ;
35207 }
35208
35209 for(MInt i = 0; i < nDim + 1; i++) {
35210 rightVector[i] *= normFactor;
35211 }
35212
35213 for(MInt i = 0; i < nDim + 1; i++) {
35214 for(MInt j = 0; j < nDim + 1; j++) {
35215 coeffVector[i] += InverseMatrix(i, j) * rightVector[j];
35216 }
35217 }
35218
35219 result = coeffVector[0] + coeffVector[1] * (pointCoords[0] - originX) + coeffVector[2] * (pointCoords[1] - originY);
35220 if(nDim == 3) {
35221 result += coeffVector[3] * (pointCoords[2] - originZ);
35222 }
35223 }
35224 // return interpolated variable value
35225 return result;
35226}
35227
35228
35229template <MInt nDim_, class SysEqn>
35231 TRACE();
35232
35233 const MInt noVars = PV->noVariables;
35234
35235 ScratchSpace<MInt> localNoWallNormalPoints(noDomains(), AT_, "localNoWallNormalPoints");
35236 localNoWallNormalPoints.fill(0);
35237
35238 ScratchSpace<MInt> localNoWallNormalCoords(noDomains(), AT_, "localNoWallNormalPoints");
35239 localNoWallNormalCoords.fill(0);
35240
35241 localNoWallNormalPoints[domainId()] = m_wallNormalPointCellIDs.size();
35242 localNoWallNormalCoords[domainId()] = m_wallNormalPointCoords.size();
35243
35244 MPI_Allgather(&localNoWallNormalPoints[domainId()], 1, MPI_INT, &localNoWallNormalPoints[0], 1, MPI_INT, mpiComm(),
35245 AT_, "localNoWallNormalPoints", "localNoWallNormalPoints");
35246 MPI_Allgather(&localNoWallNormalCoords[domainId()], 1, MPI_INT, &localNoWallNormalCoords[0], 1, MPI_INT, mpiComm(),
35247 AT_, "localNoWallNormalCoords", "localNoWallNormalCoords");
35248
35249 // Output vector for variables
35250 ScratchSpace<MFloat> outVariables(localNoWallNormalPoints[domainId()] * noVars, AT_, "outVariables");
35251 outVariables.fill(-99999999.9);
35252 ScratchSpace<MFloat> outVariablesTransformed(localNoWallNormalPoints[domainId()], AT_, "outVariablesTransformed");
35253 outVariablesTransformed.fill(-99999999.9);
35254
35255 for(MInt dom = 0; dom < noDomains(); dom++) {
35256 MInt noPoints = localNoWallNormalPoints[dom];
35257 MInt noCoords = localNoWallNormalCoords[dom];
35258 if(noPoints > 0) {
35259 std::vector<MInt> placement;
35260 placement.clear();
35261 std::vector<MFloat> variables;
35262 variables.clear();
35263
35264 ScratchSpace<MInt> sendDomainsBuffer(noPoints, AT_, "sendDomainsBuffer");
35265 sendDomainsBuffer.fill(-1);
35266
35267 ScratchSpace<MInt> sendLocalIdsBuffer(noPoints, AT_, "sendLocalIdsBuffer");
35268 sendLocalIdsBuffer.fill(-1);
35269
35270 ScratchSpace<MFloat> sendLocalCoordsBuffer(noCoords, AT_, "sendLocalCoordsBuffer");
35271 sendLocalCoordsBuffer.fill(0.0);
35272
35273 ScratchSpace<MInt> sendLocalNeighborsBuffer(noPoints * ((pow(3, nDim) - 1) * pow(2, nDim) + 1), AT_,
35274 "sendLocalNeighborsBuffer");
35275 sendLocalIdsBuffer.fill(-1);
35276 ScratchSpace<MInt> sendLocalNoNeighborsBuffer(noPoints, AT_, "sendLocalNoNeighborsBuffer");
35277 sendLocalIdsBuffer.fill(-1);
35278
35279
35280 ScratchSpace<MInt> allPlacements(noPoints, AT_, "allPlacements");
35281 allPlacements.fill(-1);
35282
35283 ScratchSpace<MFloat> allVariables(noPoints * noVars, AT_, "allVariables");
35284 allVariables.fill(-99999999.9);
35285
35286 // number of variables for the send/recv buffer count
35287 ScratchSpace<MInt> bufferNoVariables(noDomains(), AT_, "bufferNoVariables");
35288 bufferNoVariables.fill(0);
35289 // vairable offsets for displacement in the recombined list
35290 ScratchSpace<MInt> bufferVarsOffsets(noDomains(), AT_, "bufferVarsOffsets");
35291 bufferVarsOffsets.fill(0);
35292
35293 ScratchSpace<MInt> bufferNoPoints(noDomains(), AT_, "bufferNoPoints");
35294 bufferNoPoints.fill(0);
35295 ScratchSpace<MInt> bufferPointOffsets(noDomains(), AT_, "bufferPointOffsets");
35296 bufferPointOffsets.fill(0);
35297
35298 // copy info to the buffer
35299 if(domainId() == dom) {
35300 std::vector<MInt> localNeighbors;
35301 localNeighbors.clear();
35302 for(MInt c = 0; c < noPoints; c++) {
35303 sendDomainsBuffer[c] = m_wallNormalPointDomains[c];
35304 sendLocalIdsBuffer[c] = m_wallNormalPointCellIDs[c];
35305 sendLocalNoNeighborsBuffer[c] = m_neighborPointIds[c].size();
35306 for(MInt position = 0; position < MInt(m_neighborPointIds[c].size()); position++) {
35307 localNeighbors.push_back(m_neighborPointIds[c][position]);
35308 }
35309 }
35310 for(MInt neighbor = 0; neighbor < MInt(localNeighbors.size()); neighbor++) {
35311 sendLocalNeighborsBuffer[neighbor] = localNeighbors[neighbor];
35312 }
35313 for(MInt co = 0; co < noCoords; co++) {
35314 sendLocalCoordsBuffer[co] = m_wallNormalPointCoords[co];
35315 }
35316 }
35317
35318 MPI_Bcast(&sendDomainsBuffer[0], noPoints, MPI_INT, dom, mpiComm(), AT_, "sendDomainsBuffer");
35319 MPI_Bcast(&sendLocalIdsBuffer[0], noPoints, MPI_INT, dom, mpiComm(), AT_, "sendLocalIdsBuffer");
35320 MPI_Bcast(&sendLocalCoordsBuffer[0], noCoords, MPI_DOUBLE, dom, mpiComm(), AT_, "sendLocalCoordsBuffer");
35321 MPI_Bcast(&sendLocalNoNeighborsBuffer[0], noPoints, MPI_INT, dom, mpiComm(), AT_, "sendLocalNoNeighborsBuffer");
35322 MPI_Bcast(&sendLocalNeighborsBuffer[0], noPoints * 209, MPI_INT, dom, mpiComm(), AT_, "sendLocalNeighborsBuffer");
35323
35324 MInt count = 0;
35325 MInt count_next = 0;
35326 std::vector<std::vector<MInt>> neighborList;
35327 neighborList.clear();
35328
35329 std::vector<MInt> tempVec;
35330 tempVec.clear();
35331
35332 for(MInt k = 0; k < noPoints; k++) {
35333 count_next = count_next + sendLocalNoNeighborsBuffer[k];
35334 for(MInt j = count; j < count_next; j++) {
35335 tempVec.push_back(sendLocalNeighborsBuffer[j]);
35336 }
35337
35338 neighborList.push_back(tempVec);
35339 count = count_next;
35340 tempVec.clear();
35341 }
35342
35343
35344 for(MInt p = 0; p < noPoints; p++) {
35345 MInt originDomain = sendDomainsBuffer[p];
35346 if(originDomain == domainId()) {
35347 MInt localId = sendLocalIdsBuffer[p];
35348 placement.push_back(p);
35349
35350 MFloat localCoords[nDim];
35351 localCoords[0] = sendLocalCoordsBuffer[nDim * p];
35352 localCoords[1] = sendLocalCoordsBuffer[nDim * p + 1];
35353 if(nDim == 3) {
35354 localCoords[2] = sendLocalCoordsBuffer[nDim * p + 2];
35355 }
35356
35357
35358 for(MInt v = 0; v < noVars; v++) {
35359 // get primitive variables and add them to variable list
35360 MFloat var = a_pvariable(localId, v);
35361 MFloat interpolatedVar = interpolateWallNormalPointVars(v, localCoords, localId, neighborList[p]);
35362 if(m_useWallNormalInterpolation) {
35363 variables.push_back(interpolatedVar);
35364 } else {
35365 variables.push_back(var);
35366 }
35367 }
35368 }
35369 }
35370
35371 bufferNoVariables[domainId()] = variables.size() * 2;
35372 bufferNoPoints[domainId()] = placement.size();
35373
35374
35375 MPI_Allgather(&bufferNoVariables[domainId()], 1, MPI_INT, &bufferNoVariables[0], 1, MPI_INT, mpiComm(), AT_,
35376 "bufferNoVariables", "bufferNoVariables");
35377
35378 MPI_Allgather(&bufferNoPoints[domainId()], 1, MPI_INT, &bufferNoPoints[0], 1, MPI_INT, mpiComm(), AT_,
35379 "bufferNoPoints", "bufferNoPoints");
35380
35381 for(MInt d = 0; d < noDomains(); d++) {
35382 if(d > 0) {
35383 bufferVarsOffsets[d] = bufferVarsOffsets[d - 1] + bufferNoVariables[d - 1];
35384 bufferPointOffsets[d] = bufferPointOffsets[d - 1] + bufferNoPoints[d - 1];
35385 }
35386 }
35387
35388 MPI_Gatherv(&placement[0], bufferNoPoints[domainId()], MPI_INT, &allPlacements[0], &bufferNoPoints[0],
35389 &bufferPointOffsets[0], MPI_INT, dom, mpiComm(), AT_, "placement", "allPlacements");
35390
35391 MPI_Gatherv(&variables[0], bufferNoVariables[domainId()], MPI_FLOAT, &allVariables[0], &bufferNoVariables[0],
35392 &bufferVarsOffsets[0], MPI_FLOAT, dom, mpiComm(), AT_, "variables", "allVariables");
35393
35394 // copy all the info into correct order into output vectors
35395 if(domainId() == dom) {
35396 for(MInt c = 0; c < noPoints; c++) {
35397 MInt p = allPlacements[c];
35398 if(p != -1) {
35399 for(MInt v = 0; v < noVars; v++) {
35400 outVariables[p * noVars + v] = allVariables[c * noVars + v];
35401 }
35402 }
35403 }
35404 }
35405 }
35406 }
35407
35408 if(domainId() == 0) {
35409 MString interpolated = "";
35410 if(m_useWallNormalInterpolation) {
35411 interpolated = "interpolated";
35412 }
35413 cerr << "Writing " << interpolated << " NETCDF wallNormalData at time step " << globalTimeStep << " ... ";
35414 }
35415
35416 //-------------TRANSFORMATION
35417
35418 MFloat nx = 0;
35419 MFloat ny = 0;
35420 MFloat u = 0;
35421 MFloat v = 0;
35422 MInt n = 0;
35423 MFloat ut = 0;
35424
35425 for(MInt p = 0; p < localNoWallNormalPoints[domainId()]; p++) {
35426 if((p % m_normalNoPoints) == 0) {
35427 nx = m_wallNormalVectors[n * 2];
35428 ny = m_wallNormalVectors[n * 2 + 1];
35429 n++;
35430 }
35431
35432 u = outVariables[p * noVars];
35433 v = outVariables[p * noVars + 1];
35434
35435 MFloat tg1 = 0;
35436 MFloat tg2 = 0;
35437 if(ny >= 0) {
35438 tg1 = (nx * cos((3 * PI) / 2) - ny * sin((3 * PI) / 2));
35439 tg2 = (nx * sin((3 * PI) / 2) + ny * cos((3 * PI) / 2));
35440 } else if(ny < 0) {
35441 tg1 = (nx * cos(PI / 2) - ny * sin(PI / 2));
35442 tg2 = (nx * sin(PI / 2) + ny * cos(PI / 2));
35443 }
35444
35445 ut = u * tg1 + v * tg2;
35446
35447 outVariablesTransformed[p] = ut;
35448 }
35449
35450 //-------------OUTPUT
35451
35452 using namespace maia::parallel_io;
35453 MString dataFileName;
35454
35455 if(m_useWallNormalInterpolation) {
35456 dataFileName = outputDir() + "/pp_normals/interpolatedWallNormalData_" + to_string(globalTimeStep) + ".Netcdf";
35457 } else {
35458 dataFileName = outputDir() + "/pp_normals/wallNormalData_" + to_string(globalTimeStep) + ".Netcdf";
35459 }
35460
35461 ParallelIo parallelIo(dataFileName, PIO_REPLACE, mpiComm());
35462
35463 MInt localNoNormalPoints = m_wallNormalPointCoords.size() / nDim;
35464
35465 MInt workaround = 0;
35466 if(localNoNormalPoints == 0) {
35467 workaround++;
35468 }
35469
35470 ParallelIo::size_type pointOffset;
35471 ParallelIo::size_type globalNoPoints;
35472
35473 ParallelIo::size_type normalOffset;
35474 ParallelIo::size_type globalNoNormals;
35475
35476 parallelIo.calcOffset(localNoNormalPoints, &pointOffset, &globalNoPoints, mpiComm());
35477 parallelIo.calcOffset(m_noWallNormals, &normalOffset, &globalNoNormals, mpiComm());
35478
35479 parallelIo.defineScalar(PIO_INT, "points_per_normal");
35480 parallelIo.defineScalar(PIO_FLOAT, "normal_length");
35481 parallelIo.defineScalar(PIO_FLOAT, "segment_length");
35482
35483 parallelIo.defineArray(PIO_FLOAT, "originCoordX", globalNoNormals);
35484 parallelIo.defineArray(PIO_FLOAT, "originCoordZ", globalNoNormals);
35485 parallelIo.defineArray(PIO_INT, "originSide", globalNoNormals);
35486
35487 parallelIo.defineArray(PIO_FLOAT, "coordinate_x", globalNoPoints);
35488 parallelIo.defineArray(PIO_FLOAT, "coordinate_y", globalNoPoints);
35489 if(nDim == 3) {
35490 parallelIo.defineArray(PIO_FLOAT, "coordinate_z", globalNoPoints);
35491 }
35492
35493 parallelIo.defineArray(PIO_FLOAT, "variable_U_t", globalNoPoints);
35494
35495 parallelIo.defineArray(PIO_FLOAT, "variable_rho", globalNoPoints);
35496 parallelIo.defineArray(PIO_FLOAT, "variable_p", globalNoPoints);
35497
35498 MFloat segmentLength = m_normalLength / (m_normalNoPoints - 1);
35499
35500 parallelIo.writeScalar(m_normalNoPoints, "points_per_normal");
35501 parallelIo.writeScalar(m_normalLength, "normal_length");
35502 parallelIo.writeScalar(segmentLength, "segment_length");
35503
35504 if(workaround == 0) {
35505 parallelIo.setOffset(localNoNormalPoints, pointOffset);
35506
35507 parallelIo.writeArray(&m_wallNormalPointCoords[0], "coordinate_x", nDim);
35508 parallelIo.writeArray(&m_wallNormalPointCoords[1], "coordinate_y", nDim);
35509 if(nDim == 3) {
35510 parallelIo.writeArray(&m_wallNormalPointCoords[2], "coordinate_z", nDim);
35511 }
35512
35513 parallelIo.writeArray(&outVariablesTransformed[0], "variable_U_t", 1);
35514
35515 if(nDim == 2) {
35516 parallelIo.writeArray(&outVariables[2], "variable_rho", noVars);
35517 parallelIo.writeArray(&outVariables[3], "variable_p", noVars);
35518 } else {
35519 parallelIo.writeArray(&outVariables[3], "variable_rho", noVars);
35520 parallelIo.writeArray(&outVariables[4], "variable_p", noVars);
35521 }
35522
35523 parallelIo.setOffset(m_noWallNormals, normalOffset);
35524
35525 parallelIo.writeArray(&m_wallSetupOrigin[0], "originCoordX", 2);
35526 parallelIo.writeArray(&m_wallSetupOrigin[1], "originCoordZ", 2);
35527 parallelIo.writeArray(&m_wallSetupOriginSide[0], "originSide", 1);
35528
35529 } else {
35530 parallelIo.setOffset(localNoNormalPoints, pointOffset);
35531 parallelIo.writeArray(&workaround, "coordinate_x", 1);
35532 parallelIo.writeArray(&workaround, "coordinate_y", 1);
35533
35534 if(nDim == 3) {
35535 parallelIo.writeArray(&workaround, "coordinate_z", 1);
35536 }
35537
35538 parallelIo.writeArray(&workaround, "variable_U_t", 1);
35539
35540 parallelIo.writeArray(&workaround, "variable_rho", 1);
35541 parallelIo.writeArray(&workaround, "variable_p", 1);
35542
35543 parallelIo.setOffset(m_noWallNormals, normalOffset);
35544
35545 parallelIo.writeArray(&workaround, "originCoordX", 1);
35546 parallelIo.writeArray(&workaround, "originCoordZ", 1);
35547 parallelIo.writeArray(&workaround, "originSide", 1);
35548 }
35549
35550 //----------------------------------
35551
35552 if(domainId() == 0) {
35553 cerr << "ok" << endl;
35554 }
35555}
35556
35557
35559template <MInt nDim_, class SysEqn>
35561 std::ofstream logfile;
35562 logfile.open(name + "_" + std::to_string(domainId()));
35563
35564 // All cells
35565 for(MInt cellId = 0; cellId < a_noCells(); cellId++) {
35566 logfile << cellId << " g" << c_globalId(cellId);
35567 logfile << " " << a_properties(cellId);
35568 logfile << " bnd" << a_bndryId(cellId) << std::endl;
35569 }
35570 logfile << std::endl;
35571
35572 // Bndry cells
35573 const MInt noBndryCells = m_bndryCells->size();
35574 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
35575 MInt cellId = m_bndryCells->a[bndryId].m_cellId;
35576
35577 logfile << "b" << bndryId << " g" << c_globalId(cellId) << " " << cellId << " " << a_bndryId(cellId) << " leaf"
35578 << c_isLeafCell(cellId) << " halo" << a_isHalo(cellId) << " " << a_properties(cellId) << std::endl;
35579 }
35580}
35581
35586template <MInt nDim, class SysEqn>
35588 TRACE();
35589
35590 if(grid().noAzimuthalNeighborDomains() == 0) return;
35591
35592 MUint sndSize = maia::mpi::getBufferSize(grid().azimuthalHaloCells());
35593 MFloatScratchSpace haloBuff(sndSize * nDim, AT_, "haloBuff");
35594 haloBuff.fill(0);
35595 MUint rcvSize = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
35596 MFloatScratchSpace windowBuff(rcvSize * nDim, AT_, "windowBuff");
35597 windowBuff.fill(0);
35598
35599 this->m_azimuthalCartRecCoord.clear();
35600 this->m_azimuthalCartRecCoord.resize(rcvSize * nDim);
35601 MFloat angle = grid().azimuthalAngle();
35602
35603 // Get azimuthal image coordinate
35604 MInt sndCnt = 0;
35605 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35606 for(MInt j = 0; j < grid().noAzimuthalHaloCells(i); j++) {
35607 MInt cellId = grid().azimuthalHaloCell(i, j);
35608 ASSERT(a_isPeriodic(cellId), "azimuthal halo is not isPeriodic!");
35609
35610 MFloat recCoord[3];
35611 for(MInt d = 0; d < nDim; d++) {
35612 recCoord[d] = c_coordinate(cellId, d);
35613 }
35614
35615 MInt side = grid().determineAzimuthalBoundarySide(recCoord);
35616
35617 grid().rotateCartesianCoordinates(recCoord, (side * angle));
35618
35619 ASSERT(!cellOutside(cellId), "Halo outside!");
35620
35621 for(MInt d = 0; d < nDim; d++) {
35622 haloBuff[sndCnt++] = recCoord[d];
35623 }
35624 }
35625 }
35626
35627 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), grid().azimuthalWindowCells(),
35628 grid().azimuthalHaloCells(), mpiComm(), haloBuff.getPointer(), windowBuff.getPointer(),
35629 nDim);
35630
35631 MInt rcvCnt = 0;
35632 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35633 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
35634 for(MInt d = 0; d < nDim; d++) {
35635 this->m_azimuthalCartRecCoord[rcvCnt] = windowBuff[rcvCnt];
35636 rcvCnt++;
35637 }
35638#ifndef NDEBUG
35639 MFloat point[nDim];
35640 for(MInt d = 0; d < nDim; d++) {
35641 point[d] = this->m_azimuthalCartRecCoord[rcvCnt - nDim + d];
35642 }
35643 if(!this->inCell(grid().azimuthalWindowCell(i, j), point, F1 + pow(10, -12))) {
35644 mTerm(1, AT_, "Point not inside");
35645 }
35646#endif
35647 }
35648 }
35649}
35650
35651
35654template <MInt nDim, class SysEqn>
35656 TRACE();
35657
35658 if(domainId() == 0) {
35659 cerr << "Init Azimuthal Reconstruction...";
35660 }
35661
35662 m_planeInterp = false;
35663 m_planeInterp = Context::getSolverProperty<MBool>("planeInterp", m_solverId, AT_, &m_planeInterp);
35664 ASSERT(!m_planeInterp, "m_planeInterp is untested");
35665
35666 MBool noInterp = Context::getSolverProperty<MBool>("noInterp", m_solverId, AT_);
35667 if(noInterp && grid().noAzimuthalUnmappedHaloCells()) mTerm(1, AT_ "Grid not symmetric!");
35668
35669 MFloat recCoord[nDim];
35670 MFloat angle = grid().azimuthalAngle();
35671
35672 // First the unmapped halos are handled.
35673 MIntScratchSpace sndSize(grid().noAzimuthalNeighborDomains(), AT_, "sndSize");
35674 sndSize.fill(0);
35675 MInt sndSizeTotal = 0;
35676 for(MInt i = 0; i < grid().noAzimuthalUnmappedHaloCells(); i++) {
35677 MInt cellId = grid().azimuthalUnmappedHaloCell(i);
35678 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
35679 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
35680 if(a_bndryId(cellId) < 0) continue;
35681 MInt dom = grid().azimuthalDomainIndex(grid().azimuthalUnmappedHaloDomain(i));
35682 sndSize[dom]++;
35683 sndSizeTotal++;
35684 }
35685
35686 MIntScratchSpace rcvSize(grid().noAzimuthalNeighborDomains(), AT_, "rcvSize");
35687 ScratchSpace<MPI_Request> sndReq(grid().noAzimuthalNeighborDomains(), AT_, "sndReq");
35688 ScratchSpace<MPI_Request> rcvReq(grid().noAzimuthalNeighborDomains(), AT_, "rcvReq");
35689 sndReq.fill(MPI_REQUEST_NULL);
35690 rcvReq.fill(MPI_REQUEST_NULL);
35691
35692 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35693 MPI_Isend(&sndSize[i], 1, MPI_INT, grid().azimuthalNeighborDomain(i), 9, mpiComm(), &sndReq[i], AT_, "sndSize[i]");
35694 }
35695 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35696 MPI_Recv(&rcvSize[i], 1, MPI_INT, grid().azimuthalNeighborDomain(i), 9, mpiComm(), MPI_STATUS_IGNORE, AT_,
35697 "rcvSize[i]");
35698 }
35699 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35700 MPI_Wait(&sndReq[i], MPI_STATUSES_IGNORE, AT_);
35701 }
35702
35703 MInt rcvSizeTotal = 0;
35704 MIntScratchSpace sndOffsets(grid().noAzimuthalNeighborDomains() + 1, AT_, "sndOffsets");
35705 MIntScratchSpace rcvOffsets(grid().noAzimuthalNeighborDomains() + 1, AT_, "rcvOffsets");
35706 sndOffsets[0] = 0;
35707 rcvOffsets[0] = 0;
35708 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35709 rcvSizeTotal += rcvSize[i];
35710 rcvOffsets[i + 1] = rcvOffsets[i] + rcvSize[i];
35711
35712 sndOffsets[i + 1] = sndOffsets[i] + sndSize[i];
35713 sndSize[i] = 0;
35714 }
35715
35716 MFloatScratchSpace sndBuff(sndSizeTotal * (nDim + 1), AT_, "sndBuff");
35717 MFloatScratchSpace rcvBuff(rcvSizeTotal * (nDim + 1), AT_, "rcvBuff");
35718
35719 for(MInt i = 0; i < grid().noAzimuthalUnmappedHaloCells(); i++) {
35720 MInt cellId = grid().azimuthalUnmappedHaloCell(i);
35721 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
35722 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
35723 if(a_bndryId(cellId) < 0) continue;
35724
35725 if(a_bndryId(cellId) < 0) {
35726 cerr << "D:" << domainId() << " " << cellId << "/" << c_globalId(cellId) << " "
35727 << grid().azimuthalUnmappedHaloDomain(i) << " " << grid().tree().solver2grid(cellId) << "/"
35728 << c_globalId(grid().tree().solver2grid(cellId));
35729 if(c_parentId(cellId) > -1) {
35730 cerr << " " << grid().tree().solver2grid(c_parentId(cellId)) << "/"
35731 << c_globalId(grid().tree().solver2grid(c_parentId(cellId)));
35732 }
35733 cerr << " " << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, 2) << " "
35734 << a_hasProperty(cellId, SolverCell::IsInactive) << " level: " << a_level(cellId) << endl;
35735 mTerm(1, AT_, "Unmapped halo which is not bndryCell?");
35736 }
35737
35738 MInt dom = grid().azimuthalDomainIndex(grid().azimuthalUnmappedHaloDomain(i));
35739
35740 MInt side = grid().determineAzimuthalBoundarySide(&a_coordinate(cellId, 0));
35741
35742 for(MInt d = 0; d < nDim; d++) {
35743 recCoord[d] = a_coordinate(cellId, d);
35744 }
35745 grid().rotateCartesianCoordinates(recCoord, (side * angle));
35746
35747 for(MInt d = 0; d < nDim; d++) {
35748 sndBuff[sndOffsets[dom] * (nDim + 1) + sndSize[dom] * (nDim + 1) + d] = recCoord[d];
35749 }
35750 sndBuff[sndOffsets[dom] * (nDim + 1) + sndSize[dom] * (nDim + 1) + nDim] = (MFloat)side;
35751
35752 sndSize[dom]++;
35753 }
35754
35755 sndReq.fill(MPI_REQUEST_NULL);
35756 rcvReq.fill(MPI_REQUEST_NULL);
35757
35758 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35759 if(sndSize[i] <= 0) continue;
35760 MPI_Isend(&sndBuff[sndOffsets[i] * (nDim + 1)], sndSize[i] * (nDim + 1), maia::type_traits<MFloat>::mpiType(),
35761 grid().azimuthalNeighborDomain(i), 13, mpiComm(), &sndReq[i], AT_, "sndBuff[sndOffsets[i]*(nDim+1)]");
35762 }
35763
35764 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35765 if(rcvSize[i] <= 0) continue;
35766 MPI_Recv(&rcvBuff[rcvOffsets[i] * (nDim + 1)], rcvSize[i] * (nDim + 1), maia::type_traits<MFloat>::mpiType(),
35767 grid().azimuthalNeighborDomain(i), 13, mpiComm(), MPI_STATUS_IGNORE, AT_,
35768 "rcvBuff[rcvOffsets[i]*(nDim+1)]");
35769 }
35770
35771 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35772 if(sndSize[i] <= 0) continue;
35773 MPI_Wait(&sndReq[i], MPI_STATUSES_IGNORE, AT_);
35774 }
35775
35776
35777 MIntScratchSpace nghbrList(m_maxNoAzimuthalRecConst, AT_, "nghbrList");
35778 set<MInt> nearBndryCells;
35779 const MInt noBndryCells = m_fvBndryCnd->m_bndryCells->size();
35780 for(MInt bndryId = 0; bndryId < noBndryCells; bndryId++) {
35781 MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
35782 if(!a_isHalo(cellId)) {
35783 nearBndryCells.insert(cellId);
35784 }
35785 MInt counter = grid().getAdjacentGridCells(cellId, 1, nghbrList, a_level(cellId), 0);
35786 for(MInt n = 0; n < counter; n++) {
35787 MInt nghbrId = nghbrList[n];
35788 if(!a_isHalo(nghbrId)) {
35789 nearBndryCells.insert(nghbrId);
35790 }
35791 }
35792 }
35793
35794 MUint rcvCnt = 0;
35795 MUint sndCnt = 0;
35796 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35797 for(MInt j = 0; j < rcvSize[i]; j++) {
35798 for(MInt d = 0; d < nDim; d++) {
35799 recCoord[d] = rcvBuff[rcvCnt++];
35800 }
35801 MInt side = (MInt)rcvBuff[rcvCnt++];
35802
35803 MInt actualDom = domainId();
35804
35805 // Find containing cell
35806 MInt cellId = -1;
35807 for(MInt e = -12; e < 0; e++) {
35808 MFloat eps = F1 + pow(10, e);
35809 for(auto it = nearBndryCells.begin(); it != nearBndryCells.end(); ++it) {
35810 MInt bndryCell = *it;
35811
35812 if(this->inCell(bndryCell, recCoord, eps)) {
35813 // bndryCells already on max level
35814 cellId = bndryCell;
35815 break;
35816 }
35817 }
35818
35819 if(cellId < 0) {
35820 // Search in halo cells
35821 for(MInt n = 0; n < noNeighborDomains(); n++) {
35822 for(MInt c = 0; c < noHaloCells(n); c++) {
35823 if(!c_isLeafCell(haloCellId(n, c))) continue;
35824 if(this->inCell(haloCellId(n, c), recCoord, eps)) {
35825 cellId = haloCellId(n, c);
35826 actualDom = neighborDomain(n);
35827 break;
35828 }
35829 }
35830 }
35831 }
35832 if(cellId > -1) break;
35833 }
35834
35835 if(cellId < 0) {
35836 MFloat dummyCoord[3];
35837 std::copy_n(&recCoord[0], nDim, &dummyCoord[0]);
35838 grid().rotateCartesianCoordinates(dummyCoord, (-side * angle));
35839 cerr << "D:" << domainId() << " " << grid().azimuthalNeighborDomain(i) << " " << j << " " << recCoord[0] << " "
35840 << recCoord[1] << " " << recCoord[nDim - 1] << " " << dummyCoord[0] << " " << dummyCoord[1] << " "
35841 << dummyCoord[nDim - 1] << endl;
35842 mTerm(1, AT_, "No containing window found!");
35843 }
35844
35845 rcvBuff[rcvOffsets[i] + j] = actualDom;
35846 }
35847 }
35848
35849 sndReq.fill(MPI_REQUEST_NULL);
35850 rcvReq.fill(MPI_REQUEST_NULL);
35851
35852 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35853 if(rcvSize[i] <= 0) continue;
35854 MPI_Isend(&rcvBuff[rcvOffsets[i]], rcvSize[i], maia::type_traits<MFloat>::mpiType(),
35855 grid().azimuthalNeighborDomain(i), 13, mpiComm(), &sndReq[i], AT_, "rcvBuff[rcvOffsets[i]]");
35856 }
35857
35858 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35859 if(sndSize[i] <= 0) continue;
35860 MPI_Recv(&sndBuff[sndOffsets[i]], sndSize[i], maia::type_traits<MFloat>::mpiType(),
35861 grid().azimuthalNeighborDomain(i), 13, mpiComm(), MPI_STATUS_IGNORE, AT_, "sndBuff[sndOffsets[i]]");
35862 }
35863
35864 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35865 if(rcvSize[i] <= 0) continue;
35866 MPI_Wait(&sndReq[i], MPI_STATUSES_IGNORE, AT_);
35867 }
35868
35869 sndSize.fill(0);
35870 MInt sndSizeTotalG = 0;
35871 MIntScratchSpace sndSizeG(noDomains(), AT_, "sndSizeG");
35872 sndSizeG.fill(0);
35873 MIntScratchSpace azimuthalUnmappedDomains(grid().noAzimuthalUnmappedHaloCells(), AT_, "azimuthalUnmappedDomains");
35874 azimuthalUnmappedDomains.fill(-1);
35875
35876 for(MInt i = 0; i < grid().noAzimuthalUnmappedHaloCells(); i++) {
35877 MInt cellId = grid().azimuthalUnmappedHaloCell(i);
35878 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
35879 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
35880 if(a_bndryId(cellId) < 0) continue;
35881
35882 MInt assumedDomainIndex = grid().azimuthalDomainIndex(grid().azimuthalUnmappedHaloDomain(i));
35883 MInt actualDomain = sndBuff[sndOffsets[assumedDomainIndex] + sndSize[assumedDomainIndex]];
35884 sndSize[assumedDomainIndex]++;
35885
35886 sndSizeG[actualDomain]++;
35887 sndSizeTotalG++;
35888
35889 azimuthalUnmappedDomains[i] = actualDomain;
35890 }
35891
35892 MIntScratchSpace rcvSizeG(noDomains(), AT_, "rcvSizeG");
35893 rcvSizeG.fill(0);
35894 ScratchSpace<MPI_Request> sndReqG(noDomains(), AT_, "sndReqG");
35895 ScratchSpace<MPI_Request> rcvReqG(noDomains(), AT_, "rcvReqG");
35896 sndReqG.fill(MPI_REQUEST_NULL);
35897 rcvReqG.fill(MPI_REQUEST_NULL);
35898
35899 for(MInt i = 0; i < noDomains(); i++) {
35900 MPI_Isend(&sndSizeG[i], 1, MPI_INT, i, 9, mpiComm(), &sndReqG[i], AT_, "sndSizeG[i]");
35901 }
35902 for(MInt i = 0; i < grid().noDomains(); i++) {
35903 MPI_Recv(&rcvSizeG[i], 1, MPI_INT, i, 9, mpiComm(), MPI_STATUS_IGNORE, AT_, "rcvSizeG[i]");
35904 }
35905 MPI_Waitall(noDomains(), &sndReqG[0], MPI_STATUSES_IGNORE, AT_);
35906
35907 MInt noAzimuthalRemappedNeighborDoms = 0;
35908 MInt rcvSizeTotalG = 0;
35909 for(MInt i = 0; i < noDomains(); i++) {
35910 rcvSizeTotalG += rcvSizeG[i];
35911 if(rcvSizeG[i] > 0 || sndSizeG[i] > 0) noAzimuthalRemappedNeighborDoms++;
35912 }
35913
35914 m_azimuthalRemappedNeighborDomains.resize(noAzimuthalRemappedNeighborDoms);
35915 m_azimuthalRemappedNeighborsDomainIndex.assign(noDomains(), -1);
35916 m_azimuthalRemappedWindowCells.resize(noAzimuthalRemappedNeighborDoms);
35917 m_azimuthalRemappedHaloCells.resize(noAzimuthalRemappedNeighborDoms);
35918 MIntScratchSpace sndOffsetsG(noAzimuthalRemappedNeighborDoms + 1, AT_, "sndOffsetsG");
35919 MIntScratchSpace rcvOffsetsG(noAzimuthalRemappedNeighborDoms + 1, AT_, "rcvOffsetsG");
35920 sndOffsetsG[0] = 0;
35921 rcvOffsetsG[0] = 0;
35922 MInt cnt = 0;
35923 for(MInt i = 0; i < noDomains(); i++) {
35924 if(rcvSizeG[i] > 0 || sndSizeG[i] > 0) {
35925 m_azimuthalRemappedNeighborDomains[cnt] = i;
35926 m_azimuthalRemappedNeighborsDomainIndex[i] = cnt;
35927 m_azimuthalRemappedHaloCells[cnt].resize(sndSizeG[i]);
35928 m_azimuthalRemappedWindowCells[cnt].resize(rcvSizeG[i]);
35929 rcvOffsetsG[cnt + 1] = rcvOffsetsG[cnt] + rcvSizeG[i];
35930 sndOffsetsG[cnt + 1] = sndOffsetsG[cnt] + sndSizeG[i];
35931
35932 rcvSizeG[cnt] = rcvSizeG[i];
35933 cnt++;
35934 }
35935 sndSizeG[i] = 0;
35936 // rcvSizeG[i] = 0;
35937 }
35938
35939 // Now the regular azimuthal window halos cells are handled
35940 sndCnt = maia::mpi::getBufferSize(grid().azimuthalHaloCells());
35941 sndCnt += sndSizeTotalG;
35942 MFloatScratchSpace haloBuff(sndCnt * (nDim + 1), AT_, "haloBuff");
35943 haloBuff.fill(0);
35944 rcvCnt = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
35945 rcvCnt += rcvSizeTotalG;
35946 MFloatScratchSpace windowBuff(rcvCnt * (nDim + 1), AT_, "windowBuff");
35947 windowBuff.fill(0);
35948
35949 m_noAzimuthalReconstNghbrs.clear();
35950 m_noAzimuthalReconstNghbrs.assign(rcvCnt, 0);
35951 m_azimuthalCutRecCoord.clear();
35952 m_azimuthalCutRecCoord.assign(rcvCnt * nDim, F0);
35953 m_azimuthalRecConsts.clear();
35954 m_azimuthalRecConsts.assign(rcvCnt * m_maxNoAzimuthalRecConst, F0);
35955 m_azimuthalReconstNghbrIds.clear();
35956 m_azimuthalReconstNghbrIds.assign(rcvCnt * m_maxNoAzimuthalRecConst, -1);
35957 m_azimuthalBndrySide.assign(rcvCnt, 0);
35958
35959 // Get azimuthal image coordinate
35960 sndCnt = 0;
35961 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
35962 for(MInt j = 0; j < grid().noAzimuthalHaloCells(i); j++) {
35963 MInt cellId = grid().azimuthalHaloCell(i, j);
35964 ASSERT(a_isPeriodic(cellId), "azimuthal halo is not isPeriodic!");
35965 ASSERT(!cellOutside(cellId), "Halo outside!");
35966
35967 MInt side = grid().determineAzimuthalBoundarySide(&a_coordinate(cellId, 0));
35968
35969 for(MInt d = 0; d < nDim; d++) {
35970 recCoord[d] = a_coordinate(cellId, d);
35971 }
35972
35973 if(!(!m_geometry->pointIsInside(recCoord) || c_noChildren(cellId) > 0
35974 || a_hasProperty(cellId, SolverCell::IsInactive))) {
35975 cerr << "O:" << domainId() << " " << cellId << "/" << c_globalId(cellId) << " " << c_coordinate(cellId, 0)
35976 << " " << c_coordinate(cellId, 1) << " " << c_coordinate(cellId, 2) << " " << a_coordinate(cellId, 0)
35977 << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, 2) << " " << a_level(cellId) << " "
35978 << m_geometry->pointIsInside(recCoord) << " " << c_noChildren(cellId) << " "
35979 << a_hasProperty(cellId, SolverCell::IsInactive) << " " << recCoord[0] << " " << recCoord[1] << " "
35980 << recCoord[nDim - 1] << endl;
35981 }
35982 // ASSERT(!m_geometry->pointIsInside(recCoord) || c_noChildren(cellId) > 0 || a_hasProperty(cellId,
35983 // SolverCell::IsInactive), "Rec coord outside!");
35984
35985 grid().rotateCartesianCoordinates(recCoord, (side * angle));
35986
35987 for(MInt d = 0; d < nDim; d++) {
35988 haloBuff[sndCnt++] = recCoord[d];
35989 }
35990 haloBuff[sndCnt++] = (MFloat)side;
35991 }
35992 }
35993
35994 if(grid().noAzimuthalNeighborDomains() > 0) {
35995 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), grid().azimuthalWindowCells(),
35996 grid().azimuthalHaloCells(), mpiComm(), haloBuff.getPointer(), windowBuff.getPointer(),
35997 nDim + 1);
35998 }
35999
36000 rcvCnt = 0;
36001 MInt offset = 0;
36002 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36003 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
36004 for(MInt d = 0; d < nDim; d++) {
36005 recCoord[d] = windowBuff[rcvCnt++];
36006 }
36007
36008 for(MInt d = 0; d < nDim; d++) {
36009 m_azimuthalCutRecCoord[offset * nDim + d] = recCoord[d];
36010 }
36011
36012 MInt side = (MInt)windowBuff[rcvCnt++];
36013 m_azimuthalBndrySide[offset] = side;
36014
36015 offset++;
36016 }
36017 }
36018
36019 // Unmapped halos part 2
36020 MFloatScratchSpace sndBuffG(sndSizeTotalG * (nDim + 1), AT_, "sndBuffG");
36021 MFloatScratchSpace rcvBuffG(rcvSizeTotalG * (nDim + 1), AT_, "rcvBuffG");
36022 for(MInt i = 0; i < grid().noAzimuthalUnmappedHaloCells(); i++) {
36023 MInt cellId = grid().azimuthalUnmappedHaloCell(i);
36024 if(!a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) continue;
36025 if(a_hasProperty(cellId, SolverCell::IsInactive)) continue;
36026 if(a_bndryId(cellId) < 0) continue;
36027
36028 MInt actualDomain = azimuthalUnmappedDomains[i];
36029 MInt dom = m_azimuthalRemappedNeighborsDomainIndex[actualDomain];
36030 m_azimuthalRemappedHaloCells[dom][sndSizeG[dom]] = cellId;
36031
36032 MInt side = grid().determineAzimuthalBoundarySide(&a_coordinate(cellId, 0));
36033
36034 for(MInt d = 0; d < nDim; d++) {
36035 recCoord[d] = a_coordinate(cellId, d);
36036 }
36037 grid().rotateCartesianCoordinates(recCoord, (side * angle));
36038
36039 for(MInt d = 0; d < nDim; d++) {
36040 sndBuffG[sndOffsetsG[dom] * (nDim + 1) + sndSizeG[dom] * (nDim + 1) + d] = recCoord[d];
36041 }
36042 sndBuffG[sndOffsetsG[dom] * (nDim + 1) + sndSizeG[dom] * (nDim + 1) + nDim] = (MFloat)side;
36043 sndSizeG[dom]++;
36044 }
36045
36046 sndReqG.fill(MPI_REQUEST_NULL);
36047 rcvReqG.fill(MPI_REQUEST_NULL);
36048
36049 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36050 if(sndSizeG[i] <= 0) continue;
36051 MPI_Isend(&sndBuffG[sndOffsetsG[i] * (nDim + 1)], sndSizeG[i] * (nDim + 1), maia::type_traits<MFloat>::mpiType(),
36052 m_azimuthalRemappedNeighborDomains[i], 13, mpiComm(), &sndReqG[i], AT_,
36053 "sndBuffG[sndOffsetsG[i]*(nDim+1)]");
36054 }
36055
36056 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36057 if(rcvSizeG[i] <= 0) continue;
36058 MPI_Recv(&rcvBuffG[rcvOffsetsG[i] * (nDim + 1)], rcvSizeG[i] * (nDim + 1), maia::type_traits<MFloat>::mpiType(),
36059 m_azimuthalRemappedNeighborDomains[i], 13, mpiComm(), MPI_STATUS_IGNORE, AT_,
36060 "rcvBuffG[rcvOffsetsG[i]*(nDim+1)]");
36061 }
36062
36063 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36064 if(sndSizeG[i] <= 0) continue;
36065 MPI_Wait(&sndReqG[i], MPI_STATUSES_IGNORE, AT_);
36066 }
36067
36068
36069 rcvCnt = 0;
36070 sndCnt = 0;
36071 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36072 for(MInt j = 0; j < rcvSizeG[i]; j++) {
36073 for(MInt d = 0; d < nDim; d++) {
36074 recCoord[d] = rcvBuffG[rcvCnt++];
36075 }
36076 MInt side = (MInt)rcvBuffG[rcvCnt++];
36077
36078 // Find containing cell
36079 MInt cellId = -1;
36080 for(MInt e = -12; e < 0; e++) {
36081 MFloat eps = F1 + pow(10, e);
36082 for(auto it = nearBndryCells.begin(); it != nearBndryCells.end(); ++it) {
36083 MInt bndryCell = *it;
36084
36085 if(this->inCell(bndryCell, recCoord, eps)) {
36086 // bndryCells already on max level
36087 cellId = bndryCell;
36088 break;
36089 }
36090 }
36091 if(cellId > -1) break;
36092 }
36093 if(cellId < 0) {
36094 MFloat dummyCoord[3];
36095 std::copy_n(&recCoord[0], nDim, &dummyCoord[0]);
36096 grid().rotateCartesianCoordinates(dummyCoord, (-side * angle));
36097 cerr << "D:" << domainId() << " " << m_azimuthalRemappedNeighborDomains[i] << " " << j << " " << rcvSizeG[i]
36098 << " " << recCoord[0] << " " << recCoord[1] << " " << recCoord[nDim - 1] << " " << dummyCoord[0] << " "
36099 << dummyCoord[1] << " " << dummyCoord[nDim - 1] << endl;
36100 mTerm(1, AT_, "No containing window found!");
36101 }
36102
36103 m_azimuthalRemappedWindowCells[i][j] = cellId;
36104
36105 for(MInt d = 0; d < nDim; d++) {
36106 m_azimuthalCutRecCoord[offset * nDim + d] = recCoord[d];
36107 }
36108 m_azimuthalBndrySide[offset] = side;
36109
36110 offset++;
36111 }
36112 }
36113
36114 m_azimuthalRecConstSet = true;
36115
36116 if(domainId() == 0) {
36117 cerr << " done" << endl;
36118 }
36119}
36120
36125template <MInt nDim, class SysEqn>
36127 TRACE();
36128
36129 MFloat recCoord[nDim];
36130
36131 MInt offset = 0;
36132 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36133 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
36134 MInt cellId = grid().azimuthalWindowCell(i, j);
36135
36136 std::copy_n(&m_azimuthalCutRecCoord[offset * nDim], nDim, &recCoord[0]);
36137
36138 rebuildAzimuthalReconstructionConstants(cellId, offset, recCoord, mode);
36139
36140 offset++;
36141 }
36142 }
36143
36144 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36145 for(MUint j = 0; j < m_azimuthalRemappedWindowCells[i].size(); j++) {
36146 MInt cellId = m_azimuthalRemappedWindowCells[i][j];
36147
36148 std::copy_n(&m_azimuthalCutRecCoord[offset * nDim], nDim, &recCoord[0]);
36149
36150 rebuildAzimuthalReconstructionConstants(cellId, offset, recCoord, mode);
36151
36152 offset++;
36153 }
36154 }
36155}
36156
36157template <MInt nDim, class SysEqn>
36159 MFloat* recCoord, MInt mode) {
36160 TRACE();
36161
36162 const MInt maxNoNghbrs = m_maxNoAzimuthalRecConst;
36163 MIntScratchSpace nghbrList(1.5 * maxNoNghbrs, AT_, "nghbrList"); // Plus 50%
36164
36165 m_noAzimuthalReconstNghbrs[offset] = 0;
36166
36167 if(m_geometry->pointIsInside(recCoord)) {
36168 if(a_bndryId(cellId) < 0) {
36169 // Halo is inActive or a parent of bndryCells
36170 m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst] = cellId;
36171 m_noAzimuthalReconstNghbrs[offset] = 1;
36172 m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst] = F1;
36173 if(a_level(cellId) == maxRefinementLevel()) mTerm(1, AT_, "");
36174 return;
36175 } else {
36176 std::vector<MFloat> ghostCoord{F0, F0, F0};
36177 for(MInt srfc = 0; srfc < m_bndryCells->a[a_bndryId(cellId)].m_noSrfcs; srfc++) {
36178 MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[a_bndryId(cellId)].m_srfcVariables[srfc]->m_ghostCellId;
36179 std::copy_n(&a_coordinate(ghostCellId, 0), nDim, &ghostCoord[0]);
36180
36181 if(a_level(cellId) == maxLevel()) {
36182 cerr << "cut cell and stl issue"
36183 << " D:" << domainId() << " " << cellId << "/" << c_globalId(cellId) << " (" << a_coordinate(cellId, 0)
36184 << ", " << a_coordinate(cellId, 1) << ", " << a_coordinate(cellId, 2) << ") | "
36185 << "GC: (" << ghostCoord[0] << ", " << ghostCoord[1] << ", " << ghostCoord[2] << ") | "
36186 << "RC: (" << recCoord[0] << ", " << recCoord[1] << ", " << recCoord[2] << ")" << endl;
36187 }
36188 }
36189 }
36190 }
36191
36192 // Only debug info! Not an error.
36193#ifndef NDEBUG
36194 if((abs(a_coordinate(cellId, 0) - recCoord[0]) > c_cellLengthAtLevel(a_level(cellId))
36195 || abs(a_coordinate(cellId, 1) - recCoord[1]) > c_cellLengthAtLevel(a_level(cellId))
36196 || abs(a_coordinate(cellId, nDim - 1) - recCoord[nDim - 1]) > c_cellLengthAtLevel(a_level(cellId)))
36197 && !a_hasProperty(cellId, SolverCell::IsInactive)) {
36198 MInt side = m_azimuthalBndrySide[offset];
36199 MFloat dummyCoord[3];
36200 MFloat angle = grid().azimuthalAngle();
36201 cerr << "Rec coord " << domainId() << " " << cellId << "/" << c_globalId(cellId) << " " << recCoord[0] << " "
36202 << recCoord[1] << " " << recCoord[nDim - 1] << " / Window G " << c_coordinate(cellId, 0) << " "
36203 << c_coordinate(cellId, 1) << " " << c_coordinate(cellId, nDim - 1) << " FV " << a_coordinate(cellId, 0) << " "
36204 << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, nDim - 1) << " / " << a_level(cellId) << " "
36205 << c_cellLengthAtLevel(a_level(cellId)) << " " << side;
36206
36207 std::copy_n(&recCoord[0], nDim, &dummyCoord[0]);
36208 grid().rotateCartesianCoordinates(dummyCoord, (-side * angle));
36209 cerr << " / Halo " << dummyCoord[0] << " " << dummyCoord[1] << " " << dummyCoord[nDim - 1] << endl;
36210 }
36211#endif
36212
36213 MInt contCell = -1;
36214 if(this->inCell(cellId, recCoord)) {
36215 contCell = cellId;
36216 } else {
36217 MInt counter = grid().getAdjacentGridCells(cellId, 1, nghbrList, (a_level(cellId) - 1), 2);
36218 for(MInt n = 0; n < counter; n++) {
36219 MInt nghbrId = nghbrList[n];
36220 if(this->inCell(nghbrId, recCoord)) {
36221 contCell = nghbrId;
36222 break;
36223 }
36224 }
36225 }
36226
36227 if(contCell < 0) {
36228 MInt counter = grid().getAdjacentGridCells(cellId, 1, nghbrList, (a_level(cellId) - 1), 2);
36229 cerr << domainId() << " No contCell"
36230 << " " << cellId << "/" << c_globalId(cellId) << " " << a_level(cellId) << " G " << c_coordinate(cellId, 0)
36231 << " " << c_coordinate(cellId, 1) << " " << c_coordinate(cellId, nDim - 1) << " S " << a_coordinate(cellId, 0)
36232 << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, nDim - 1) << " R " << recCoord[0] << " "
36233 << recCoord[1] << " " << recCoord[2] << endl;
36234 for(MInt n = 0; n < counter; n++) {
36235 MInt nghbrId = nghbrList[n];
36236 cerr << "Nghbr: " << n << "/" << (counter - 1) << " " << nghbrId << "/" << c_globalId(nghbrId) << " "
36237 << a_coordinate(nghbrId, 0) << " " << a_coordinate(nghbrId, 1) << " " << a_coordinate(nghbrId, nDim - 1)
36238 << endl;
36239 }
36240 mTerm(1, AT_, "No containing cell found?");
36241 }
36242
36243 MInt contCellLC = contCell;
36244 contCellLC = grid().findContainingLeafCell(recCoord, contCell);
36245 MInt cellIdLC = cellId;
36246 if(c_noChildren(cellId) > 0) {
36247 if(this->inCell(cellId, recCoord)) {
36248 cellIdLC = grid().findContainingLeafCell(recCoord, cellId);
36249 } else {
36250 // In this case haloCell is a bndryCell and a_hasProperty(haloCell, SolverCell::IsNotGradient) = true.
36251 MInt nextId = cellId;
36252 for(MInt l = 0; l < (maxLevel() - a_level(cellId)); l++) {
36253 MFloat minDist = numeric_limits<MFloat>::max();
36254 MInt closestChild = -1;
36255 for(MInt child = 0; child < grid().m_maxNoChilds; child++) {
36256 const MInt childId = c_childId(nextId, child);
36257 if(childId < 0) {
36258 continue;
36259 }
36260 MFloat dist = F0;
36261 for(MInt d = 0; d < nDim; d++) {
36262 dist += pow(recCoord[d] - c_coordinate(childId, d), F2);
36263 }
36264 if(dist < minDist) {
36265 closestChild = childId;
36266 }
36267 }
36268 nextId = closestChild;
36269 }
36270 cellIdLC = nextId;
36271 }
36272 }
36273
36274 if(a_isPeriodic(contCellLC)) {
36275 mTerm(1, "azimuthal window cell is isPeriodic!");
36276 }
36277
36278 // No interp can be specified for 90 degree periodicity
36279 MBool noInterp = Context::getSolverProperty<MBool>("noInterp", m_solverId, AT_);
36280 if(noInterp) {
36281 m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst] = contCellLC;
36282 m_noAzimuthalReconstNghbrs[offset]++;
36283 m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst] = F1;
36284 return;
36285 }
36286
36287 // Add contCellLC to recNghbrs
36288 if(a_hasProperty(contCellLC, SolverCell::IsOnCurrentMGLevel)) {
36289 m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + m_noAzimuthalReconstNghbrs[offset]] = contCellLC;
36290 m_noAzimuthalReconstNghbrs[offset]++;
36291 }
36292 if(cellIdLC != contCellLC && a_hasProperty(cellIdLC, SolverCell::IsOnCurrentMGLevel)) {
36293 m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + m_noAzimuthalReconstNghbrs[offset]] = cellIdLC;
36294 m_noAzimuthalReconstNghbrs[offset]++;
36295 }
36296
36297 // Add bndryGhostCell
36298 if(mode == 0 && a_bndryId(contCellLC) > -1) {
36299 for(MInt srfc = 0; srfc < m_bndryCells->a[a_bndryId(contCellLC)].m_noSrfcs; srfc++) {
36300 MInt ghostCellId = m_fvBndryCnd->m_bndryCells->a[a_bndryId(contCellLC)].m_srfcVariables[srfc]->m_ghostCellId;
36301 if(ghostCellId < 0) mTerm(1, AT_, "ghostCellId not set!");
36302 m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + m_noAzimuthalReconstNghbrs[offset]] = ghostCellId;
36303 m_noAzimuthalReconstNghbrs[offset]++;
36304 }
36305 }
36306
36307 MInt axDir = grid().raw().m_azimuthalAxialDir;
36308 const MInt counter = grid().getAdjacentGridCells(cellIdLC, 2, nghbrList, a_level(cellIdLC), 2);
36309 MInt nghbrTmpCnt = 0;
36310 MInt dbgCnt = 0;
36311 for(MInt k = 0; k < counter; k++) {
36312 MInt nghbrId = nghbrList[k];
36313 if(nghbrId < 0) continue;
36314 if(a_isPeriodic(nghbrId)) mTerm(1, "azimuthal recNghbr is periodic! Increase cutOffNmbrLayers");
36315 if(!a_hasProperty(nghbrId, SolverCell::IsOnCurrentMGLevel)) continue;
36316 if(nghbrId == contCellLC) {
36317 continue;
36318 }
36319 if(nghbrId == cellIdLC) {
36320 continue;
36321 }
36322 if(m_planeInterp
36323 && abs(a_coordinate(nghbrId, axDir) - recCoord[axDir]) / c_cellLengthAtLevel(a_level(contCellLC)) > F1B2) {
36324 continue;
36325 }
36326
36327 dbgCnt++;
36328 if(m_noAzimuthalReconstNghbrs[offset] >= m_maxNoAzimuthalRecConst) {
36329 cerr << "too many rec nghbrs " << contCellLC << "/" << c_globalId(contCellLC) << " " << dbgCnt << " "
36330 << m_maxNoAzimuthalRecConst << " " << c_coordinate(contCellLC, 0) << " " << c_coordinate(contCellLC, 1)
36331 << " " << c_coordinate(contCellLC, 2) << endl;
36332 continue;
36333 }
36334
36335 m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + m_noAzimuthalReconstNghbrs[offset]] = nghbrId;
36336 m_noAzimuthalReconstNghbrs[offset]++;
36337 nghbrTmpCnt++;
36338 }
36339
36340 // This handels inactive cells, i.e., ls-value < 0 in moving Bndry cases.
36341 if(nghbrTmpCnt == 0 && !a_hasProperty(contCellLC, SolverCell::IsNotGradient)) {
36342 m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst] = cellIdLC;
36343 m_noAzimuthalReconstNghbrs[offset] = 1;
36344 m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst] = F1;
36345 return;
36346 }
36347
36348 if(nghbrTmpCnt == 0) {
36349 cerr << "D:" << domainId() << " " << cellId << "/" << c_globalId(cellId) << " " << contCell << "/"
36350 << c_globalId(contCell) << " " << c_level(contCell) << " " << c_noChildren(contCell) << " "
36351 << c_coordinate(contCell, 0) << " " << c_coordinate(contCell, 1) << " " << c_coordinate(contCell, nDim - 1)
36352 << " " << contCellLC << "/" << c_globalId(contCellLC) << " " << c_level(contCellLC) << " "
36353 << c_coordinate(contCellLC, 0) << " " << c_coordinate(contCellLC, 1) << " "
36354 << c_coordinate(contCellLC, nDim - 1) << endl;
36355 mTerm(1, "Cell without neighbors?");
36356 }
36357
36358 const MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
36359
36360 // Compute and store the reconstruction constants
36361 MBool nonlinear = true; // false;
36362 MInt recDim = nDim + 1;
36363 if(nonlinear) {
36364 if(m_planeInterp) {
36365 recDim = 2 * nDim; // Plane
36366 } else {
36367 recDim = 3 * nDim + 1;
36368 }
36369 }
36370 MFloatScratchSpace tmpA(m_maxNoAzimuthalRecConst, recDim, AT_, "tmpA");
36371 MFloatScratchSpace tmpC(recDim, m_maxNoAzimuthalRecConst, AT_, "tmpC");
36372 MFloatScratchSpace weights(m_maxNoAzimuthalRecConst, AT_, "weights");
36373
36374 const MFloat normalizationFactor = FPOW2(a_level(contCellLC)) / c_cellLengthAtLevel(0);
36375 weights.fill(F0);
36376
36377 // loop over least-squares cell cluster
36378 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36379 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
36380
36381 MInt dimCnt = 0;
36382
36383 MFloat fac = F1; // pow(F1B2, (MInt) (a_coordinate(recId,axDir) - recCoord[axDir]) /
36384 // c_cellLengthAtLevel(a_level(contCellLC)));
36385 if(!a_isBndryGhostCell(recId) && a_isBndryCell(recId)) {
36386 const MFloat vf = a_cellVolume(recId) / c_cellVolumeAtLevel(a_level(recId));
36387 fac = maia::math::deltaFun(vf, 1e-6, 0.1);
36388 }
36389
36390 tmpA(nghbr, dimCnt) = F1;
36391 dimCnt++;
36392
36393 MFloat dxdx = F0;
36394 MFloat dx[nDim];
36395 if(m_planeInterp) {
36396 for(MInt i = 0; i < (nDim - 1); i++) {
36397 MInt perDir1 = grid().azimuthalDir(i);
36398 dx[i] = (a_coordinate(recId, perDir1) - recCoord[perDir1]) * normalizationFactor;
36399 dxdx += POW2(a_coordinate(recId, perDir1) - recCoord[perDir1]);
36400 }
36401 for(MInt i = 0; i < (nDim - 1); i++) {
36402 tmpA(nghbr, dimCnt) = dx[i];
36403 dimCnt++;
36404 }
36405 } else {
36406 for(MInt i = 0; i < nDim; i++) {
36407 dx[i] = (a_coordinate(recId, i) - recCoord[i]) * normalizationFactor;
36408 dxdx += POW2(a_coordinate(recId, i) - recCoord[i]);
36409 }
36410 for(MInt i = 0; i < nDim; i++) {
36411 tmpA(nghbr, dimCnt) = dx[i];
36412 dimCnt++;
36413 }
36414 }
36415
36416 weights[nghbr] = fac * maia::math::RBF(dxdx, POW2(c_cellLengthAtCell(contCellLC)));
36417
36418 if(nonlinear) {
36419 if(m_planeInterp) {
36420 for(MInt i = 0; i < (nDim - 1); i++) {
36421 MInt perDir1 = grid().azimuthalDir(i);
36422 tmpA(nghbr, dimCnt) = 0.5 * POW2((a_coordinate(recId, perDir1) - recCoord[perDir1]) * normalizationFactor);
36423 dimCnt++;
36424 }
36425 for(MInt i = 0; i < (nDim - 1); i++) {
36426 MInt perDir1 = grid().azimuthalDir(i);
36427 for(MInt j = i + 1; j < (nDim - 1); j++) {
36428 MInt perDir2 = grid().azimuthalDir(j);
36429 tmpA(nghbr, dimCnt) = (a_coordinate(recId, perDir2) - recCoord[perDir2])
36430 * (a_coordinate(recId, perDir1) - recCoord[perDir1]) * POW2(normalizationFactor);
36431 dimCnt++;
36432 }
36433 }
36434 } else {
36435 for(MInt i = 0; i < nDim; i++) {
36436 tmpA(nghbr, dimCnt) = 0.5 * POW2((a_coordinate(recId, i) - recCoord[i]) * normalizationFactor);
36437 dimCnt++;
36438 }
36439 for(MInt i = 0; i < nDim; i++) {
36440 for(MInt j = i + 1; j < nDim; j++) {
36441 tmpA(nghbr, dimCnt) = (a_coordinate(recId, j) - recCoord[j]) * (a_coordinate(recId, i) - recCoord[i])
36442 * POW2(normalizationFactor);
36443 dimCnt++;
36444 }
36445 }
36446 }
36447 }
36448 ASSERT(dimCnt == recDim, "");
36449 }
36450
36451 const MInt rank = maia::math::invertR(tmpA, weights, tmpC, noNghbrIds, recDim);
36452 if(rank < min(noNghbrIds, recDim)) {
36453 cerr << domainId() << ": QRD failed for azimuthal periodic cell " << cellId << "(" << c_globalId(cellId) << ") "
36454 << a_isHalo(cellId) << " " << a_level(cellId) << " " << c_noChildren(cellId) << " " << noNghbrIds << endl;
36455 cerr << "G: (" << a_coordinate(cellId, 0) << ", " << a_coordinate(cellId, 1) << ", "
36456 << a_coordinate(cellId, nDim - 1) << ") " << endl;
36457 cerr << "R: (" << recCoord[0] << ", " << recCoord[1] << ", " << recCoord[2] << "), "
36458 << m_geometry->pointIsInside(recCoord) << " " << a_hasProperty(cellId, SolverCell::IsInactive) << endl;
36459 MFloat angle = grid().azimuthalAngle();
36460 MInt side = grid().determineAzimuthalBoundarySide(recCoord);
36461 grid().rotateCartesianCoordinates(recCoord, (side * angle));
36462 cerr << " M " << contCellLC << "(" << c_globalId(contCellLC) << ")"
36463 << " " << a_bndryId(contCellLC) << " " << a_coordinate(contCellLC, 0) << " " << a_coordinate(contCellLC, 1)
36464 << " " << a_coordinate(contCellLC, nDim - 1) << " H " << recCoord[0] << " " << recCoord[1] << " "
36465 << recCoord[nDim - 1] << endl;
36466
36467 for(MInt i = 0; i < noNghbrIds; i++) {
36468 for(MInt j = 0; j < recDim; j++) {
36469 cerr << " " << tmpA(i, j);
36470 }
36471 cerr << endl;
36472 }
36473 mTerm(1, AT_, "Error in matrix inverse!");
36474 }
36475
36476 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36477 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
36478 ASSERT(!a_isPeriodic(recId), "ERROR");
36479
36480 // First entry is not normalized!
36481 m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst + nghbr] = tmpC(0, nghbr); // * normalizationFactor;
36482 }
36483
36484 const MInt condNum = maia::math::frobeniusMatrixNormSquared(tmpA, noNghbrIds, recDim);
36485 if(condNum < F0 || condNum > 1e7 || std::isnan(condNum)) {
36486 cerr << domainId() << " SVD decomposition for azimuthal periodic windowCell " << contCell << "/"
36487 << c_globalId(contCell) << " level " << a_level(contCell) << " with large condition number: " << condNum << " "
36488 << noNghbrIds << "x" << recDim << " "
36489 << a_cellVolume(contCell) / pow(c_cellLengthAtCell(contCell), (MFloat)nDim) << " coords "
36490 << a_coordinate(contCell, 0) << ", " << a_coordinate(contCell, 1) << ", " << a_coordinate(contCell, 2)
36491 << " bndryId " << a_bndryId(contCell) << endl;
36492 }
36493}
36494
36498template <MInt nDim, class SysEqn>
36500 TRACE();
36501
36502 MUint rcvSize = maia::mpi::getBufferSize(m_azimuthalMaxLevelWindowCells);
36503 MIntScratchSpace windowData(rcvSize, AT_, "windowData");
36504 windowData.fill(0);
36505 MUint sndSize = maia::mpi::getBufferSize(m_azimuthalMaxLevelHaloCells);
36506 MIntScratchSpace haloData(sndSize, AT_, "haloData");
36507 haloData.fill(0);
36508
36509 m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells.resize(grid().noAzimuthalNeighborDomains());
36510 m_fvBndryCnd->m_azimuthalNearBoundaryWindowMap.resize(grid().noAzimuthalNeighborDomains());
36511 m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells.resize(grid().noAzimuthalNeighborDomains());
36512
36513 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36514 m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells[i].clear();
36515 m_fvBndryCnd->m_azimuthalNearBoundaryWindowMap[i].clear();
36516 m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i].clear();
36517 }
36518
36519 if(grid().noAzimuthalNeighborDomains() > 0) {
36520 MInt sndCnt = 0;
36521 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36522 for(MUint j = 0; j < m_azimuthalMaxLevelHaloCells[i].size(); j++) {
36523 MInt cellId = m_azimuthalMaxLevelHaloCells[i][j];
36524 if(activeFlag[cellId] > 0) {
36525 ASSERT(a_isPeriodic(cellId), "");
36526 m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i].push_back(cellId);
36527 haloData[sndCnt] = 1;
36528 }
36529 sndCnt++;
36530 }
36531 }
36532
36533 // Exchange
36534 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), m_azimuthalMaxLevelWindowCells,
36535 m_azimuthalMaxLevelHaloCells, mpiComm(), haloData.getPointer(), windowData.getPointer(),
36536 1);
36537
36538 MInt rcvCnt = 0;
36539 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36540 for(MUint j = 0; j < m_azimuthalMaxLevelWindowCells[i].size(); j++) {
36541 MInt cellId = m_azimuthalMaxLevelWindowCells[i][j];
36542 MInt offset = m_azimuthalMaxLevelWindowMap[i][j];
36543 if(windowData[rcvCnt] > 0) {
36544 m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells[i].push_back(cellId);
36545 m_fvBndryCnd->m_azimuthalNearBoundaryWindowMap[i].push_back(offset);
36546
36547 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
36548 for(MInt n = 0; n < noNghbrIds; n++) {
36549 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + n];
36550 activeFlag[recId] = 1;
36551 }
36552 }
36553 // m_azimuthalHaloActive[offset] = windowData[rcvCnt];
36554 rcvCnt++;
36555 }
36556 }
36557 }
36558
36559 if(m_azimuthalRemappedNeighborDomains.size() > 0) {
36560 MInt offset = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
36561 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36562 for(MUint j = 0; j < m_azimuthalRemappedWindowCells[i].size(); j++) {
36563 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
36564 for(MInt n = 0; n < noNghbrIds; n++) {
36565 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + n];
36566 activeFlag[recId] = 1;
36567 }
36568
36569 offset++;
36570 }
36571 }
36572 }
36573 m_azimuthalNearBndryInit = true;
36574}
36575
36576
36580template <MInt nDim, class SysEqn>
36582 TRACE();
36583
36584 if(!m_azimuthalRecConstSet) mTerm(1, AT_, "Azimuthal reconstruction constants not initialized!");
36585
36586 MInt noVars = m_sysEqn.CV->noVariables;
36587
36588 MUint sndSize = mMax(maia::mpi::getBufferSize(m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells),
36589 maia::mpi::getBufferSize(m_azimuthalRemappedWindowCells));
36590 MFloatScratchSpace windowData(sndSize * noVars, AT_, "windowData");
36591 windowData.fill(0);
36592 MUint rcvSize = mMax(maia::mpi::getBufferSize(m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells),
36593 maia::mpi::getBufferSize(m_azimuthalRemappedHaloCells));
36594 MFloatScratchSpace haloData(rcvSize * noVars, AT_, "windowData");
36595 haloData.fill(0);
36596
36597 MInt sndCnt = 0;
36598 MInt rcvCnt = 0;
36599 if(grid().noAzimuthalNeighborDomains() > 0) {
36600 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36601 for(MUint j = 0; j < m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells[i].size(); j++) {
36602 MInt cellId = m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells[i][j];
36603 MInt offset = m_fvBndryCnd->m_azimuthalNearBoundaryWindowMap[i][j];
36604 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
36605 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36606 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
36607 if(a_isBndryGhostCell(recId)) {
36608 setConservativeVariables(recId);
36609 }
36610#ifndef NDEBUG
36611 checkAzimuthalRecNghbrConsistency(recId);
36612#endif
36613 }
36614
36615 // loop over least-squares cell cluster
36616 interpolateAzimuthalData(&windowData[sndCnt * noVars], offset, noVars, &a_variable(0, 0));
36617 // Transform cartesian velocities
36618 MInt side = m_azimuthalBndrySide[offset];
36619 rotateVectorAzimuthal(side, &windowData[sndCnt * noVars], noVars, m_rotIndVarsCV);
36620
36621 if(windowData[sndCnt * noVars + m_sysEqn.CV->RHO] < F0
36622 && (a_cellVolume(cellId) / pow(c_cellLengthAtLevel(a_level(cellId)), 3) > m_fvBndryCnd->m_volumeLimitWall)) {
36623 cerr << globalTimeStep << "/" << m_RKStep << " Window data CV " << domainId() << " " << cellId << "/"
36624 << c_globalId(cellId) << " " << c_level(cellId) << " " << side << " "
36625 << a_hasProperty(cellId, SolverCell::IsSplitChild) << " " << a_coordinate(cellId, 0) << " "
36626 << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, nDim - 1);
36627 for(MInt v = 0; v < noVars; v++) {
36628 cerr << " /" << v << " " << windowData[sndCnt * noVars + v] << " " << a_variable(cellId, v);
36629 }
36630 cerr << endl;
36631
36632 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36633 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
36634 cerr << "Window nghbr " << domainId() << " " << recId << "/";
36635 if(a_isBndryGhostCell(recId)) {
36636 cerr << " ";
36637 } else {
36638 cerr << c_globalId(recId) << " " << a_level(recId);
36639 }
36640 cerr << " " << a_coordinate(recId, 0) << " " << a_coordinate(recId, 1) << " "
36641 << a_coordinate(recId, nDim - 1) << " "
36642 << m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst + nghbr] << " "
36643 << a_variable(recId, m_sysEqn.CV->RHO) << " " << a_isHalo(recId) << " " << a_isPeriodic(recId) << " "
36644 << (a_cellVolume(cellId) / pow(c_cellLengthAtLevel(a_level(cellId)), 3)
36645 > m_fvBndryCnd->m_volumeLimitWall)
36646 << endl;
36647 }
36648 }
36649
36650 sndCnt++;
36651 }
36652 }
36653
36654 // Exchange
36655 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells,
36656 m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells, mpiComm(), windowData.getPointer(),
36657 haloData.getPointer(), noVars);
36658
36659 // Extract
36660 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36661 for(MUint j = 0; j < m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i].size(); j++) {
36662 MInt cellId = m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i][j];
36663 for(MInt v = 0; v < noVars; v++) {
36664 a_variable(cellId, v) = haloData[rcvCnt + v];
36665 }
36666 if(a_variable(cellId, m_sysEqn.CV->RHO) < F0) {
36667 cerr << domainId() << ": EXC Halo CV " << cellId << "/" << c_globalId(cellId) << " " << a_bndryId(cellId)
36668 << " " << a_level(cellId) << " /r " << a_variable(cellId, m_sysEqn.CV->RHO) << " "
36669 << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, nDim - 1)
36670 << " " << a_hasProperty(cellId, SolverCell::IsSplitChild) << " "
36671 << a_hasProperty(cellId, SolverCell::IsSplitCell) << endl;
36672 }
36673
36674 rcvCnt += noVars;
36675 }
36676 }
36677 }
36678
36679
36680 // Remapped azimuthal window cells
36681 if(m_azimuthalRemappedNeighborDomains.size() > 0) {
36682 windowData.fill(F0);
36683 haloData.fill(F0);
36684 sndCnt = 0;
36685 MInt offset = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
36686 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36687 for(MUint j = 0; j < m_azimuthalRemappedWindowCells[i].size(); j++) {
36688 MInt cellId = m_azimuthalRemappedWindowCells[i][j];
36689
36690 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
36691 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36692 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
36693 if(a_isBndryGhostCell(recId)) {
36694 setConservativeVariables(recId);
36695 }
36696#ifndef NDEBUG
36697 checkAzimuthalRecNghbrConsistency(recId);
36698#endif
36699 }
36700 // loop over least-squares cell cluster
36701 interpolateAzimuthalData(&windowData[sndCnt * noVars], offset, noVars, &a_variable(0, 0));
36702 // Transform cartesian velocities
36703 MInt side = m_azimuthalBndrySide[offset];
36704 rotateVectorAzimuthal(side, &windowData[sndCnt * noVars], noVars, m_rotIndVarsCV);
36705
36706 if(windowData[sndCnt * noVars + m_sysEqn.CV->RHO] < F0
36707 && (a_cellVolume(cellId) / pow(c_cellLengthAtLevel(a_level(cellId)), 3) > m_fvBndryCnd->m_volumeLimitWall)) {
36708 cerr << "Window data CV Rem " << domainId() << " " << cellId << "/" << c_globalId(cellId) << " "
36709 << c_level(cellId) << " " << a_hasProperty(cellId, SolverCell::IsSplitChild) << " "
36710 << a_coordinate(cellId, 0) << " " << a_coordinate(cellId, 1) << " " << a_coordinate(cellId, nDim - 1);
36711 for(MInt v = 0; v < noVars; v++) {
36712 cerr << " /" << v << " " << windowData[sndCnt * noVars + v] << " " << a_variable(cellId, v);
36713 }
36714 cerr << endl;
36715
36716 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
36717 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
36718 cerr << "Window nghbr " << domainId() << " " << recId << "/";
36719 if(a_isBndryGhostCell(recId)) {
36720 cerr << " ";
36721 } else {
36722 cerr << c_globalId(recId) << " " << a_level(recId);
36723 }
36724 cerr << " " << a_coordinate(recId, 0) << " " << a_coordinate(recId, 1) << " "
36725 << a_coordinate(recId, nDim - 1) << " "
36726 << m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst + nghbr] << " "
36727 << a_variable(recId, m_sysEqn.CV->RHO) << " " << a_isHalo(recId) << " " << a_isPeriodic(recId) << " "
36728 << (a_cellVolume(cellId) / pow(c_cellLengthAtLevel(a_level(cellId)), 3)
36729 > m_fvBndryCnd->m_volumeLimitWall)
36730 << endl;
36731 }
36732 }
36733
36734 sndCnt++;
36735 offset++;
36736 }
36737 }
36738
36739 // Exchange
36740 maia::mpi::exchangeBuffer(m_azimuthalRemappedNeighborDomains, m_azimuthalRemappedHaloCells,
36741 m_azimuthalRemappedWindowCells, mpiComm(), windowData.getPointer(), haloData.getPointer(),
36742 noVars);
36743
36744 // Extract
36745 rcvCnt = 0;
36746 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36747 for(MUint j = 0; j < m_azimuthalRemappedHaloCells[i].size(); j++) {
36748 MInt cellId = m_azimuthalRemappedHaloCells[i][j];
36749 for(MInt v = 0; v < noVars; v++) {
36750 a_variable(cellId, v) = haloData[rcvCnt + v];
36751 }
36752 rcvCnt += noVars;
36753 }
36754 }
36755 }
36756}
36757
36761template <MInt nDim, class SysEqn>
36763 TRACE();
36764
36765 MInt noVars = m_sysEqn.CV->noVariables;
36766
36767 MUint sndSize = mMax(maia::mpi::getBufferSize(m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells),
36768 maia::mpi::getBufferSize(m_azimuthalRemappedWindowCells));
36769 MFloatScratchSpace windowData(sndSize * noVars, AT_, "windowData");
36770 windowData.fill(0);
36771 MUint rcvSize = mMax(maia::mpi::getBufferSize(m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells),
36772 maia::mpi::getBufferSize(m_azimuthalRemappedHaloCells));
36773 MFloatScratchSpace haloData(rcvSize * noVars, AT_, "windowData");
36774 haloData.fill(0);
36775
36776 // Send
36777 MInt sndCnt = 0;
36778 MInt rcvCnt = 0;
36779 if(grid().noAzimuthalNeighborDomains() > 0) {
36780 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36781 for(MUint j = 0; j < m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i].size(); j++) {
36782 MInt cellId = m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells[i][j];
36783 for(MInt v = 0; v < noVars; v++) {
36784 haloData[sndCnt + v] = a_variable(cellId, v);
36785 }
36786 sndCnt += noVars;
36787 }
36788 }
36789
36790 // Exchange
36791 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells,
36792 m_fvBndryCnd->m_azimuthalNearBoundaryHaloCells, mpiComm(), haloData.getPointer(),
36793 windowData.getPointer(), noVars);
36794
36795 // Extract
36796 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36797 for(MUint j = 0; j < m_fvBndryCnd->m_azimuthalNearBoundaryWindowCells[i].size(); j++) {
36798 MInt offset = m_fvBndryCnd->m_azimuthalNearBoundaryWindowMap[i][j];
36799 // Transform cartesian velocities
36800 MInt side = -1 * m_azimuthalBndrySide[offset];
36801 rotateVectorAzimuthal(side, &windowData[rcvCnt * noVars], noVars, m_rotIndVarsCV);
36802 // loop over least-squares cell cluster
36803 interpolateAzimuthalDataReverse(&a_variable(0, 0), offset, noVars, &windowData[rcvCnt * noVars]);
36804
36805 rcvCnt++;
36806 }
36807 }
36808 }
36809
36810 // Send Remapped
36811 if(m_azimuthalRemappedNeighborDomains.size() > 0) {
36812 windowData.fill(F0);
36813 haloData.fill(F0);
36814 sndCnt = 0;
36815 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36816 for(MUint j = 0; j < m_azimuthalRemappedHaloCells[i].size(); j++) {
36817 MInt cellId = m_azimuthalRemappedHaloCells[i][j];
36818 for(MInt v = 0; v < noVars; v++) {
36819 haloData[sndCnt + v] = a_variable(cellId, v);
36820 }
36821 sndCnt += noVars;
36822 }
36823 }
36824
36825 // Exchange
36826 maia::mpi::exchangeBuffer(m_azimuthalRemappedNeighborDomains, m_azimuthalRemappedWindowCells,
36827 m_azimuthalRemappedHaloCells, mpiComm(), haloData.getPointer(), windowData.getPointer(),
36828 noVars);
36829
36830 // Extract
36831 rcvCnt = 0;
36832 MInt offset = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
36833 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36834 for(MUint j = 0; j < m_azimuthalRemappedWindowCells[i].size(); j++) {
36835 // Transform cartesian velocities
36836 MInt side = -1 * m_azimuthalBndrySide[offset];
36837 rotateVectorAzimuthal(side, &windowData[rcvCnt * noVars], noVars, m_rotIndVarsCV);
36838 // loop over least-squares cell cluster
36839 interpolateAzimuthalDataReverse(&a_variable(0, 0), offset, noVars, &windowData[rcvCnt * noVars]);
36840
36841 rcvCnt++;
36842 offset++;
36843 }
36844 }
36845 }
36846}
36847
36851template <MInt nDim, class SysEqn>
36852template <MBool exchangeAll_>
36854 const vector<MInt>& rotIndices) {
36855 TRACE();
36856
36857 if(grid().noAzimuthalNeighborDomains() > 0) {
36858 MUint sndSize = (exchangeAll_) ? maia::mpi::getBufferSize(grid().azimuthalWindowCells())
36859 : maia::mpi::getBufferSize(m_azimuthalMaxLevelWindowCells);
36860 MFloatScratchSpace windowData(sndSize * noVars, AT_, "windowData");
36861 windowData.fill(0);
36862 MUint rcvSize = (exchangeAll_) ? maia::mpi::getBufferSize(grid().azimuthalHaloCells())
36863 : maia::mpi::getBufferSize(m_azimuthalMaxLevelHaloCells);
36864 MFloatScratchSpace haloData(rcvSize * noVars, AT_, "haloData");
36865 haloData.fill(0);
36866
36867 MInt sndCnt = 0;
36868 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36869 MInt noWindows =
36870 (exchangeAll_) ? grid().noAzimuthalWindowCells(i) : (signed)m_azimuthalMaxLevelWindowCells[i].size();
36871 for(MInt j = 0; j < noWindows; j++) {
36872 MInt cellId = (exchangeAll_) ? grid().azimuthalWindowCell(i, j) : m_azimuthalMaxLevelWindowCells[i][j];
36873 MInt offset = (exchangeAll_) ? sndCnt : m_azimuthalMaxLevelWindowMap[i][j];
36874 fillExcBufferAzimuthal(cellId, offset, &windowData[sndCnt * noVars], data, noVars, rotIndices);
36875 sndCnt++;
36876 }
36877 }
36878
36879 // Exchange
36880 if(exchangeAll_) {
36881 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), grid().azimuthalHaloCells(),
36882 grid().azimuthalWindowCells(), mpiComm(), windowData.getPointer(),
36883 haloData.getPointer(), noVars);
36884 } else {
36885 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), m_azimuthalMaxLevelHaloCells,
36886 m_azimuthalMaxLevelWindowCells, mpiComm(), windowData.getPointer(),
36887 haloData.getPointer(), noVars);
36888 }
36889
36890 // Extract
36891 MInt rcvCnt = 0;
36892 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36893 MInt noHalos = (exchangeAll_) ? grid().noAzimuthalHaloCells(i) : (signed)m_azimuthalMaxLevelHaloCells[i].size();
36894 for(MInt j = 0; j < noHalos; j++) {
36895 MInt cellId = (exchangeAll_) ? grid().azimuthalHaloCell(i, j) : m_azimuthalMaxLevelHaloCells[i][j];
36896 for(MInt v = 0; v < noVars; v++) {
36897 data[cellId * noVars + v] = haloData[rcvCnt + v];
36898 }
36899 rcvCnt += noVars;
36900 }
36901 }
36902 }
36903
36904 // Handle azimuthal unmapped halos
36905 exchangeAzimuthalRemappedHaloCells();
36906
36907 if(exchangeAll_) {
36908 for(MInt i = 0; i < grid().noAzimuthalUnmappedHaloCells(); i++) {
36909 MInt cellId = grid().azimuthalUnmappedHaloCell(i);
36910 reduceData(cellId, data, noVars);
36911 }
36912 }
36913}
36914
36918template <MInt nDim, class SysEqn>
36920 TRACE();
36921
36922 if(m_azimuthalRemappedNeighborDomains.size() == 0) return;
36923
36924 MInt noVars = PV->noVariables;
36925 MUint sndSize = maia::mpi::getBufferSize(m_azimuthalRemappedWindowCells);
36926 MFloatScratchSpace windowData(sndSize * noVars, AT_, "windowData");
36927 windowData.fill(0);
36928 MUint rcvSize = maia::mpi::getBufferSize(m_azimuthalRemappedHaloCells);
36929 MFloatScratchSpace haloData(rcvSize * noVars, AT_, "haloData");
36930 haloData.fill(0);
36931
36932 MInt sndCnt = 0;
36933 MInt offset = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
36934 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36935 for(MUint j = 0; j < m_azimuthalRemappedWindowCells[i].size(); j++) {
36936 MInt cellId = m_azimuthalRemappedWindowCells[i][j];
36937 fillExcBufferAzimuthal(cellId, offset, &windowData[sndCnt * noVars], &a_pvariable(0, 0), noVars, m_rotIndVarsCV);
36938 sndCnt++;
36939 offset++;
36940 }
36941 }
36942
36943 // Exchange
36944 maia::mpi::exchangeBuffer(m_azimuthalRemappedNeighborDomains, m_azimuthalRemappedHaloCells,
36945 m_azimuthalRemappedWindowCells, mpiComm(), windowData.getPointer(), haloData.getPointer(),
36946 noVars);
36947
36948 // Extract
36949 MInt rcvCnt = 0;
36950 for(MUint i = 0; i < m_azimuthalRemappedNeighborDomains.size(); i++) {
36951 for(MUint j = 0; j < m_azimuthalRemappedHaloCells[i].size(); j++) {
36952 MInt cellId = m_azimuthalRemappedHaloCells[i][j];
36953
36954 for(MInt v = 0; v < noVars; v++) {
36955 a_pvariable(cellId, v) = haloData[rcvCnt + v];
36956 }
36957 rcvCnt += noVars;
36958 }
36959 }
36960}
36961
36962
36966template <MInt nDim, class SysEqn>
36968 TRACE();
36969
36970 if(grid().noAzimuthalNeighborDomains() == 0) return;
36971
36972 m_azimuthalMaxLevelHaloCells.resize(grid().noAzimuthalNeighborDomains());
36973 m_azimuthalMaxLevelWindowCells.resize(grid().noAzimuthalNeighborDomains());
36974 m_azimuthalMaxLevelWindowMap.resize(grid().noAzimuthalNeighborDomains());
36975
36976 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36977 m_azimuthalMaxLevelHaloCells[i].clear();
36978 m_azimuthalMaxLevelWindowCells[i].clear();
36979 m_azimuthalMaxLevelWindowMap[i].clear();
36980 }
36981
36982 MUint rcvSize = maia::mpi::getBufferSize(grid().azimuthalWindowCells());
36983 MIntScratchSpace windowData(rcvSize, AT_, "windowData");
36984 windowData.fill(0);
36985 MUint sndSize = maia::mpi::getBufferSize(grid().azimuthalHaloCells());
36986 MIntScratchSpace haloData(sndSize, AT_, "haloData");
36987 haloData.fill(0);
36988
36989 m_azimuthalHaloActive.clear();
36990 m_azimuthalHaloActive.assign(rcvSize, 0);
36991
36992 MInt sndCnt = 0;
36993 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
36994 m_azimuthalMaxLevelHaloCells[i].reserve(grid().noAzimuthalHaloCells(i));
36995
36996 for(MInt j = 0; j < grid().noAzimuthalHaloCells(i); j++) {
36997 MInt cellId = grid().azimuthalHaloCell(i, j);
36998 if(a_hasProperty(cellId, SolverCell::IsOnCurrentMGLevel)) {
36999 ASSERT(a_isPeriodic(cellId), "");
37000 m_azimuthalMaxLevelHaloCells[i].push_back(cellId);
37001 haloData[sndCnt] = 1;
37002 }
37003 sndCnt++;
37004 }
37005 }
37006
37007 // Exchange
37008 if(grid().noAzimuthalNeighborDomains() > 0) {
37009 maia::mpi::exchangeBuffer(grid().azimuthalNeighborDomains(), grid().azimuthalWindowCells(),
37010 grid().azimuthalHaloCells(), mpiComm(), haloData.getPointer(), windowData.getPointer());
37011 }
37012
37013 MInt rcvCnt = 0;
37014 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
37015 m_azimuthalMaxLevelWindowCells[i].reserve(grid().noAzimuthalWindowCells(i));
37016
37017 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
37018 MInt cellId = grid().azimuthalWindowCell(i, j);
37019 ASSERT(m_noAzimuthalReconstNghbrs[rcvCnt] >= 1, "");
37020 if(windowData[rcvCnt] > 0) {
37021 m_azimuthalMaxLevelWindowCells[i].push_back(cellId);
37022 m_azimuthalMaxLevelWindowMap[i].push_back(rcvCnt);
37023 }
37024
37025 rcvCnt++;
37026 }
37027 }
37028}
37029
37030
37034template <MInt nDim, class SysEqn>
37036 const MFloat* vars) {
37037 TRACE();
37038
37039 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
37040 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
37041 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
37042 for(MInt v = 0; v < noVars; v++) {
37043 data[v] += m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst + nghbr] * vars[recId * noVars + v];
37044 }
37045 }
37046}
37047
37048
37052template <MInt nDim, class SysEqn>
37054 const MFloat* vars) {
37055 TRACE();
37056
37057 MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
37058
37059 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
37060 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
37061
37062 if(a_isBndryGhostCell(recId)) {
37063 // The first recNghbr is the cell containg the reconstruction coordinate.
37064 // c.f. rebuildAzimuthalReconstructionConstants
37065 MInt baseId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst];
37066 recId = baseId;
37067 }
37068
37069 for(MInt v = 0; v < noVars; v++) {
37070 data[recId * noVars + v] += m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst + nghbr] * vars[v];
37071 }
37072 }
37073}
37074
37078template <MInt nDim, class SysEqn>
37080 const std::vector<MInt>& indices) {
37081 TRACE();
37082
37083 MFloat phi = grid().azimuthalAngle();
37084 MInt dir1 = -1;
37085 MInt dir2 = -1;
37086
37087 MInt sum = 0;
37088 for(MInt d = 0; d < noData; d++) {
37089 if(indices[d] > 0) {
37090 if(sum == 0) {
37091 dir1 = d;
37092 }
37093 if(sum == 1) {
37094 dir2 = d;
37095 }
37096 sum++;
37097 }
37098 }
37099 if(!(sum == 2)) {
37100 mTerm(1, AT_, "Vector is only rotated along one axis.");
37101 }
37102
37103 MFloatScratchSpace vTmp(noData, AT_, "vTmp");
37104 for(MInt d = 0; d < noData; d++) {
37105 vTmp[d] = data[d];
37106 }
37107
37108 data[dir1] = cos(phi) * vTmp[dir1] + side * sin(phi) * vTmp[dir2];
37109 data[dir2] = -side * sin(phi) * vTmp[dir1] + cos(phi) * vTmp[dir2];
37110}
37111
37116template <MInt nDim, class SysEqn>
37118 TRACE();
37119
37120 if(!a_isBndryGhostCell(cellId) && a_isHalo(cellId)) {
37121 MBool isNearBndry = false;
37122 for(MInt n = 0; n < noNeighborDomains(); n++) {
37123 for(MUint m = 0; m < m_fvBndryCnd->m_nearBoundaryHaloCells[n].size(); m++) {
37124 MInt bndryId = m_fvBndryCnd->m_nearBoundaryHaloCells[n][m];
37125 if(a_hasProperty(bndryId, SolverCell::IsSplitChild)) bndryId = getAssociatedInternalCell(bndryId);
37126 if(c_globalId(bndryId) == c_globalId(cellId)) {
37127 isNearBndry = true;
37128 }
37129 }
37130 }
37131 if(!isNearBndry) {
37132 cerr << "Not near bndry! " << domainId() << " " << cellId << "/" << c_globalId(cellId) << " "
37133 << c_coordinate(cellId, 0) << " " << c_coordinate(cellId, 1) << " " << c_coordinate(cellId, nDim - 1) << " "
37134 << c_level(cellId);
37135 for(MInt n = 0; n < noNeighborDomains(); n++) {
37136 for(MInt m = 0; m < m_noMaxLevelHaloCells[n]; m++) {
37137 MInt bndryId = m_maxLevelHaloCells[n][m];
37138 if(c_globalId(bndryId) == c_globalId(cellId)) {
37139 cerr << " Is maxLevel!";
37140 }
37141 }
37142 }
37143 cerr << endl;
37144 mTerm(1, AT_, "Not near bndry");
37145 }
37146 }
37147}
37148
37152template <MInt nDim, class SysEqn>
37154 TRACE();
37155 if(grid().noAzimuthalNeighborDomains() == 0) return;
37156
37157 MInt sndCnt = 0;
37158 for(MInt i = 0; i < grid().noAzimuthalNeighborDomains(); i++) {
37159 for(MInt j = 0; j < grid().noAzimuthalWindowCells(i); j++) {
37160 const MInt noNghbrIds = m_noAzimuthalReconstNghbrs[sndCnt];
37161 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
37162 MInt recId = m_azimuthalReconstNghbrIds[sndCnt * m_maxNoAzimuthalRecConst + nghbr];
37163 setConservativeVariables(recId);
37164 }
37165 sndCnt++;
37166 }
37167 }
37168}
37169
37170
37178template <MInt nDim, class SysEqn>
37180 TRACE();
37181
37182 const MInt noSmallCells = (signed)m_fvBndryCnd->m_smallCutCells.size();
37183 const MInt noFVars = FV->noVariables;
37184 const MInt noCVars = CV->noVariables;
37185 const MInt noPVars = PV->noVariables;
37186 ScratchSpace<MFloat> rhsUpdate(noSmallCells * noFVars, AT_, "rhsUpdate");
37187 // interpolated rhs from all reconstruction neighbors
37188 MFloatScratchSpace rhsNB(noFVars, AT_, "rhsNB");
37189
37190 MIntScratchSpace sendBufferCnts(mMax(1, noNeighborDomains()), AT_, "sendBufferCnts");
37191 MIntScratchSpace recvBufferCnts(mMax(1, noNeighborDomains()), AT_, "recvBufferCnts");
37192 ScratchSpace<MPI_Request> sendReq(mMax(1, noNeighborDomains()), AT_, "sendReq");
37193 ScratchSpace<MPI_Request> recvReq(mMax(1, noNeighborDomains()), AT_, "recvReq");
37194
37195 MFloatScratchSpace rhsSponge(noFVars, AT_, "rhsSponge");
37196
37197 //-------------
37198
37199 // 0. Request rhs values of involved halo cells
37200 {
37201 sendReq.fill(MPI_REQUEST_NULL);
37202 recvReq.fill(MPI_REQUEST_NULL);
37203 sendBufferCnts.fill(0);
37204 recvBufferCnts.fill(0);
37205 for(MInt i = 0; i < noNeighborDomains(); i++) {
37206 sendBufferCnts(i) = noFVars * (signed)m_fvBndryCnd->m_nearBoundaryWindowCells[i].size();
37207 recvBufferCnts(i) = noFVars * (signed)m_fvBndryCnd->m_nearBoundaryHaloCells[i].size();
37208 if(m_fvBndryCnd->m_nearBoundaryWindowCells[i].empty()) {
37209 continue;
37210 }
37211 MInt sendBufferCounter = 0;
37212 for(MUint j = 0; j < m_fvBndryCnd->m_nearBoundaryWindowCells[i].size(); j++) {
37213 MInt cellId = m_fvBndryCnd->m_nearBoundaryWindowCells[i][j];
37214 for(MInt v = 0; v < noFVars; v++) {
37215 m_sendBuffers[i][sendBufferCounter] = a_rightHandSide(cellId, v);
37216 sendBufferCounter++;
37217 }
37218 }
37219 }
37220 MInt sendCnt = 0;
37221 MInt recvCnt = 0;
37222 if(m_nonBlockingComm) {
37223 for(MInt i = 0; i < noNeighborDomains(); i++) {
37224 if(sendBufferCnts(i) == 0) {
37225 continue;
37226 }
37227 ASSERT(sendBufferCnts(i) <= m_noMaxLevelWindowCells[i] * noFVars, "");
37228 MPI_Isend(m_sendBuffers[i], sendBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 12, mpiComm(), &sendReq[sendCnt],
37229 AT_, "m_sendBuffers[i]");
37230 sendCnt++;
37231 }
37232 for(MInt i = 0; i < noNeighborDomains(); i++) {
37233 if(recvBufferCnts(i) == 0) {
37234 continue;
37235 }
37236 ASSERT(recvBufferCnts(i) <= m_noMaxLevelHaloCells[i] * noFVars, "");
37237 MPI_Irecv(m_receiveBuffers[i], recvBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 12, mpiComm(),
37238 &recvReq[recvCnt], AT_, "m_receiveBuffers[i]");
37239 recvCnt++;
37240 }
37241 if(recvCnt > 0) {
37242 MPI_Waitall(recvCnt, &recvReq[0], MPI_STATUSES_IGNORE, AT_);
37243 }
37244 } else {
37245 for(MInt i = 0; i < noNeighborDomains(); i++) {
37246 if(sendBufferCnts(i) == 0) {
37247 continue;
37248 }
37249 ASSERT(sendBufferCnts(i) <= m_noMaxLevelWindowCells[i] * noFVars, "");
37250 MPI_Issend(m_sendBuffers[i], sendBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 12, mpiComm(), &sendReq[sendCnt],
37251 AT_, "m_sendBuffers[i]");
37252 sendCnt++;
37253 }
37254 for(MInt i = 0; i < noNeighborDomains(); i++) {
37255 if(recvBufferCnts(i) == 0) {
37256 continue;
37257 }
37258 ASSERT(recvBufferCnts(i) <= m_noMaxLevelHaloCells[i] * noFVars, "");
37259 MPI_Recv(m_receiveBuffers[i], recvBufferCnts(i), MPI_DOUBLE, neighborDomain(i), 12, mpiComm(),
37260 MPI_STATUS_IGNORE, AT_, "m_receiveBuffers[i]");
37261 recvCnt++;
37262 }
37263 }
37264 for(MInt i = 0; i < noNeighborDomains(); i++) {
37265 if(m_fvBndryCnd->m_nearBoundaryHaloCells[i].empty()) {
37266 continue;
37267 }
37268 MInt recvBufferCounter = 0;
37269 for(MUint j = 0; j < m_fvBndryCnd->m_nearBoundaryHaloCells[i].size(); j++) {
37270 MInt cellId = m_fvBndryCnd->m_nearBoundaryHaloCells[i][j];
37271 for(MInt v = 0; v < noFVars; v++) {
37272 a_rightHandSide(cellId, v) = m_receiveBuffers[i][recvBufferCounter];
37273 recvBufferCounter++;
37274 }
37275 }
37276 }
37277 if(sendCnt > 0) {
37278 MPI_Waitall(sendCnt, &sendReq[0], MPI_STATUSES_IGNORE, AT_);
37279 }
37280
37281#ifndef NDEBUG
37282 divCheck(1);
37283#endif
37284 }
37285
37286#if !defined NDEBUG || defined _MB_DEBUG_
37287 MInt nanCnt = 0;
37288#endif
37289 // 1) Compute the rhs-Update for all small-cells
37290 // interpolation based on bndry-reconstructionConstants,
37291 // which are distance and volume fraction weighted
37292 // rhs/cellVolumes is the effective variable change in the cell (i.e. dQ/dt)
37293 for(MInt smallc = 0; smallc < noSmallCells; smallc++) {
37294 const MInt bndryId = m_fvBndryCnd->m_smallCutCells[smallc];
37295 ASSERT(std::count(m_fvBndryCnd->m_smallCutCells.begin(), m_fvBndryCnd->m_smallCutCells.end(), bndryId) == 1, "");
37296 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
37297 if(a_isPeriodic(cellId)) {
37298 continue;
37299 }
37300 if(a_isHalo(cellId)) {
37301 continue;
37302 }
37303 if(a_hasProperty(cellId, SolverCell::IsPeriodicWithRot)) {
37304 continue;
37305 }
37306 if(a_hasProperty(cellId, SolverCell::IsCutOff) && !m_fvBndryCnd->m_cbcCutOff) {
37307 continue;
37308 }
37309
37310 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
37311 const MInt noRecNghbrs = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size();
37312 if(noRecNghbrs == 0) {
37313 cerr << domainId() << ": Warning: no reconstruction posible in small cell " << cellId << endl;
37314 continue;
37315 }
37316
37317 for(MInt v = 0; v < noFVars; v++) {
37318 rhsNB[v] = F0;
37319
37320 // SmallCell itself and BCs are excluded
37321 for(MInt n = noSrfcs + 1; n < noRecNghbrs; n++) {
37322 if(fabs(m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n]) > m_eps) {
37323 const MInt recNId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
37324 rhsNB[v] += m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n] * a_FcellVolume(recNId)
37325 * a_rightHandSide(recNId, v);
37326 }
37327
37328#if !defined NDEBUG || defined _MB_DEBUG_
37329 if(nanCnt < 100
37330 && (std::isnan(m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n])
37331 || std::isnan(a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], v)))) {
37332 cerr << domainId() << ": "
37333 << " nan detected in smallCellCorrection " << globalTimeStep << "/" << m_RKStep << " "
37334 << " " << cellId << "(" << c_globalId(cellId) << ") " << n << "/" << noRecNghbrs << " " << v << " "
37335 << m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n] << "("
37336 << c_globalId(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n]) << ")"
37337 << " " << m_fvBndryCnd->m_bndryCell[bndryId].m_cellVarsRecConst[IPOW2(noSrfcs) * n] << " "
37338 << a_pvariable(m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n], v) << endl;
37339 nanCnt++;
37340 if(nanCnt == 100) {
37341 cerr << domainId() << ": More than 100 nan's, not reporting any more." << endl;
37342 }
37343 }
37344#endif
37345 }
37346 rhsUpdate[smallc * noFVars + v] = rhsNB[v];
37347 }
37348 }
37349
37350 // 2. Update smallCell RHS
37351 for(MInt smallc = 0; smallc < noSmallCells; smallc++) {
37352 const MInt bndryId = m_fvBndryCnd->m_smallCutCells[(unsigned)smallc];
37353 ASSERT(std::count(m_fvBndryCnd->m_smallCutCells.begin(), m_fvBndryCnd->m_smallCutCells.end(), bndryId) == 1, "");
37354 const MInt cellId = m_fvBndryCnd->m_bndryCells->a[bndryId].m_cellId;
37355 if(a_isPeriodic(cellId)) {
37356 continue;
37357 }
37358 if(a_isHalo(cellId)) {
37359 continue;
37360 }
37361 if(a_hasProperty(cellId, SolverCell::IsPeriodicWithRot)) {
37362 continue;
37363 }
37364 // correct for cbc cutOff cells!
37365 if(a_hasProperty(cellId, SolverCell::IsCutOff) && !m_fvBndryCnd->m_cbcCutOff) {
37366 continue;
37367 }
37368 ASSERT(maxLevel() >= maxUniformRefinementLevel() && maxLevel() <= maxRefinementLevel(), "");
37369
37370 MFloat vfrac = a_cellVolume(cellId) / c_cellVolumeAtLevel(maxLevel());
37371 if(m_localTS) {
37372 vfrac = a_cellVolume(cellId) / c_cellVolumeAtLevel(a_level(cellId));
37373 }
37374 const MFloat volumeLimit = m_fvBndryCnd->m_volumeLimitWall;
37375 MFloat fac = maia::math::deltaFun(vfrac, 1e-16, volumeLimit);
37376
37377 // compute additional factor for boundary condition-sponging
37378 const MFloat volumeLimitSponge = 0.6 * m_fvBndryCnd->m_volumeLimitWall;
37379 const MFloat facSponge = 0.5 - 0.5 * maia::math::deltaFun(vfrac, 1e-16, volumeLimitSponge);
37380
37381 // correction for very very small cells:
37382 // limit the own RHS and increase bndry-cnd sponging for faster convergence
37383 const MFloat limitValue = 0.000047872 * 1.5 / m_cfl;
37384 MFloat spongeFactor = 2;
37385 if(fac < limitValue) {
37386 fac = limitValue;
37387 spongeFactor = 20.0;
37388 }
37389
37390 // set surfc primary variables for sponging towards surface values
37391 // take surface averaged variable
37392 setPrimitiveVariables(cellId);
37393
37394 const MInt noSrfcs = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
37395 MFloatScratchSpace pvars(noPVars, AT_, "pvars");
37396 pvars.fill(0);
37397 MFloat combSurfArea = 0;
37398 for(MInt srfc = 0; srfc < noSrfcs; srfc++) {
37399 combSurfArea += m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area;
37400 if(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcs[srfc]->m_bndryCndId == 3007) {
37401 mTerm(1, AT_, "Not presribed for 3007 bc yet!");
37402 }
37403 for(MInt var = 0; var < noPVars; var++) {
37404 if(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[var] == BC_DIRICHLET) {
37405 const MInt ghostCellId = m_bndryCells->a[bndryId].m_srfcVariables[srfc]->m_ghostCellId;
37406 const MFloat imageVar = F2 * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[var]
37407 - a_pvariable(ghostCellId, var);
37408 const MFloat imageDist =
37409 mMax(F0, (mMax(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance,
37410 F1B2 * c_cellLengthAtLevel(a_level(cellId)))
37411 - m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance));
37412 const MFloat distSum = imageDist + m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
37413 // interpolate cell variable based on distance average of surface and image-point variable
37414 pvars(var) += (m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area / distSum
37415 * (m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[var] * imageDist
37416 + imageVar * m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance));
37417 } else if(m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_variablesType[var] == BC_ROBIN) {
37418 MFloat imageVar = 0;
37419 for(MInt s = 0; s < m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs; s++) {
37420 // imageVar += a_pvariable(cellId,var) *
37421 // m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n];
37422 imageVar += m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[var]
37423 * m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[s];
37424 }
37425 for(MUint n = m_fvBndryCnd->m_bndryCells->a[bndryId].m_noSrfcs;
37426 n < m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds.size();
37427 n++) {
37428 const MInt nghbrId = m_fvBndryCnd->m_bndryCell[bndryId].m_recNghbrIds[n];
37429 imageVar += m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_imagePointRecConst[n]
37430 * a_pvariable(nghbrId, var);
37431 }
37432 const MFloat imageDist =
37433 mMax(F0, (mMax(m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance,
37434 F1B2 * c_cellLengthAtLevel(a_level(cellId)))
37435 - m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance));
37436 const MFloat distSum = imageDist + m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance;
37437 pvars(var) += (m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area / distSum
37438 * (m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[var] * imageDist
37439 + imageVar * m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance));
37440 } else {
37441 // use cell variable directly
37442 pvars(var) += m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area * a_pvariable(cellId, var);
37443 // use surface gradient to extrapolate value in cell
37444 // only different from the above when using the image-variable as reference in the bndry-Cnd!
37445 // const MFloat pValue = m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_primVars[var] +
37446 // m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_centroidDistance *
37447 // m_fvBndryCnd->m_bndryCell[bndryId].m_srfcVariables[srfc]->m_normalDeriv[var];
37448 // pvars(var) += m_fvBndryCnd->m_bndryCells->a[bndryId].m_srfcs[srfc]->m_area * pValue;
37449 }
37450 }
37451 }
37452 for(MInt var = 0; var < noPVars; var++) {
37453 pvars(var) /= combSurfArea;
37454 }
37455
37456 // compute rhs-Sponge based on averaged primary variable on all surfaces
37457 // convert to conservative variables
37458 MFloatScratchSpace cvars(noCVars, AT_, "cvars");
37459 MFloat* avars = hasAV ? &a_avariable(cellId, 0) : nullptr;
37460 sysEqn().computeConservativeVariables(&pvars(0), &cvars(0), avars);
37461
37462 // and apply sponging based on conservative variables
37463 rhsSponge[CV->RHO] = 3 * spongeFactor * (a_variable(cellId, CV->RHO) - cvars(CV->RHO));
37464 for(MInt i = 0; i < nDim; i++) {
37465 rhsSponge[CV->RHO_VV[i]] = spongeFactor * (a_variable(cellId, CV->RHO_VV[i]) - cvars[CV->RHO_VV[i]]);
37466 }
37467 rhsSponge[CV->RHO_E] = spongeFactor * (a_variable(cellId, CV->RHO_E) - cvars[CV->RHO_E]);
37468 for(MInt v = 0; v < noFVars; v++) {
37469 a_rightHandSide(cellId, v) = fac * a_rightHandSide(cellId, v) + facSponge * rhsSponge[v] * a_cellVolume(cellId)
37470 + (F1 - fac - facSponge) * rhsUpdate[smallc * noFVars + v] / a_FcellVolume(cellId);
37471 }
37472 }
37473}
37474
37478template <MInt nDim, class SysEqn>
37480 MFloat* dataSrc, MInt noData,
37481 const std::vector<MInt>& rotIndex) {
37482 TRACE();
37483
37484 if(m_azimuthalRecConstSet) {
37485 // loop over least-squares cell cluster
37486 interpolateAzimuthalData(&dataDest[0], offset, noData, &dataSrc[0]);
37487 // Transform cartesian velocities
37488 if(rotIndex.size() >= (unsigned)1) {
37489 MInt side = m_azimuthalBndrySide[offset];
37490 rotateVectorAzimuthal(side, &dataDest[0], noData, rotIndex);
37491 }
37492 } else {
37493 // cerr << "azimuthalRecConstSet == False; Using nearest neighbor!" << endl;
37494 for(MInt v = 0; v < noData; v++) {
37495 dataDest[v] = dataSrc[cellId * noData + v];
37496 }
37497 // Transform cartesian velocities
37498 // m_azimuthalNearBoundarySide is not allocated yet. Therefore, rotation is not possible yet!
37499 }
37500
37501 for(MInt v = 0; v < noData; v++) {
37502 if(!(dataDest[v] >= F0 || dataDest[v] < F0) || std::isnan(dataDest[v])) {
37503 cerr << globalTimeStep << "/" << m_RKStep << " Window data:" << domainId() << " " << offset << " " << cellId
37504 << "/" << c_globalId(cellId) << " " << c_level(cellId) << " " << c_coordinate(cellId, 0) << " "
37505 << c_coordinate(cellId, 1) << " " << c_coordinate(cellId, nDim - 1) << " "
37506 << (m_levelSetMb ? a_levelSetValuesMb(cellId, 0) : -1) << " // " << v << " " << dataDest[v] << " "
37507 << dataSrc[cellId * noData + v] << endl;
37508
37509 if(m_azimuthalRecConstSet) {
37510 const MInt noNghbrIds = m_noAzimuthalReconstNghbrs[offset];
37511 for(MInt nghbr = 0; nghbr < noNghbrIds; nghbr++) {
37512 MInt recId = m_azimuthalReconstNghbrIds[offset * m_maxNoAzimuthalRecConst + nghbr];
37513 if(!(dataSrc[recId * noData + v] >= F0 || dataSrc[recId * noData + v] < F0)
37514 || std::isnan(dataSrc[recId * noData + v])) {
37515 cerr << "Rec " << nghbr << "/" << (noNghbrIds - 1) << " " << recId << "/";
37516 if(!a_isBndryGhostCell(recId)) {
37517 cerr << c_globalId(recId) << " " << c_level(recId) << " " << c_parentId(recId);
37518 } else {
37519 cerr << "- -";
37520 }
37521 cerr << " " << a_isHalo(recId) << " " << a_hasProperty(recId, SolverCell::IsCutOff) << " "
37522 << a_hasProperty(recId, SolverCell::IsOnCurrentMGLevel) << " " << a_coordinate(recId, 0) << " "
37523 << a_coordinate(recId, 1) << " " << a_coordinate(recId, nDim - 1) << " // " << v << " "
37524 << dataSrc[recId * noData + v] << " "
37525 << m_azimuthalRecConsts[offset * m_maxNoAzimuthalRecConst + nghbr] << endl;
37526 }
37527 }
37528 }
37529 }
37530 }
37531}
37532
37533//----------------------------------------------------------------------------
37534
37539template <MInt nDim, class SysEqn>
37541 MFloat minCoord = std::numeric_limits<MFloat>::max();
37542 MFloat maxCoord = std::numeric_limits<MFloat>::lowest();
37543 for(MInt cellId = 0; cellId < noInternalCells(); cellId++) {
37544 minCoord = mMin(minCoord, a_coordinate(cellId, direction) - F1B2 * c_cellLengthAtLevel(maxRefinementLevel()));
37545 maxCoord = mMax(maxCoord, a_coordinate(cellId, direction) + F1B2 * c_cellLengthAtLevel(maxRefinementLevel()));
37546 }
37547 MPI_Allreduce(MPI_IN_PLACE, &minCoord, 1, MPI_DOUBLE, MPI_MIN, mpiComm(), AT_, "MPI_IN_PLACE", "minCoord");
37548 MPI_Allreduce(MPI_IN_PLACE, &maxCoord, 1, MPI_DOUBLE, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "maxCoord");
37549 return maxCoord - minCoord;
37550}
37551
37556template <MInt nDim, class SysEqn>
37558 mDeallocate(m_A);
37559 mDeallocate(m_ATA);
37560 mDeallocate(m_ATAi);
37561 mDeallocate(m_cellSurfaceMapping);
37562 mDeallocate(m_smallCellIds);
37563 mDeallocate(m_masterCellIds);
37564 mDeallocate(m_activeCellIds);
37565
37566 mDeallocate(m_maxLevelHaloCells);
37567 mDeallocate(m_maxLevelWindowCells);
37568 mDeallocate(m_noMaxLevelHaloCells);
37569 mDeallocate(m_noMaxLevelWindowCells);
37570 mDeallocate(m_sendBuffers);
37571 mDeallocate(m_receiveBuffers);
37572 mDeallocate(m_mpi_request);
37573 mDeallocate(m_sendBuffersNoBlocking);
37574 mDeallocate(m_receiveBuffersNoBlocking);
37575 mDeallocate(m_mpi_sendRequest);
37576 mDeallocate(m_mpi_receiveRequest);
37577
37578 IF_CONSTEXPR(isDetChem<SysEqn>) {
37579 mDeallocate(m_detChem.infSpeciesName);
37580 mDeallocate(m_detChem.infSpeciesMassFraction);
37581 mDeallocate(m_YInfinity);
37582 mDeallocate(m_molarMass);
37583 mDeallocate(m_fMolarMass);
37584 mDeallocate(m_standardHeatFormation);
37585 }
37586
37587 if(m_wmLES) {
37588 mDeallocate(m_noWMImgPointsSend);
37589 mDeallocate(m_noWMImgPointsRecv);
37590 mDeallocate(m_wmImgSendBuffer);
37591 mDeallocate(m_wmImgRecvBuffer);
37592 mDeallocate(m_wmImgRecvIdMap);
37593 mDeallocate(m_mpi_wmRequest);
37594 mDeallocate(m_mpi_wmSendReq);
37595 mDeallocate(m_mpi_wmRecvReq);
37596 }
37597}
37598
37599
37600template <MInt nDim_, class SysEqn>
37602 TRACE();
37603
37604 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
37605
37606 // sort array
37607 sort(m_LESAverageCells.begin(), m_LESAverageCells.end());
37608
37609 mAlloc(m_LESVarAverage, m_LESNoVarAverage, "m_LESVarAverage", AT_);
37610
37611 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
37612 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37613 m_LESVarAverage[var].push_back(F0);
37614 }
37615 }
37616
37617 if(m_calcLESAverage && m_restartLESAverage
37618 && (globalTimeStep > m_zonalAveragingTimeStep || globalTimeStep > m_averageStartTimeStep)) {
37619 loadLESAverage();
37620 } else {
37621 for(MInt var = 0; var < noVariables(); var++) {
37622 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37623 MInt cellId = m_LESAverageCells[c];
37624 ASSERT(c < (MInt)m_LESVarAverage[var].size(),
37625 "Trying to access data [" + to_string(var) + "][" + to_string(c) + "] in m_LESVarAverage with length "
37626 + to_string(m_LESVarAverage[var].size()));
37627
37628 m_LESVarAverage[var][c] = a_pvariable(cellId, var);
37629 }
37630 }
37631
37632 MInt count = 0;
37633 MInt index = 0;
37634 for(MInt i = 0; i < nDim; i++) {
37635 for(MInt j = count; j < nDim; j++) {
37636 MInt indexAvg = index + noVariables();
37637 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37638 MInt cellId = m_LESAverageCells[c];
37639
37640 ASSERT(c < (MInt)m_LESVarAverage[indexAvg].size(),
37641 "Trying to access data [" + to_string(indexAvg) + "][" + to_string(c)
37642 + "] in m_LESVarAverage with length " + to_string(m_LESVarAverage[indexAvg].size()));
37643
37644 m_LESVarAverage[indexAvg][c] = a_pvariable(cellId, i) * a_pvariable(cellId, j);
37645 }
37646 index++;
37647 }
37648 count++;
37649 }
37650 }
37651}
37652
37653template <MInt nDim_, class SysEqn>
37655 TRACE();
37656
37657 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
37658
37659 MFloat avgFactor = getAveragingFactor();
37660
37661 for(MInt var = 0; var < noVariables(); var++) {
37662 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37663 MInt cellId = m_LESAverageCells[c];
37664
37665 ASSERT(c < (MInt)m_LESVarAverage[var].size(),
37666 "Trying to access data [" + to_string(var) + "][" + to_string(c) + "] in m_LESVarAverage with length "
37667 + to_string(m_LESVarAverage[var].size()) + ", domainId: " + to_string(domainId()));
37668
37669 m_LESVarAverage[var][c] = avgFactor * a_pvariable(cellId, var) + (1 - avgFactor) * m_LESVarAverage[var][c];
37670 }
37671 }
37672
37673 MInt count = 0;
37674 MInt index = 0;
37675 for(MInt i = 0; i < nDim; i++) {
37676 for(MInt j = count; j < nDim; j++) {
37677 MInt indexAvg = index + noVariables() + m_averageReconstructNut[0];
37678 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37679 MInt cellId = m_LESAverageCells[c];
37680
37681 ASSERT(c < (MInt)m_LESVarAverage[indexAvg].size(),
37682 "Trying to access data [" + to_string(indexAvg) + "][" + to_string(c)
37683 + "] in m_LESVarAverage with length " + to_string(m_LESVarAverage[indexAvg].size()));
37684
37685 m_LESVarAverage[indexAvg][c] = avgFactor * a_pvariable(cellId, i) * a_pvariable(cellId, j)
37686 + (1 - avgFactor) * m_LESVarAverage[indexAvg][c];
37687 }
37688 index++;
37689 }
37690 count++;
37691 }
37692}
37693
37694template <MInt nDim_, class SysEqn>
37696 TRACE();
37697
37698 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
37699
37700 stringstream fn;
37701 fn.clear();
37702 if(m_useNonSpecifiedRestartFile) {
37703 fn << restartDir() << "restartLESAverage" << m_solverId;
37704 } else {
37705 fn << restartDir() << "restartLESAverage" << m_solverId << "_" << globalTimeStep;
37706 }
37707 fn << ParallelIo::fileExt();
37708
37709 MString fileName = fn.str();
37710
37711 if(domainId() == 0) {
37712 cerr << "loading LES average restart file " << fn.str() << "...";
37713 }
37714
37715 using namespace maia::parallel_io;
37716 ParallelIo parallelIo(fileName, PIO_READ, mpiComm());
37717
37718 ParallelIo::size_type size = 0;
37719 ParallelIo::size_type start = 0;
37720 ParallelIo::size_type count = 0;
37721
37722 size = parallelIo.getArraySize("avgCellIds");
37723
37724 start = 0;
37725 count = size;
37726
37727 vector<MLong> avgCellIds((MInt)size, -1);
37728 ScratchSpace<MFloat> LESVar((MInt)size, AT_, "LESVar");
37729
37730 parallelIo.setOffset(count, start);
37731 parallelIo.readArray(&avgCellIds[0], "avgCellIds");
37732
37733 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
37734 MString s = "LESAverageVar" + to_string(var);
37735 parallelIo.readArray(&LESVar[0], s);
37736
37737 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37738 MInt cellId = m_LESAverageCells[c];
37739
37740 if(a_isBndryGhostCell(cellId)) continue;
37741
37742 MLong gCellId = (MLong)c_globalId(cellId);
37743 vector<MLong>::iterator findLESGlobalId = find(avgCellIds.begin(), avgCellIds.end(), gCellId);
37744 if(findLESGlobalId != avgCellIds.end()) {
37745 MInt dist = std::distance(avgCellIds.begin(), findLESGlobalId);
37746 m_LESVarAverage[var][c] = LESVar[dist];
37747 }
37748 }
37749 }
37750
37751 // set bndryGhostCells
37752 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37753 MInt cellId = m_LESAverageCells[c];
37754 if(a_isBndryCell(cellId)) {
37755 // find corresponding bndryGhostCell and set the value according to BC
37756 for(MInt nghbr = 0; nghbr < a_noReconstructionNeighbors(cellId); nghbr++) {
37757 const MInt recNghbrId = a_reconstructionNeighborId(cellId, nghbr);
37758 if(a_isBndryGhostCell(recNghbrId)) {
37759 vector<MInt>::iterator findBndryGhostId =
37760 find(m_LESAverageCells.begin(), m_LESAverageCells.end(), recNghbrId);
37761 if(findBndryGhostId != m_LESAverageCells.end()) {
37762 MInt index = std::distance(m_LESAverageCells.begin(), findBndryGhostId);
37763
37764 // set values (TODO: only for wall-BC implemented for now)
37765 for(MInt var = 0; var < noVariables(); var++) {
37766 m_LESVarAverage[var][index] = -m_LESVarAverage[var][c];
37767 }
37768 for(MInt var = noVariables(); var < m_LESNoVarAverage; var++) {
37769 m_LESVarAverage[var][index] = m_LESVarAverage[var][c];
37770 }
37771 }
37772 }
37773 }
37774 }
37775 }
37776
37777 if(domainId() == 0) {
37778 cerr << "done" << endl;
37779 }
37780}
37781
37782
37783template <MInt nDim_, class SysEqn>
37785 TRACE();
37786
37787 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
37788
37789 if(domainId() == 0) {
37790 cerr << "Writing LES average restart file at " << globalTimeStep << "...";
37791 }
37792
37793 MLong noAvgCells = 0;
37794 vector<pair<MInt, MInt>> LESCellsGlobalId;
37795 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37796 MInt cellId = m_LESAverageCells[c];
37797 if(a_isHalo(cellId)) continue;
37798 if(a_isPeriodic(cellId)) continue;
37799 if(a_isBndryGhostCell(cellId)) continue;
37800 if(a_hasProperty(cellId, FvCell::IsSplitChild)) continue;
37801 if(a_hasProperty(cellId, FvCell::IsSplitClone)) continue;
37802 MInt globalLESId = c_globalId(cellId);
37803 LESCellsGlobalId.emplace_back(make_pair(globalLESId, c));
37804 noAvgCells++;
37805 }
37806
37807 MLong noAvgCellsGlobal = noAvgCells;
37808 ScratchSpace<MPI_Offset> offsets(noDomains() + 1, AT_, "offsets");
37809 offsets(0) = 0;
37810 if(noDomains() > 1) {
37811 offsets(domainId() + 1) = (MPI_Offset)noAvgCells;
37812
37813 MPI_Allgather(&noAvgCells, 1, MPI_LONG, &offsets[1], 1, MPI_LONG, mpiComm(), AT_, "noAvgCells", "offsets[1]");
37814
37815 for(MInt d = 0; d < noDomains(); d++) {
37816 offsets(d + 1) += offsets(d);
37817 }
37818 noAvgCellsGlobal = noAvgCells;
37819
37820 MPI_Allreduce(MPI_IN_PLACE, &noAvgCellsGlobal, 1, MPI_LONG, MPI_SUM, mpiComm(), AT_, "MPI_IN_PLACE",
37821 "noAvgCellsGlobal");
37822
37823 if(noAvgCellsGlobal != offsets(noDomains())) {
37824 mTerm(1, AT_, "Dimension mismatch.");
37825 }
37826 }
37827
37828 offsets(noDomains()) = (MPI_Offset)noAvgCellsGlobal;
37829
37830 stringstream fn;
37831 fn.clear();
37832 if(m_useNonSpecifiedRestartFile) {
37833 fn << outputDir() << "restartLESAverage" << m_solverId;
37834 } else {
37835 fn << outputDir() << "restartLESAverage" << m_solverId << "_" << globalTimeStep;
37836 }
37837 fn << ParallelIo::fileExt();
37838 MString fileName = fn.str();
37839
37840 MLongScratchSpace avgCellIds(noAvgCells, AT_, "avgCellIds");
37841 for(MInt i = 0; i < noAvgCells; i++) {
37842 avgCellIds[i] = LESCellsGlobalId[i].first;
37843 }
37844
37845 ParallelIo::size_type start = 0;
37846 ParallelIo::size_type count = 0;
37847
37848 using namespace maia::parallel_io;
37849 ParallelIo parallelIo(fileName, PIO_REPLACE, mpiComm());
37850
37851 count = noAvgCellsGlobal;
37852 parallelIo.defineArray(PIO_LONG, "avgCellIds", count);
37853 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
37854 MString s = "LESAverageVar" + to_string(var);
37855 parallelIo.defineArray(PIO_FLOAT, s, count);
37856 }
37857
37858 start = offsets(domainId());
37859 count = noAvgCells;
37860 parallelIo.setOffset(count, start);
37861
37862 parallelIo.writeArray(avgCellIds.begin(), "avgCellIds");
37863
37864 ScratchSpace<MFloat> LESVar(noAvgCells, AT_, "LESVar");
37865 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
37866 MString s = "LESAverageVar" + to_string(var);
37867 for(MInt i = 0; i < noAvgCells; i++) {
37868 LESVar[i] = m_LESVarAverage[var][LESCellsGlobalId[i].second];
37869 }
37870 parallelIo.writeArray(LESVar.begin(), s);
37871 }
37872
37873 if(domainId() == 0) cerr << "ok" << endl;
37874}
37875
37876
37880template <MInt nDim_, class SysEqn>
37882 TRACE();
37883
37884 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
37885
37886 mAlloc(m_STGSpongeFactor, nDim + 3, "m_STGSpongeFactor", AT_);
37887 for(MInt i = 0; i < nDim + 3; i++) {
37888 m_STGSpongeFactor[i].clear();
37889 }
37890
37891 for(MInt varId = 0; varId < nDim + 3; varId++) {
37892 m_STGSpongeFactor[varId].resize(c_noCells());
37893 for(MInt c = 0; c < c_noCells(); c++) {
37894 ASSERT(c < (MInt)m_STGSpongeFactor[varId].size(),
37895 "Trying to access data [" + to_string(varId) + "][" + to_string(c) + "] in m_STGSpongeFactor with length "
37896 + to_string(m_STGSpongeFactor[varId].size()));
37897
37898 m_STGSpongeFactor[varId][c] = F0;
37899 }
37900 }
37901}
37902
37903template <MInt nDim_, class SysEqn>
37905 TRACE();
37906
37907 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
37908
37909 m_spongeLocations.clear();
37910 m_spongeCells.clear();
37911
37912 MInt noSpongeCells = 0;
37913 MInt noSpongeLocations = 0;
37914
37915 // ======================================================
37916 // 1) Determine cells for periodic average
37917 // ======================================================
37918 MFloat periodicL = 0;
37919 MBool first = true;
37920
37921 for(MInt c = 0; c < (MInt)m_LESAverageCells.size(); c++) {
37922 MInt cellId = m_LESAverageCells[c];
37923 if(!c_isLeafCell(cellId)) continue;
37924 MInt averageDir = abs(m_7901wallDir + m_7901periodicDir - nDim);
37925 MFloat pos = a_coordinate(cellId, averageDir);
37926 MFloat halfCellLength = grid().halfCellLength(cellId);
37927
37928 if(approx(m_7901Position, pos, halfCellLength) && !a_isInactive(cellId)) {
37929 if(first) {
37930 periodicL = a_coordinate(cellId, m_7901periodicDir) - F1B3 * halfCellLength;
37931 first = false;
37932 }
37933 if(abs(a_coordinate(cellId, m_7901periodicDir) + halfCellLength - 1e-16 - periodicL) < halfCellLength) {
37934 m_spongeLocations.push_back(a_coordinate(cellId, m_7901wallDir));
37935 m_spongeLocations.push_back(a_coordinate(cellId, m_7901periodicDir));
37936 noSpongeLocations++;
37937 noSpongeLocations++;
37938 }
37939 m_spongeCells.push_back(cellId);
37940 noSpongeCells++;
37941 }
37942 }
37943
37944 m_noSpongeCells = noSpongeCells;
37945
37946 // ======================================================
37947 // 2) Create communicator commSponge
37948 // ======================================================
37949 MInt comm_size;
37950 MPI_Comm_size(mpiComm(), &comm_size);
37951 std::vector<MInt> spongeCellsperDomain(comm_size);
37952
37953 if(noDomains() > 1) {
37954 MPI_Allgather(&noSpongeCells, 1, MPI_INT, &spongeCellsperDomain[0], 1, MPI_INT, mpiComm(), AT_, "noSpongeCells ",
37955 "spongeCellsperDomain");
37956 }
37957
37958 MInt noInvolvedRanks = 0;
37959 std::vector<MInt> involvedRanks(comm_size);
37960 for(MInt i = 0; i < comm_size; i++) {
37961 if(spongeCellsperDomain[i]) {
37962 involvedRanks[noInvolvedRanks] = i;
37963 ++noInvolvedRanks;
37964 }
37965 }
37966
37967 MPI_Comm commSponge;
37968 MPI_Group group;
37969 MPI_Group groupSponge;
37970 MPI_Comm_group(mpiComm(), &group, AT_, "group");
37971 MPI_Group_incl(group, noInvolvedRanks, &involvedRanks[0], &groupSponge, AT_);
37972 MPI_Comm_create(mpiComm(), groupSponge, &commSponge, AT_, "commStg");
37973
37974 m_spongeComm = commSponge;
37975 m_spongeCommSize = noInvolvedRanks;
37976
37977 // find all sponge locations locally on ranks containing the comparison plane
37978 if(m_noSpongeCells > 0) {
37979 for(MInt i = 0; i < noInvolvedRanks; i++) {
37980 if(involvedRanks[i] == domainId()) {
37981 m_spongeRank = i;
37982 break;
37983 }
37984 }
37985
37986 m_spongeRoot = involvedRanks[0];
37987
37988 // ======================================================
37989 // 3) Determine global locations in wall-normal direction for spanwise average
37990 // ======================================================
37991 MInt globalNoBcStgLocations = 0;
37992 MInt globalNoBcStgCells = 0;
37993 MPI_Allreduce(&noSpongeLocations, &globalNoBcStgLocations, 1, MPI_INT, MPI_SUM, m_spongeComm, AT_,
37994 "noSpongeLocations", "globalNoBcStgLocations");
37995
37996 MPI_Allreduce(&noSpongeCells, &globalNoBcStgCells, 1, MPI_INT, MPI_SUM, m_spongeComm, AT_, "noSpongeCells",
37997 "globalNoBcStgCells");
37998
37999 // ScratchSpace<MFloat> globalBcStgLocations(globalNoBcStgLocations, "globalBcStgLocations", FUN_);
38000 mAlloc(m_globalBcStgLocationsG, globalNoBcStgLocations, "m_globalBcStgLocationsG", AT_);
38001 if(m_spongeCommSize > 0) {
38002 ScratchSpace<MInt> recvbuf(comm_size, "recvbuf", FUN_);
38003 recvbuf.fill(0);
38004
38005 MPI_Gather(&noSpongeLocations, 1, MPI_INT, &recvbuf[0], 1, MPI_INT, 0, m_spongeComm, AT_, "noSpongeLocations",
38006 "recvbuf");
38007
38008 ScratchSpace<MInt> displs(comm_size, "displspos", FUN_);
38009 if(domainId() == m_spongeRoot) {
38010 MInt offset = 0;
38011 for(MInt dom = 0; dom < comm_size; dom++) {
38012 displs[dom] = offset;
38013 offset += recvbuf[dom];
38014 }
38015 }
38016
38017 MPI_Gatherv(&m_spongeLocations[0], noSpongeLocations, MPI_DOUBLE, &m_globalBcStgLocationsG[0],
38018 &recvbuf[m_spongeRank], &displs[m_spongeRank], MPI_DOUBLE, 0, m_spongeComm, AT_, "m_spongeLocations",
38019 "globalBcStgLocations");
38020
38021 MPI_Bcast(&m_globalBcStgLocationsG[0], globalNoBcStgLocations, MPI_DOUBLE, 0, m_spongeComm, AT_,
38022 "m_globalBcStgLocationsG");
38023
38024 // for broadcasting to all
38025 m_globalNoSpongeLocations = globalNoBcStgLocations;
38026 // if(domainId() == m_spongeRoot){
38027 // mAlloc(m_globalBcStgLocationsG, globalNoBcStgLocations, "m_globalBcStgLocationsG", AT_);
38028 // for(MInt i = 0; i < globalNoBcStgLocations; i++) {
38029 // m_globalBcStgLocationsG[i] = globalBcStgLocations[i];
38030 // }
38031 // }
38032 }
38033 }
38034
38035 // Broadcast sponge root to all
38036 MPI_Allreduce(MPI_IN_PLACE, &m_spongeRoot, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE", "m_spongeRoot");
38037
38038 // Broadcast from sponge root to all
38039 MInt globalNoBcStgLocationsG = 0;
38040 if(m_noSpongeCells > 0) {
38041 globalNoBcStgLocationsG = m_globalNoSpongeLocations;
38042 }
38043 MPI_Allreduce(MPI_IN_PLACE, &globalNoBcStgLocationsG, 1, MPI_INT, MPI_MAX, mpiComm(), AT_, "MPI_IN_PLACE",
38044 "globalNoBcStgLocationsG");
38045
38046 if(m_noSpongeCells == 0) {
38047 mAlloc(m_globalBcStgLocationsG, globalNoBcStgLocationsG, "m_globalBcStgLocationsG", AT_);
38048 }
38049 MPI_Bcast(&m_globalBcStgLocationsG[0], globalNoBcStgLocationsG, MPI_DOUBLE, m_spongeRoot, mpiComm(), AT_,
38050 "m_globalBcStgLocationsG");
38051
38052 m_globalSpongeLocations.clear();
38053 m_globalNoSpongeLocations = 0;
38054
38055 for(MInt i = 0; i < globalNoBcStgLocationsG / 2; i++) {
38056 MFloat L1 = m_globalBcStgLocationsG[2 * i + 0];
38057 MFloat L2 = m_globalBcStgLocationsG[2 * i + 1];
38058 auto it =
38059 std::find_if(m_globalSpongeLocations.begin(), m_globalSpongeLocations.end(),
38060 [&L1](const std::pair<MFloat, MFloat>& element) { return approx(element.first, L1, 1e-16); });
38061 if(it == m_globalSpongeLocations.end()) {
38062 m_globalSpongeLocations.push_back(make_pair(L1, L2));
38063 m_globalNoSpongeLocations++;
38064 }
38065 }
38066
38067 sort(m_globalSpongeLocations.begin(), m_globalSpongeLocations.end());
38068
38069 // ======================================================
38070 // 4) Determine local cells in periodic locations of global wall-normal locations
38071 // ======================================================
38072 if(m_noSpongeCells > 0) {
38073 mAlloc(m_spongeAverageCellId, m_globalNoSpongeLocations, "m_spongeAverageCellId", FUN_);
38074 mAlloc(m_globalNoPeriodicExchangeCells, m_globalNoSpongeLocations, "m_globalNoPeriodicExchangeCells", 0, FUN_);
38075
38076 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38077 m_spongeAverageCellId[i].clear();
38078 }
38079
38080 vector<MInt> noPeriodicExchangeCells(m_globalNoSpongeLocations, F0);
38081
38082 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38083 for(MInt c = 0; c < m_noSpongeCells; c++) {
38084 MInt cellId = m_spongeCells[c];
38085 if(abs(a_coordinate(cellId, m_7901wallDir) - m_globalSpongeLocations[i].first) < 1e-16) {
38086 if(!a_isHalo(cellId)) {
38087 m_spongeAverageCellId[i].push_back(cellId);
38088 ++noPeriodicExchangeCells[i];
38089 }
38090 }
38091 }
38092 }
38093
38094 if(m_spongeCommSize > 0) {
38095 MPI_Allreduce(&noPeriodicExchangeCells[0], &m_globalNoPeriodicExchangeCells[0], m_globalNoSpongeLocations,
38096 MPI_INT, MPI_SUM, m_spongeComm, AT_, "noPeriodicExchangeCells", "m_globalNoPeriodicExchangeCells");
38097 }
38098 }
38099
38100 mAlloc(m_LESPeriodicAverage, m_LESNoVarAverage, m_globalNoSpongeLocations, "m_LESPeriodicAverage", F0, FUN_);
38101 mAlloc(m_uvErr, m_globalNoSpongeLocations, "m_uvErr", F0, FUN_);
38102 mAlloc(m_uvRans, m_globalNoSpongeLocations, "m_uvRans", F0, FUN_);
38103 mAlloc(m_uvInt, m_globalNoSpongeLocations, "m_uvInt", F0, FUN_);
38104}
38105
38106template <MInt nDim_, class SysEqn>
38108 TRACE();
38109
38110 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
38111
38112 // load preliminary sponge data and fill m_uvRans
38113 stringstream fn;
38114 fn.clear();
38115 MString fname = Context::getSolverProperty<MString>("preliminarySpongeDataFile", m_solverId, AT_, &fname);
38116 if(m_spongeRank == 0) cerr << "loading STG preliminary sponge data from " << fname << "...";
38117
38118 ifstream preliminarySpongeData;
38119 preliminarySpongeData.open(fname);
38120
38121 vector<MFloat> data;
38122 MFloat num;
38123 string line;
38124
38125 while(preliminarySpongeData >> num) {
38126 data.push_back(num);
38127 }
38128
38129 // MInt count = 0;
38130 MInt preliminarySpongeDataVarCount = Context::getSolverProperty<MInt>("preliminarySpongeDataVarCount", m_solverId,
38131 AT_, &preliminarySpongeDataVarCount);
38132 MInt uvIndex = Context::getSolverProperty<MInt>("preliminarySpongeDataUVIndex", m_solverId, AT_, &uvIndex);
38133 MInt dataCount = data.size() / preliminarySpongeDataVarCount;
38134
38135 vector<vector<MFloat>> preData(dataCount, vector<MFloat>(preliminarySpongeDataVarCount, 0));
38136
38137 MInt index = 0;
38138 for(MInt d = 0; d < dataCount; d++) {
38139 for(MInt dd = 0; dd < preliminarySpongeDataVarCount; dd++) {
38140 index = preliminarySpongeDataVarCount * d + dd;
38141 preData[d][dd] = data[index];
38142 }
38143 }
38144
38145 preliminarySpongeData.close();
38146
38147 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38148 MFloat pos = m_globalSpongeLocations[i].first;
38149 for(MInt d = 0; d < dataCount - 1; d++) {
38150 // Interpolation
38151 if(preData[d][0] < pos && preData[d + 1][0] > pos) {
38152 m_uvRans[i] = preData[d][uvIndex]
38153 + (preData[d + 1][uvIndex] - preData[d][uvIndex]) / (preData[d + 1][0] - preData[d][0])
38154 * (pos - preData[d][0]);
38155 }
38156 }
38157 }
38158
38159 if(m_spongeRank == 0) cerr << "ok" << endl;
38160}
38161
38162template <MInt nDim_, class SysEqn>
38164 TRACE();
38165
38166 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
38167
38168 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38169 if(m_zonal) m_uvRans[i] = F0;
38170 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
38171 m_LESPeriodicAverage[var][i] = F0;
38172 }
38173 }
38174
38175 if(m_spongeRank > -1) {
38176 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38177 for(MInt p = 0; p < (MInt)m_spongeAverageCellId[i].size(); p++) {
38178 MInt cellId = m_spongeAverageCellId[i][p];
38179 // find index of cellId
38180 vector<MInt>::iterator findAvgId = find(m_LESAverageCells.begin(), m_LESAverageCells.end(), cellId);
38181 if(findAvgId != m_LESAverageCells.end()) {
38182 MInt avgId = distance(m_LESAverageCells.begin(), findAvgId);
38183 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
38184 m_LESPeriodicAverage[var][i] += m_LESVarAverage[var][avgId] / m_globalNoPeriodicExchangeCells[i];
38185 }
38186 if(m_zonal) {
38187 m_uvRans[i] += m_RANSValues[m_noRANSVariables - 1][cellId] / m_globalNoPeriodicExchangeCells[i];
38188 }
38189 }
38190 }
38191 }
38192
38193 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
38194 MPI_Allreduce(MPI_IN_PLACE, m_LESPeriodicAverage[var], m_globalNoSpongeLocations, MPI_DOUBLE, MPI_SUM,
38195 m_spongeComm, AT_, "MPI_IN_PLACE", "m_LESPeriodicAverage[var]");
38196 }
38197
38198 if(m_zonal) {
38199 MPI_Allreduce(MPI_IN_PLACE, &m_uvRans[0], m_globalNoSpongeLocations, MPI_DOUBLE, MPI_SUM, m_spongeComm, AT_,
38200 "MPI_IN_PLACE", "m_uvRans");
38201 }
38202
38203 // calculate m_uvInt and m_uvErr
38204 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38205 MFloat uv_LES =
38206 m_LESPeriodicAverage[noVariables() + 1][i] - m_LESPeriodicAverage[0][i] * m_LESPeriodicAverage[1][i];
38207 m_uvErr[i] = m_uvRans[i] - uv_LES;
38208 if(abs(m_uvInt[i]) < m_spongeLimitFactor * abs(m_uvRans[i]) ||
38209 // if the sign is differnt, allow the integral to get smaller
38210 m_uvErr[i] * m_uvInt[i] < 1e-16) {
38211 m_uvInt[i] += timeStep() * m_uvErr[i];
38212 }
38213 }
38214 }
38215
38216 // broadcast to all
38217 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
38218 MPI_Bcast(&m_LESPeriodicAverage[var][0], m_globalNoSpongeLocations, MPI_DOUBLE, m_spongeRoot, mpiComm(), AT_,
38219 "m_LESPeriodicAverage");
38220 }
38221 MPI_Bcast(&m_uvInt[0], m_globalNoSpongeLocations, MPI_DOUBLE, m_spongeRoot, mpiComm(), AT_, "m_uvInt");
38222 MPI_Bcast(&m_uvErr[0], m_globalNoSpongeLocations, MPI_DOUBLE, m_spongeRoot, mpiComm(), AT_, "m_uvErr");
38223
38224 if(m_STGSponge) {
38225 MFloat alpha = 10.0;
38226 MFloat beta = 2.0;
38227 // fill m_STGSpongeFactor
38228 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
38229 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38230 MFloat uv_LES =
38231 m_LESPeriodicAverage[noVariables() + 1][i] - m_LESPeriodicAverage[0][i] * m_LESPeriodicAverage[1][i];
38232 MFloat pos = m_globalSpongeLocations[i].first;
38233 if(approx(pos, a_coordinate(cellId, m_7901wallDir), 1e-16)) {
38234 for(MInt d = 0; d < nDim; d++) {
38235 // u - <u>_{z,t}
38236 m_STGSpongeFactor[d][cellId] = a_pvariable(cellId, d) - m_LESPeriodicAverage[d][i];
38237 }
38238 m_STGSpongeFactor[nDim - 1][cellId] = m_uvRans[i];
38239 // e(y,t)
38240 m_STGSpongeFactor[nDim][cellId] = m_uvErr[i];
38241 // r(y,t)
38242 m_STGSpongeFactor[nDim + 1][cellId] = alpha * m_uvErr[i] + beta * m_uvInt[i];
38243 // debug: <u'v'>_{z,t}
38244 m_STGSpongeFactor[nDim + 2][cellId] = uv_LES;
38245 }
38246 }
38247 }
38248 }
38249}
38250
38251
38255template <MInt nDim_, class SysEqn>
38257 TRACE();
38258
38259 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
38260
38261 for(MInt var = 0; var < m_LESNoVarAverage; var++) {
38262 m_LESVarAverage[var].clear();
38263 for(auto it = std::begin(m_LESAverageCells); it != std::end(m_LESAverageCells); ++it) {
38264 m_LESVarAverage[var].push_back(F0);
38265 }
38266 }
38267}
38268
38269
38270template <MInt nDim_, class SysEqn>
38272 TRACE();
38273
38274 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
38275 // find LES cells to be averaged
38276 m_LESAverageCells.clear();
38277
38278 if(!grid().isActive()) return;
38279
38280 if(!m_zonal) {
38281 m_LESNoVarAverage = noVariables() + (nDim - 1) * 3;
38282
38283 MFloat averagePos = m_7901Position;
38284 MInt averageDir = abs(m_7901wallDir + m_7901periodicDir - nDim);
38285 // MInt averageFaceDir = m_7901faceNormalDir;
38286
38287 if(!std::isinf(m_7901Position)) {
38288 // positions to find cells for LES average
38289 m_averagePos.push_back(averagePos);
38290 m_averageDir.push_back(averageDir);
38291 m_averageReconstructNut.push_back(false);
38292 }
38293 }
38294
38295 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) {
38296 for(MInt p = 0; p < (MInt)m_averagePos.size(); p++) {
38297 MInt noLESAverageCells = 0;
38298 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
38299 MFloat halfCellLength = grid().halfCellLength(cellId);
38300 MFloat pos = a_coordinate(cellId, m_averageDir[p]);
38301 if(approx(m_averagePos[p], pos, halfCellLength)) {
38302 m_LESAverageCells.push_back(cellId);
38303 noLESAverageCells++;
38304 }
38305 }
38306
38307 // add neignbor for nu_t reconstruction
38308 if(m_averageReconstructNut[p]) {
38309 for(MInt l = 0; l < noLESAverageCells; l++) {
38310 MInt cellId = m_LESAverageCells[l];
38311 for(MInt nghbr = 0; nghbr < a_noReconstructionNeighbors(cellId); nghbr++) {
38312 const MInt recNghbrId = a_reconstructionNeighborId(cellId, nghbr);
38313
38314 vector<MInt>::iterator findRecNghbrId =
38315 find(m_LESAverageCells.begin(), m_LESAverageCells.end(), recNghbrId);
38316
38317 if(findRecNghbrId == m_LESAverageCells.end()) {
38318 m_LESAverageCells.push_back(recNghbrId);
38319 }
38320 }
38321 }
38322 }
38323
38324 MInt noAvgCellsGlobal = 0;
38325 MInt size = (MInt)m_LESAverageCells.size();
38326 MPI_Allreduce(&size, &noAvgCellsGlobal, 1, MPI_INT, MPI_SUM, mpiComm(), AT_, "size", "noAvgCellsGlobal");
38327
38328 if(domainId() == 0) {
38329 cerr << "m_noLESAverageCells: " << noAvgCellsGlobal << endl;
38330 }
38331 }
38332 }
38333}
38334
38335
38336template <MInt nDim_, class SysEqn>
38338 TRACE();
38339
38340 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) {
38341 for(MInt var = 0; var < m_noLESVariables; var++) {
38342 m_LESValues[var].resize(c_noCells());
38343 }
38344 }
38345 else {
38346 for(MInt var = 0; var < m_noRANSVariables; var++) {
38347 m_RANSValues[var].resize(c_noCells());
38348 }
38349 }
38350}
38351
38352
38353template <MInt nDim_, class SysEqn>
38355 TRACE();
38356
38357 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
38358
38359 if(m_spongeRank > -1 && domainId() == m_spongeRoot) {
38360 stringstream fn;
38361 fn.clear();
38362 if(m_useNonSpecifiedRestartFile) {
38363 fn << outputDir() << "stgSpongeData";
38364 } else {
38365 fn << outputDir() << "stgSpongeData_" << globalTimeStep;
38366 }
38367 fn << ".txt";
38368
38369 MString fname = fn.str();
38370
38371 cerr << "Writing STG sponge data at " << globalTimeStep << " ..";
38372
38373 MString header = "#x1 x2 m_uvInt";
38374
38375 ofstream spongeData;
38376 spongeData.precision(16);
38377
38378 spongeData.open(fname);
38379 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38380 MString line;
38381 line.append(to_string(m_globalSpongeLocations[i].first) + ";" + to_string(m_globalSpongeLocations[i].second) + ";"
38382 + to_string(m_uvInt[i]) + ";");
38383
38384 spongeData << line << endl;
38385 }
38386 spongeData.close();
38387
38388 cerr << "ok" << endl;
38389 }
38390}
38391
38392template <MInt nDim_, class SysEqn>
38394 TRACE();
38395
38396 IF_CONSTEXPR(SysEqn::m_noRansEquations > 0) return;
38397
38398 if(m_spongeRank > -1 && domainId() == m_spongeRoot) {
38399 stringstream fn;
38400 fn.clear();
38401 if(m_useNonSpecifiedRestartFile) {
38402 fn << restartDir() << "stgSpongeData";
38403 } else {
38404 fn << restartDir() << "stgSpongeData_" << globalTimeStep;
38405 }
38406 fn << ".txt";
38407
38408 MString fname = fn.str();
38409
38410 cerr << "Loading STG sponge data at " << globalTimeStep << " ..";
38411
38412 ifstream spongeData;
38413 spongeData.open(fname);
38414
38415 vector<double> data(3);
38416 char ch;
38417 MFloat num;
38418
38419 while(spongeData >> num) {
38420 data.push_back(num);
38421 spongeData >> ch;
38422 }
38423
38424 // MInt count = 0;
38425 if(m_globalSpongeLocations.size() == 0) {
38426 cerr << "ERROR in loading sponge data" << endl;
38427 return;
38428 }
38429 MInt dataCount = 0;
38430 for(MInt i = 0; i < m_globalNoSpongeLocations; i++) {
38431 for(unsigned int d = 0; d < data.size() - 3; d++) {
38432 // read wall normal position and compare it to calculated wall positions
38433 if(d % 3 == 0) {
38434 // Interpolation
38435 if((data[d] <= m_globalSpongeLocations[i].first || approx(data[d], m_globalSpongeLocations[i].first, 1e-8))
38436 && (data[d + 3] >= m_globalSpongeLocations[i].first
38437 || approx(data[d + 3], m_globalSpongeLocations[i].first, 1e-8))) {
38438 m_uvInt[i] =
38439 data[d + 2]
38440 + (data[d + 5] - data[d + 2]) / (data[d + 3] - data[d]) * (m_globalSpongeLocations[i].first - data[d]);
38441 dataCount++;
38442 }
38443 }
38444 }
38445 }
38446
38447 // check if all data was correctly read
38448 if(dataCount != m_globalNoSpongeLocations) {
38449 cerr << "not all data was correctly read" << endl;
38450 cerr << "read data count: " << dataCount << ", should be: " << m_globalNoSpongeLocations << endl;
38451 }
38452
38453 spongeData.close();
38454
38455 cerr << "ok" << endl;
38456 }
38457
38458 // commuicate data to all ranks
38459 if(m_spongeRank > -1 && m_spongeCommSize > 0) {
38460 MPI_Allreduce(MPI_IN_PLACE, &m_uvInt[0], m_globalNoSpongeLocations, MPI_DOUBLE, MPI_SUM, m_spongeComm, AT_,
38461 "MPI_IN_PLACE", "m_uvInt");
38462 }
38463}
38464
38465
38466template <MInt nDim_, class SysEqn>
38468 TRACE();
38469
38470 // exchange LESVarAverage
38471 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) {
38472 // add halo cells
38473 //----------------------------------
38474 for(MInt p = 0; p < (MInt)m_averagePos.size(); p++) {
38475 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
38476 MFloat halfCellLength = grid().halfCellLength(cellId);
38477 MFloat pos = a_coordinate(cellId, m_averageDir[p]);
38478 if(approx(m_averagePos[p], pos, halfCellLength) && a_isHalo(cellId)) {
38479 m_LESAverageCells.push_back(cellId);
38480 for(MInt v = 0; v < m_LESNoVarAverage; v++) {
38481 m_LESVarAverage[v].push_back(F0);
38482 }
38483 }
38484 }
38485
38486 // add neignbor for nu_t reconstruction
38487 if(m_averageReconstructNut[p]) {
38488 for(auto it = std::begin(m_LESAverageCells); it != std::end(m_LESAverageCells); ++it) {
38489 // for(MInt c = 0; c < m_noLESAverageCells ; c++){
38490 MInt cellId = *it; // m_LESAverageCells[c];
38491 if(a_isHalo(cellId)) {
38492 for(MInt nghbr = 0; nghbr < a_noReconstructionNeighbors(cellId); nghbr++) {
38493 const MInt recNghbrId = a_reconstructionNeighborId(cellId, nghbr);
38494
38495 if(a_hasProperty(recNghbrId, FvCell::IsSplitChild)) continue;
38496 if(a_hasProperty(recNghbrId, FvCell::IsSplitClone)) continue;
38497
38498 vector<MInt>::iterator findRecNghbrId =
38499 find(m_LESAverageCells.begin(), m_LESAverageCells.end(), recNghbrId);
38500
38501 if(findRecNghbrId == m_LESAverageCells.end()) {
38502 m_LESAverageCells.push_back(recNghbrId);
38503 for(MInt v = 0; v < m_LESNoVarAverage; v++) {
38504 m_LESVarAverage[v].push_back(F0);
38505 }
38506 }
38507 }
38508 }
38509 }
38510 }
38511 }
38512 //----------------------------------
38513
38514 // exchange halo cells
38515 for(MInt v = 0; v < m_LESNoVarAverage; v++) {
38516 ScratchSpace<MFloat> exchangeLESVarAverage(c_noCells(), "exchangeLESVarAverage", FUN_);
38517 exchangeLESVarAverage.fill(F0);
38518 for(MInt cellId = 0; cellId < c_noCells(); cellId++) {
38519 vector<MInt>::iterator findAverageId = find(m_LESAverageCells.begin(), m_LESAverageCells.end(), cellId);
38520 if(findAverageId != m_LESAverageCells.end()) {
38521 MInt LESAvgId = distance(m_LESAverageCells.begin(), findAverageId);
38522 if(!a_isHalo(cellId)) {
38523 // if(LESAvgId < m_LESAverageCellsHaloOffset){
38524 exchangeLESVarAverage[cellId] = m_LESVarAverage[v][LESAvgId];
38525 }
38526 }
38527 }
38528
38529 exchangeData(&exchangeLESVarAverage[0], 1);
38530
38531 for(MInt LESAvgId = 0; LESAvgId < (MInt)m_LESAverageCells.size(); LESAvgId++) {
38532 MInt cellId = m_LESAverageCells[LESAvgId];
38533 if(a_isHalo(cellId)) {
38534 m_LESVarAverage[v][LESAvgId] = exchangeLESVarAverage[cellId];
38535 }
38536 }
38537 }
38538 }
38539}
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
define the names of all variables and attributes in the netcdf file
const MChar * time
const MChar * globalTimeStep
const MChar * physicalTime
static MInt propertyLength(const MString &name, MInt solverId=m_noSolvers)
Returns the number of elements of a property.
Definition: context.cpp:538
static MBool propertyExists(const MString &name, MInt solver=m_noSolvers)
This function checks if a property exists in general.
Definition: context.cpp:494
void computeSrfcs(MInt, MInt, MInt, MInt)
virtual void computeConservativeVariables()
Dispatches the computation of the conservative variables for different number of species.
void resetSolver() override
Reset the solver prior to load balancing.
virtual void LSReconstructCellCenter()
Dispatch the reconstruction computation to the appropiate loop.
virtual MFloat & vorticityAtCell(const MInt cellId, const MInt dir)
void computeQCriterion(MFloatScratchSpace &qCriterion)
virtual void viscousFlux_Gequ_Pv_Plenum()
Computes the viscous flux using a central difference scheme, modified version for flame plenum comput...
virtual void computePrimitiveVariablesCoarseGrid()
Computes the primitive variables: velocity, density, and pressure from the conservative variables and...
MFloat cv_p(MInt cellId) const noexcept
Returns the pressure computed from the conservative variables of the cell cellId.
virtual void initNearBoundaryExchange(const MInt mode=0, const MInt offset=0)
Setup the near-boundary communicator needed for the flux-redistribution method.
virtual void loadGridFlowVarsPar(const MChar *fileName)
This function loads the flow information of the cells such as variables and attributes like u_velocit...
void exchangeFloatDataAzimuthal(MFloat *data, MInt noVars, const std::vector< MInt > &rotIndices)
MFloat computeTimeStepApeDirectional(MInt cellId) const noexcept
MFloat computeWMViscositySpalding(MInt)
void computeSpeciesReactionRates()
Dispatches the species reaction rate computation at each cell by calling the relevant method from the...
void setAndAllocateCombustionGequPvProperties()
reads in the combustion properties
void viscousFluxCompact_(F &viscousFluxFct)
Computes the viscous fluxes using a compact stencil with increased stability for flows with dominatin...
void getSolverTimings(std::vector< std::pair< MString, MFloat > > &solverTimings, const MBool allTimings) override
Get solver timings.
void resizeGridMap() override
Swap the given cells.
virtual void determineLESAverageCells()
virtual void calcSamplingVariables(const std::vector< MInt > &varIds, const MBool exchange) override
Calculate sampling variables.
MBool requiresTimeStepUpdate() const
Returns true if the time-step should be updated on this step.
virtual void nonReflectingBCAfterTreatmentCutOff()
void setAndAllocateSpongeLayerProperties()
Reads and initializes properties associated with sponge boundary conditions.
MInt cellDataSizeDlb(const MInt dataId, const MInt gridCellId) override
Return data size to be communicated during DLB for a grid cell and given data id.
virtual MInt getAdjacentLeafCells_d2_c(const MInt, const MInt, MIntScratchSpace &, MIntScratchSpace &)
MFloat reduceData(const MInt cellId, MFloat *data, const MInt dataBlockSize=1, const MBool average=true)
determines the value of 'data' in the given cell by recusively volumetric averaging among all its off...
void deleteSrfcs()
Deletes all surfaces existing.
void balance(const MInt *const noCellsToReceiveByDomain, const MInt *const noCellsToSendByDomain, const MInt *const targetDomainsByCell, const MInt oldNoCells) override
Balance the solver.
void setMeanMolarWeight_PV(MInt cellId)
FvCartesianSolverXD()=delete
void computeConservativeVariablesCoarseGrid()
Computes the primitive variables: velocity, density, and pressure from the conservative variables and...
void getGlobalSolverVars(std::vector< MFloat > &globalFloatVars, std::vector< MInt > &globalIdVars) override
Get/set global solver variables during DLB.
virtual void smallCellRHSCorrection(const MInt timerId=-1)
void reInitActiveCellIdsMemory()
Allocate memory to arrays according to the current number of cells.
std::vector< MInt > findWallNormalNeighbors(MInt pointId)
MFloat computeWMViscositySpalding3D(MInt)
virtual void writeListOfActiveFlowCells()
void rotateVectorAzimuthal(MInt side, MFloat *data, MInt noData, const std::vector< MInt > &indices)
void sensorEntropyQuot(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
void setAndAllocateJetProperties()
reads in the jet properties
void resetExternalSources()
Reset external sources.
virtual void setConservativeVariables(MInt cellId)
computes conservative from primitive variables for given cell id
void LSReconstructCellCenterCons(const MUint noSpecies)
virtual void copyRHSIntoGhostCells()
virtual MInt getAdjacentLeafCells_d0_c(const MInt, const MInt, MIntScratchSpace &, MIntScratchSpace &)
void tripForceCoefficients(MFloat *, MFloat *, MFloat *, MInt, MInt)
virtual void computeSurfaceValuesLOCD(MInt timerId=-1)
virtual MFloat getBoundaryHeatFlux(const MInt cellId) const
calculates heat flux of boundary cells
virtual void computeSurfaceValuesLimitedSlopes(MInt timerId=-1)
void getInterpolatedVariablesInCell(const MInt cellId, const MFloat *position, MFloat *vars)
calculates interpolated variables for a given position in a given cell
MInt setUpBndryInterpolationStencil(const MInt, MInt *, const MFloat *)
void removeCell(const MInt) override
Remove the given cell.
void getDefaultWeights(MFloat *weights, std::vector< MString > &names) const
Return the default weights for all load quantities.
void getInterpolatedVariables(const MInt cellId, const MFloat *position, MFloat *vars) override
calculates interpolated variables for a given position in a given cell
virtual void computeReconstructionConstants()
void computeMeanMolarWeights_PV()
Dispatches the mean molar weight computation at the cell center from the primitive variables by calli...
void findNeighborHood(MInt cellId, MInt layer, std::vector< MInt > &nghbrList)
Obtain list of neighbors for the given extend.
void setAndAllocateAdaptationProperties()
This function reads the properties required for adaptive mesh refinement.
void initAzimuthalReconstruction()
void resetSponge()
reset sponge properties
virtual void cutOffBoundaryCondition()
virtual void resetRHSNonInternalCells()
void checkGhostCellIntegrity()
Checks whether cells' isGhost and the boundary Id coincede. Cells' isGhost is is used to tell the gri...
void saveSolverSolution(const MBool forceOutput=false, const MBool finalTimeStep=false) override
Manages solver-specific output.
void finalizeAdaptation() override
void swapCells(const MInt, const MInt) override
void linearInterpolation(MInt, MInt, MInt *)
virtual void initInterpolationForCell(const MInt cellId)
Init the interpolation for points inside a given cell (based on interpolateVariables())
virtual void resetBoundaryCells(const MInt offset=0)
void loadRestartTime(const MChar *fileName, MInt &globalTimeStepInput, MFloat &timeInput, MFloat &physicalTimeInput)
This function loads the flow information of the cells such as variables and attributes like u_velocit...
void extendStencil(const MInt)
extend the reconstruction sencil towards all diagonal cells on the first layer
virtual void resetSolverFull()
MBool useTimeStepFromRestartFile() const
Returns true if the time-step from a restart file should be reused.
virtual MInt getAdjacentLeafCells_d2(const MInt, const MInt, MIntScratchSpace &, MIntScratchSpace &)
void prepareAdaptation() override
void calculateHeatRelease()
calculates heatRelease, currently used for postprocessing (average_in)
void setAndAllocateZonalProperties()
std::array< MFloat, nDim_+2 > computeSpongeDeltas(MInt cellId, std::array< MFloat, 6 >)
void setCombustionGequPvVariables()
reads in the combustion properties
void exchangeAzimuthalRemappedHaloCells()
void loadSampleVariables(MInt timeStep)
load variables for the specified timeStep
MFloat time() const override
returns the time
MFloat crankAngle(const MFloat, const MInt)
help-function for engine calculations which returns the crank-angle for a given time mode = 0: return...
void setSamplingProperties()
Reads properties associated with variable sampling.
void buildLeastSquaresStencilSimple()
Determine the least squares stencil.
void bilinearInterpolation(MInt, MInt, MInt *)
void computeGamma()
Dispatches the gamma computation at each cell by calling the relevant function from the detChemSysEqn...
void writeCutCellsToGridFile()
Writes cut cell information to an existing grid file in order to visualize it in ParaView.
std::array< MFloat, 6 > computeTargetValues()
virtual void viscousFlux_Gequ_Pv()
Computes the viscous flux using a central difference scheme.
void setMeanMolarWeight_CV(MInt cellId)
Computes the mean molar weight at the given cell ID from the primitive variables. The mean molar weig...
virtual void getDimensionalizationParams(std::vector< std::pair< MFloat, MString > > &dimParams) const
get dimensionalization parameters
void setInputOutputProperties()
Reads properties and initializes variables associated with input/output.
void reInitSmallCellIdsMemory()
Reallocate memory to small and master cell id arrays according to the current number of cells.
MBool prepareRestart(MBool, MBool &) override
Prepare the solvers for a grid-restart.
void send(const MBool exchangeAll=false)
Send window cell data to corresponding neighbors.
void saveDebugRestartFile()
Saves the solver restart file and the grid restartFile NOTE: for debugging purposes only!...
virtual void initSolutionStep(MInt)
Initializes the solver.
virtual void correctBoundarySurfaces_()
virtual void saveRestartFile(const MBool)
MFloat computeTimeStep(MInt cellId) const noexcept
void finalizeBalance() override
Reinitialize solver after all data structures have been recreated.
void sensorVorticity(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
void computeDomainAndSpongeDimensions()
Extracts the minimum and maximum coordinates of all cells in the grid.
void setRungeKuttaProperties()
This function reads the properties required for Runge Kutta time stepping.
virtual void initializeRungeKutta()
Reads the Runge-Kutta properties and initializes the variables required for Runge Kutta time stepping...
void finalizeMpiExchange()
Finalize non-blocking MPI communication (cancel open requests, free all requests)
void startMpiExchange()
Begin non-blocking communication by posting new send requests.
void saveGridFlowVarsPar(const MChar *fileName, MInt noTotalCells, MLong noInternalCells, MFloatScratchSpace &variables, std::vector< MString > &dbVariablesName, MInt, MIntScratchSpace &idVariables, std::vector< MString > &idVariablesName, MInt, MFloatScratchSpace &dbParameters, std::vector< MString > &dbParametersName, MIntScratchSpace &idParameters, std::vector< MString > &idParametersName, const MInt *recalcIds)
This function stores the massivley parallel flow information of the cells.
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.
MBool cellOutside(const MInt)
void setNumericalProperties()
Reads and initializes properties associated with the numerical method.
void computeGridCellCoordinates(MFloat *)
computes the coordinates of the grid cell centers and stores them into a one-dimensional array
void computeVorticity2D(MFloat *const vorticity)
void computeVorticity3D(MFloat *const vorticity)
void createBoundaryCells()
identifies bndry cells (Sets a_isInterface for the solver!)
MFloat setAndAllocateSpongeDomainProperties(MFloat)
reads in the sponge properties for the domain boundaries
void getSampleVariables(MInt cellId, const MFloat *&vars)
read only access to primitive variables of a single cell
virtual void filterConservativeVariablesAtFineToCoarseGridInterfaces()
void initAzimuthalMaxLevelExchange()
void setConservativeVarsOnAzimuthalRecCells()
void sensorInterfaceLs(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen)
virtual void correctMasterCells()
adds the right hand side of small cells to their corresponding master cells and sets the small cell R...
MInt getAdjacentLeafCells(const MInt, const MInt, MIntScratchSpace &, MIntScratchSpace &)
retrieves the first 'noLayers' layers of direct and(or diagonal neighbors to the given cell
void fillExcBufferAzimuthal(MInt cellId, MInt offset, MFloat *dataDest, MFloat *dataSrc, MInt noData, const std::vector< MInt > &rotIndex=std::vector< MInt >())
void computeForceCoefficients(MFloat *)
void azimuthalNearBoundaryReverseExchange()
MFloat cv_a(MInt cellId) const noexcept
Returns the speed-of-sound computed from the conservative variables of the cell cellId.
virtual MInt getAdjacentLeafCells_d1_c(const MInt, const MInt, MIntScratchSpace &, MIntScratchSpace &)
virtual void Muscl(MInt=-1)
Reconstructs the flux on the surfaces.
void sensorInterface(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
virtual void convertPrimitiveRestartVariables()
converts the primitive restart variables to a new Mach Number
virtual void getSolverSamplingProperties(std::vector< MInt > &samplingVars, std::vector< MInt > &noSamplingVars, std::vector< std::vector< MString > > &samplingVarNames, const MString featureName="") override
Read sampling related properties.
void bilinearInterpolationAtBnd(MInt, MInt, MInt *)
void scatter()
Scatter received data of all neighbors to the corresponding halo cells.
virtual void initSolverSamplingVariables(const std::vector< MInt > &varIds, const std::vector< MInt > &noSamplingVars) override
Initialize sampling variables/allocate memory.
void sensorCutOff(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen)
void allocateAndInitSolverMemory()
Allocates the resources of the FV solver. Mostly arrays of size maxNoCells used in the main part of t...
void interpolateVariablesInCell(const MInt cellId, const MFloat *position, std::function< MFloat(MInt, MInt)> variables, MFloat *result)
Interpolate the given variable field inside a cell at a given position (based on interpolateVariables...
void swapProxy(const MInt, const MInt) override
void setAndAllocateDetailedChemistryProperties()
void azimuthalNearBoundaryExchange()
void interpolateAzimuthalDataReverse(MFloat *data, MInt offset, MInt noVars, const MFloat *vars)
void sensorPatch(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
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 setTestcaseProperties()
Reads and initializes properties associated with the physics of the simulation and allocates small ar...
virtual void initializeMaxLevelExchange()
parallel: Store all necessary data in send buffer
MFloat cv_T(MInt cellId) const noexcept
Returns the temperature computed from the conservative variables of the cell cellId.
virtual void smallCellCorrection(const MInt timerId=-1)
Flux-redistribution method Apply a stable correction to small-cells and redistribute the defective fl...
MInt determineRestartTimeStep() const override
Determine the restart time step from the restart file (for useNonSpecifiedRestartFile = true)
void computeReconstructionConstantsSVD()
Compute the reconstruction constants using a weighted least squares approached solved via singular va...
void sensorInterfaceLsMb(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen)
void exchangeGapInfo()
exchanges the Gap-Information with the solver-own communicators!
virtual void resetImplicitCoefficients()
void interpolateVariables(const MInt cellId, const MFloat *position, MFloat *result)
calculates interpolated variables (in the range a, b) for a given position in a given cell
void limitWeights(MFloat *) override
Limit Weight types to avoid large memory disbalance between ranks for DLB.
void correctMajorSpeciesMassFraction()
Corrects the mass fraction of the predominant species to ensure conservation due to numerical or appr...
void interpolateAzimuthalData(MFloat *data, MInt offset, MInt noVars, const MFloat *vars)
void refineCell(const MInt) override
void computeSamplingTimeStep_()
computes the time step according to the sample variables
void getPrimitiveVariables(MInt, MFloat *, MFloat *, MInt)
void initSolver() override
Initializes the fv-solver.
void finishMpiExchange()
Finish non-blocking communication by waiting for receive requests.
void gather()
Gather data of all window cells for all neighbors in the send buffers.
void initAzimuthalCartesianHaloInterpolation()
void lhsBnd()
Apply lhsBnd.
void sensorDerivative(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
computes the sensor values for a derivative sensor
MInt noLoadTypes() const override
void balancePost() override
Reinitialize solver after setting solution data in DLB.
virtual void updateSpongeLayer()
computes the additional rhs of all cells lying inside the sponge layer to dissipate outgoing waves.
void getHeatRelease(MFloat *&heatRelease)
returns
void getLoadQuantities(MInt *const loadQuantities) const override
Return the cumulative load quantities on this domain.
void removeChilds(const MInt) override
virtual void nonReflectingBCCutOff()
MFloat getCellLoad(const MInt cellId, const MFloat *const weights) const override
Return the load of a single cell (given computational weights).
void computeInitialPressureLossForChannelFlow()
Computes pressure loss for the initial condition of channel flow testcases as . Requires property ReT...
void applyCoarseLevelCorrection()
Apply coarse-level correction to RHS.
virtual void getVorticity(MFloat *const vorticity)
wrapper for vorticity computation
void implicitTimeStep() override
virtual void applyInitialCondition()
Initializes the entire flow field.
void setGlobalSolverVars(std::vector< MFloat > &globalFloatVars, std::vector< MInt > &globalIdVars) override
Set global solver variables (see getGlobalSolverVars())
virtual MInt getAdjacentLeafCells_d1(const MInt, const MInt, MIntScratchSpace &, MIntScratchSpace &)
MFloat computeTimeStepEulerDirectional(MInt cellId) const noexcept
void cancelMpiRequests() override
Cancel open MPI (receive) requests.
virtual void loadOldVariables(const MString &fileName)
This function loads oldVariable data from a restartFile-type file.
virtual void computePrimitiveVariables()
Dispatches the computation of the primitive variables for different number of species.
void initCanteraObjects()
Allocates the Cantera objects that define a thermodynamic phase, reaction kinetics and transport prop...
void lhsBndFinish()
Finish the split MPI communication and perform the left out part from lhsBnd().
void computeVorticity3DT(MFloat *const vorticity)
Compute vorticity and store in vorticity pointer (transposed version)
virtual void calcSamplingVarAtPoint(const MFloat *point, const MInt id, const MInt sampleVarId, MFloat *state, const MBool interpolate=false) override
Calculate the sampling variables at a given point in a cell.
void updateSpongeLayerRhs(MInt, std::array< MFloat, nDim_+2 >)
virtual MInt getAdjacentLeafCells_d0(const MInt, const MInt, MIntScratchSpace &, MIntScratchSpace &)
virtual void distributeFluxToCells()
Distributes the surface fluxes to the cell RHS.
MInt noVariables() const override
Return the number of primitive variables.
void initializeFvCartesianSolver(const MBool *propertiesGroups)
FV Constructor: reads and allocate properties/variables:
virtual void applyBoundaryCondition()
handles the application of boundary conditions to the ghost cells
virtual void computeLimitedSurfaceValues(MInt timerId=-1)
void tripFourierCoefficients(MFloat *, MInt, MFloat, MFloat)
void computeMeanMolarWeights_CV()
Dispatches the mean molar weight computation at the cell center from the conservative variables by ca...
void sensorParticle(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
virtual void resetZonalLESAverage()
Initializes zonal exchange arrays.
void setInfinityState()
Computes/defines the infinity values/state once and for all Ideally the infinity variables should not...
virtual void computeSurfaceValuesLimitedSlopesMan(MInt timerId=-1)
aaplies the slope limiter to the slopes before calling computeSurfaceValues_
MFloat interpolateWallNormalPointVars(MInt var, MFloat coords[], MInt localId, std::vector< MInt > neighborList)
void viscousFlux_(F &viscousFluxFct)
Computes the viscous flux using a central difference scheme to approximate the slopes at the surface ...
void setPrimitiveVariables(MInt cellId)
computes primitive from primitive variables for given cell id. This is the version for all SysEqn.
virtual void resetRHSCutOffCells()
void sensorSpecies(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
void initializeTimers()
Initializes the communication timers.
void computeSurfaceCoefficients()
Dispatches the transport coefficients computation at each surfaces by calling the relevant function f...
virtual void setCellProperties()
void computeAcousticSourceTermQe(MFloatScratchSpace &, MFloatScratchSpace &, MFloatScratchSpace &, MFloatScratchSpace &)
MInt getNghbrLeafCells(const MInt cellId, MInt refCell, MInt layer, MInt *nghbrs, MInt dir, MInt dir1=-1, MInt dir2=-1) const
returns the neighbor leaf cells in the specified direction 'dir' (dir1 and dir2 are used to identify ...
void setAndAllocateCombustionTFProperties()
Reads and initializes properties associated with combustion simulations.
void writeRestartFile(const MBool, const MBool, const MString, MInt *) override
virtual void reIntAfterRestart(MBool)
virtual void applyExternalSource()
Add external sources to the RHS.
void checkForSrfcsMGC()
Check all existing cells if surfaces have to be created member function with the task to check all ex...
void exchangeExternalSources()
Exchange external sources.
virtual void getVorticityT(MFloat *const vorticity)
wrapper for vorticity computation (transposed version)
void oldPressure(MFloat *const p)
This function computes the pressure from the oldVariables.
void findDirectNghbrs(MInt cellId, std::vector< MInt > &nghbrList)
Obtain list of direct neighbors of given cell.
virtual void initComputeSurfaceValuesLimitedSlopesMan1()
initializes the limiter at cells, that are in the vicinity of a given stl-geometry
void sensorInterfaceDelta(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen)
void setActiveFlag(MIntScratchSpace &, const MInt mode, const MInt offset)
Set the flag for the cells needed for near bndry exchange.
virtual void copyVarsToSmallCells()
MBool cellParticipatesInTimeStep(MInt cellId) const noexcept
Does the cell cellId participate in the time-step computation?
void allocateCommunicationMemory()
Allocates and initializes send/receive buffers for multiSolver computations.
void checkInfinityVarsConsistency()
Check that all infinity (or other global) variables are equal on all ranks.
void initAzimuthalNearBoundaryExchange(MIntScratchSpace &activeFlag)
void exchangeProperties()
exchanges isInactive and isOnCurrentMGLevel
virtual void correctBoundarySurfaces()
void resetCutOffCells()
resets all Cut-Off Information should only be called before the adaptation and balance!
MFloat computeTimeStepMethod(MInt cellId) const noexcept
Computes the time-step of the cell cellId.
void interpolateSurfaceDiffusionFluxOnCellCenter(MFloat *const, MFloat *const)
void checkCellSurfaces()
checks if the surfaces for a cell are correct and balanced The accumulated cell surfaces in +x direct...
virtual void resetZonalSolverData()
virtual bool rungeKuttaStep()
Dispatches the RungeKutta method for different number of species.
void getDomainDecompositionInformation(std::vector< std::pair< MString, MInt > > &domainInfo) override
Return decomposition information, i.e. number of local elements,...
MBool solutionStep() override
Performs one Runge-Kutta step of the FV solver, returns true if the time step is completed.
void setAndAllocateSpongeBoundaryProperties()
reads in the sponge properties for specific boundaries
void checkForSrfcsMGC_2_()
Check all existing cells if surfaces have to be created member function with the task to check all ex...
virtual void updateMultiSolverInformation(MBool fullReset=false)
virtual MBool gridPointIsInside(MInt, MInt)
void checkAzimuthalRecNghbrConsistency(MInt cellId)
void rebuildAzimuthalReconstructionConstants(MInt cellId, MInt offset, MFloat *recCoord, MInt mode=0)
void reduceVariables()
Check whether any of the extracted cells lie below the halo cell level and interpolate their variable...
void postTimeStep() override
: Performs the post time step
void receive(const MBool exchangeAll=false)
Receive halo cell data from corresponding neighbors.
MFloat computeDomainLength(MInt direction)
void sensorEntropyGrad(std::vector< std::vector< MFloat > > &sensors, std::vector< std::bitset< 64 > > &sensorCellFlag, std::vector< MFloat > &sensorWeight, MInt sensorOffset, MInt sen) override
void finalizeInitSolver() override
Initializes the solver afer the initialRefinement!
virtual void initComputeSurfaceValuesLimitedSlopesMan2()
can be used to apply the slope limiter at certain positions such as refinement interfaces,...
virtual void initSTGSponge()
Initializes zonal exchange arrays.
void dumpCellData(const MString name)
Dump cell data of each rank to a separate file for debugging purposes.
virtual void computeAzimuthalReconstructionConstants(MInt mode=0)
void setCellWeights(MFloat *) override
MFloat computeRecConstSVD(const MInt cellId, const MInt offset, MFloatScratchSpace &tmpA, MFloatScratchSpace &tmpC, MFloatScratchSpace &weights, const MInt recDim, const MInt, const MInt, const std::array< MBool, nDim > dirs={}, const MBool relocateCenter=false)
compute the reconstruction constants of the given cell by a weighted least-squares approach via singu...
void balancePre() override
Reinitialize solver for DLB prior to setting solution data.
virtual void getSampleVarsDerivatives(const MInt cellId, const MFloat *&vars)
Access derivatives of primitive variables of a given cell.
MFloat computeTimeStepDiffusionNS(MFloat density, MFloat temperature, MFloat Re, MFloat C, MFloat dx) const noexcept
void getSampleVariableNames(std::vector< MString > &varNames) override
Return the sample variable names (primitive variables)
virtual void LSReconstructCellCenter_Boundary()
Computes the slopes at the cell centers of only the boundary cells.
virtual void getBoundaryDistance(MFloatScratchSpace &)
Get distance to boundary, currently bc 3003. Should be replaced by more precise distance using STL in...
MBool isOnGeometry(const MFloat, const MFloat *, MString)
Definition: geometry.cpp:748
static MString printSelfReport()
Returns a shortened string summing up the scratch space state information.
Definition: scratch.cpp:129
static MString printSelf()
Returns a string summing up the scratch state information and all scratch space elements information.
Definition: scratch.cpp:106
This class is a ScratchSpace.
Definition: scratch.h:758
size_type size() const
Definition: scratch.h:302
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
Definition: iovtk.h:24
void writeVtkXmlOutput(const MChar *fileName)
Copy of parallel single-file VTU output using MPI I/O.
Definition: iovtk.cpp:180
Checks if the primitive variable C exists.
void set(const T &value)
Initializes tensor to constant value.
Definition: tensor.h:271
size_type size() const
Returns the size of the array as product of all five dimensions (i.e. not the actual array size but t...
Definition: tensor.h:206
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ MAIA_MPI_FV_TAG
Definition: enums.h:20
@ FV_HEAT_RELEASE
Definition: enums.h:384
@ FV_VORT
Definition: enums.h:384
@ FV_PV
Definition: enums.h:384
@ NETCDF
Definition: enums.h:18
@ VTK
Definition: enums.h:18
@ VTP
Definition: enums.h:18
@ VTU
Definition: enums.h:18
@ HOCD_LIMITED
Definition: enums.h:180
@ LOCD
Definition: enums.h:180
@ HOCD_LIMITED_SLOPES_MAN
Definition: enums.h:180
@ HOCD
Definition: enums.h:180
@ HOCD_LIMITED_SLOPES
Definition: enums.h:180
@ SUZI_TC
Definition: enums.h:178
@ TINA_TC
Definition: enums.h:178
@ EULER
Definition: enums.h:176
@ FIVE_POINT_STABILIZED
Definition: enums.h:184
@ FIVE_POINT
Definition: enums.h:184
@ THREE_POINT
Definition: enums.h:184
@ SLAU
Definition: enums.h:182
@ AUSM
Definition: enums.h:182
@ AUSMPLUS
Definition: enums.h:182
@ RANS_SA_DV
Definition: enums.h:54
@ RANS_SST
Definition: enums.h:57
@ RANS_FS
Definition: enums.h:55
@ RANS_KOMEGA
Definition: enums.h:56
SolverType
Definition: enums.h:22
@ MAIA_FV_APE
Definition: enums.h:24
@ COMBUSTION
Definition: enums.h:276
@ LS_SOLVER
Definition: enums.h:280
@ LEVELSETMB
Definition: enums.h:275
@ LEVELSET
Definition: enums.h:274
@ LS_RANS
Definition: enums.h:277
@ BC_ROBIN
Definition: enums.h:334
@ BC_UNSET
Definition: enums.h:334
@ BC_NEUMANN
Definition: enums.h:334
@ BC_ISOTHERMAL
Definition: enums.h:334
@ BC_DIRICHLET
Definition: enums.h:334
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
const MString const MString & message
Definition: functions.h:37
constexpr Real POW3(const Real x)
Definition: functions.h:123
constexpr Real POW2(const Real x)
Definition: functions.h:119
Real ABS(const Real x)
Definition: functions.h:85
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
@ IsSplitChild
cell is a split child
@ IsSplitClone
cell is an older-version of a splitchild
@ IsOnCurrentMGLevel
ATTRIBUTES1(ATTRIBUTE_NO_AUTOVEC) void FvCartesianSolverXD< nDim_
resets the solver
constexpr bool hasE
const MInt m_revDir[6]
MInt globalTimeStep
void printAllocatedMemory(const MLong oldAllocatedBytes, const MString &solverName, const MPI_Comm comm)
Prints currently allocated memory.
MInt globalNoDomains()
Return global number of domains.
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
MInt noSolvers
Definition: maiatypes.h:73
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_Send_init(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_Send_init
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_File_seek(MPI_File mpi_fh, MPI_Offset offset, int whence, const MString &name)
same as MPI_File_seek
int MPI_Waitsome(int incount, MPI_Request array_of_requests[], int *outcount, int array_of_indices[], MPI_Status array_of_statuses[], const MString &name)
same as MPI_Waitsome
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_Recv_init(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_Recv_init
int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_create, but updates the number of MPI communicators
int MPI_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_File_open(MPI_Comm comm, const char *filename, int amode, MPI_Info info, MPI_File *mpi_fh, const MString &name)
same as MPI_File_open
int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup, const MString &name)
same as MPI_Group_incl
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group, const MString &name, const MString &varname)
same as MPI_Comm_group
int MPI_Cancel(MPI_Request *request, const MString &name)
same as MPI_cancel
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_Exscan(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_Exscan
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_File_close(MPI_File *mpi_fh, const MString &name)
same as MPI_File_close
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_Request_free(MPI_Request *request, const MString &name)
same as MPI_Request_free
int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_split, but updates the number of MPI communicators
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
int MPI_Alltoallv(const void *sendbuf, const int sendcounts[], const int sdispls[], MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int rdispls[], MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Alltoallv
int MPI_Startall(int count, MPI_Request array_of_requests[], const MString &name)
same as MPI_Startall
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, const MString &name, const MString &varname)
same as MPI_Send
void const MInt const MInt const MInt const MInt maxNoCells
Definition: collector.h:240
void const MInt cellId
Definition: collector.h:239
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.
void cross(const T *const u, const T *const v, T *const c)
Definition: maiamath.h:101
MFloat RBF(const MFloat R, const MFloat R0)
radial base function
Definition: maiamath.h:873
MInt sgn(T val)
Definition: maiamath.h:495
MFloat distance(const MFloat *a, const MFloat *b)
Definition: maiamath.h:249
void invert(MFloat *A, const MInt m, const MInt n)
Definition: maiamath.cpp:171
MFloat frobeniusMatrixNormSquared(MFloatScratchSpace &m, MInt dim1, MInt dim2)
Definition: maiamath.h:328
MFloat deltaFun(const MFloat r, const MFloat r0, const MFloat r1)
Definition: maiamath.h:885
void initFft(fftw_complex *uPhysField, fftw_complex *vPhysField, fftw_complex *wPhysField, MInt lx, MInt ly, MInt lz, MInt noPeakModes, const MFloat Ma)
Generates a velocity field from Fourier-modes using FFTW.
Definition: maiafftw.h:892
MFloat crankAngle(const MFloat time, const MFloat Strouhal, const MFloat offset, const MInt mode)
help-function for engine calculations which returns the crank-angle for a given time,...
Definition: maiamath.h:506
MInt inverse(MFloat **a, MFloat **ainv, MInt n, const MFloat epsilon)
Definition: maiamath.h:587
MInt getGlobalPosFFTW(MInt i0, MInt i1, MInt i2, MInt ny, MInt nz)
Definition: maiafftw.h:59
MInt invertR(T &A, T &weights, T &AInv, const MInt m, const MInt n)
Definition: maiamath.cpp:280
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 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 reverseExchangeAddData(const std::vector< MInt > &nghbrDomains, const std::vector< std::vector< MInt > > &haloCellVec, const std::vector< std::vector< MInt > > &windowCellVec, const MPI_Comm comm, U **const data, const MInt noDat=1)
Generic exchange from halo to window cells, however in this case the value in the halo-cell is added ...
Definition: mpiexchange.h:1205
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
const MInt PIO_INT
Definition: parallelio.h:48
const MInt PIO_LONG
Definition: parallelio.h:50
const MInt PIO_CREATE
< File mode to create a new file. Aborts if file already exists
Definition: parallelio.h:34
const MInt PIO_READ
Definition: parallelio.h:40
Namespace for auxiliary functions/classes.
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
MInt nearest(Point< DIM > pt, MFloat &dist)
Definition: kdtree.h:199
Definition: pointbox.h:20
Definition: contexttypes.h:19
define array structures