MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
fvstructuredsolver.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#include <cmath>
9#include <cstdlib>
10#include "COMM/mpioverride.h"
12#include "IO/parallelio.h"
13#include "IO/parallelio_hdf5.h"
14#include "UTIL/maiamath.h"
16#include "globals.h"
17#if not defined(MAIA_MS_COMPILER)
18#include <unistd.h>
19#endif
20#include <vector>
21
22using namespace std;
23
32template <MInt nDim>
34 const MPI_Comm comm)
35 : Solver(solverId, comm),
37 m_grid(grid_),
38 m_eps(std::numeric_limits<MFloat>::epsilon()) {
39 (void)propertiesGroups;
40 const MLong oldAllocatedBytes = allocatedBytes();
41
42 // initialize all timers
43 initTimers();
44
45 if(domainId() == 0) {
46 cout << "Initializing Structured Solver..." << endl;
47 }
48
49 m_isActive = true;
50
51 // for the zonal approach we will have to split the communicator
52 m_StructuredComm = comm;
53
54 // intialize the most important properties
55 initializeFvStructuredSolver(propertiesGroups);
56
57 // numericals method:
59
60 // set testcase parameters
62
63 // set moving grid parameters
65
67
68 // initialize cell
74 RECORD_TIMER_START(m_timers[Timers::GridDecomposition]);
75 m_grid->gridDecomposition(false);
76 RECORD_TIMER_STOP(m_timers[Timers::GridDecomposition]);
77
78
79 m_log << "Setting porous properties..." << endl;
81 m_log << "Setting porous properties... SUCCESSFUL!" << endl;
83 m_log << "Setting zonal properties..." << endl;
85 m_log << "Setting zonal properties... SUCCESSFUL!" << endl;
86
87 m_log << "Allocating variables..." << endl;
89 m_log << "Allocating variables... SUCCESSFUL!" << endl;
90
91 m_log << "Reading input output properties..." << endl;
93 m_log << "Reading input output properties... SUCCESSFUL!" << endl;
94
98 // 4) assign window winformation (3D-2D possible because of dimension)
99 // but be careful, only 3D has been tested and implemented
100 m_grid->setCells(m_cells);
101 m_grid->prepareReadGrid(); // determines grid dimensions (point and cell wise) and allocates m_grid->m_coordinates
103 m_noCells = m_grid->m_noCells;
104 m_noActiveCells = m_grid->m_noActiveCells;
105 m_noPoints = m_grid->m_noPoints;
106 m_totalNoCells = m_grid->m_totalNoCells;
108 m_nOffsetCells = m_grid->m_nOffsetCells;
109 m_nOffsetPoints = m_grid->m_nOffsetPoints;
110 m_nPoints = m_grid->m_nPoints;
111 m_nActivePoints = m_grid->m_nActivePoints;
112 m_nCells = m_grid->m_nCells;
113 m_nActiveCells = m_grid->m_nActiveCells;
114 m_noBlocks = m_grid->getNoBlocks();
115 m_blockId = m_grid->getMyBlockId();
116
118 make_unique<FvStructuredSolverWindowInfo<nDim>>(m_grid, m_StructuredComm, noDomains(), domainId(), m_solverId);
119
120 m_windowInfo->readWindowInfo();
121 m_windowInfo->initGlobals();
123 m_windowInfo->readWindowCoordinates(m_grid->m_periodicDisplacements);
124
130 Context::getSolverProperty<MBool>("setLocalWallDistance", m_solverId, AT_, &m_setLocalWallDistance);
131 IF_CONSTEXPR(nDim == 3) {
132 if(m_setLocalWallDistance) mTerm(-1, "Not implemented in 3D yet!");
133 }
135 if(!m_setLocalWallDistance) m_windowInfo->setWallInformation();
136 }
137
138 // Create the mapping for the boundary and domain windows
139 // the windows are needed for boundary condition application
140 // and data exchange between the domains
146 &m_grid->m_hasSingularity, &m_plenumComm, &m_plenumRoot);
148 m_singularity = m_grid->m_singularity; // new SingularInformation[30]; //TODO_SS labels:FV,totest check this
149 m_hasSingularity = m_grid->m_hasSingularity;
151 //
154 // Creating the communication flags needed
155 // for all inter-domain exchange operations
157
159 // set flag for the periodic exchange
160 for(MInt i = 0; i < (MInt)m_windowInfo->rcvMap.size(); i++) {
161 if(m_windowInfo->rcvMap[i]->BC >= 4000 && m_windowInfo->rcvMap[i]->BC <= 4999) {
163 break;
164 }
165 }
166
167 // TODO_SS labels:FV,toremove the following is not used
168 // if(m_zonal || m_rans) {
169 // if (m_setLocalWallDistance)
170 // m_windowInfo->setLocalWallInformation();
171 // }
172
176 // Information about singularities needs to be known for allocating metrices
177 m_grid->allocateMetricsAndJacobians();
178
180
181 m_windowInfo->createCommunicationExchangeFlags(m_sndComm, m_rcvComm, PV->noVariables, m_cells->pvariables);
182
183 MInt averageCellsPerDomain = (MInt)(m_totalNoCells / noDomains());
184 MFloat localDeviation = ((MFloat)averageCellsPerDomain - (MFloat)m_noActiveCells) / ((MFloat)averageCellsPerDomain);
185 MFloat localDeviationSquare = POW2(localDeviation);
186 MFloat globalMaxDeviation = F0;
187 MFloat globalMinDeviation = F0;
188 MFloat globalAvgDeviation = F0;
189 MInt globalMaxNoCells = 0;
190 MInt globalMinNoCells = 0;
191 MPI_Allreduce(&localDeviation, &globalMaxDeviation, 1, MPI_DOUBLE, MPI_MAX, m_StructuredComm, AT_, "localDeviation",
192 "globalMaxDeviation");
193 MPI_Allreduce(&localDeviation, &globalMinDeviation, 1, MPI_DOUBLE, MPI_MIN, m_StructuredComm, AT_, "localDeviation",
194 "globalMinDeviation");
195 MPI_Allreduce(&localDeviationSquare, &globalAvgDeviation, 1, MPI_DOUBLE, MPI_SUM, m_StructuredComm, AT_,
196 "localDeviation", "globalAvgDeviation");
197 globalAvgDeviation = sqrt(globalAvgDeviation / noDomains());
198 MPI_Allreduce(&m_noActiveCells, &globalMaxNoCells, 1, MPI_INT, MPI_MAX, m_StructuredComm, AT_, "m_noActiveCells",
199 "globalMaxNoCells");
200 MPI_Allreduce(&m_noActiveCells, &globalMinNoCells, 1, MPI_INT, MPI_MIN, m_StructuredComm, AT_, "m_noActiveCells",
201 "globalMinNoCells");
202
204 if(domainId() == 0) {
205 cout << "///////////////////////////////////////////////////////////////////" << endl
206 << "Total no. of grid cells: " << m_totalNoCells << endl
207 << "Average cells per domain: " << averageCellsPerDomain << endl
208 << "Max no of cells per domain: " << globalMaxNoCells << endl
209 << "Min no of cells per domain: " << globalMinNoCells << endl
210 << "Average deviation from average: " << globalAvgDeviation * 100.0 << " percent" << endl
211 << "Maximum deviation from average: +" << globalMaxDeviation * 100.0 << " / " << globalMinDeviation * 100.0
212 << " percent" << endl
213 << "///////////////////////////////////////////////////////////////////" << endl;
214 }
215
216 // read the grid from partition and
217 // and move coordinates to right position
218 if(domainId() == 0) {
219 cout << "Reading Grid..." << endl;
220 }
221 m_log << "->reading the grid file" << endl;
222 RECORD_TIMER_START(m_timers[Timers::GridReading]);
223 m_grid->readGrid();
224 RECORD_TIMER_STOP(m_timers[Timers::GridReading]);
225 m_log << "------------- Grid read successfully! -------------- " << endl;
226 if(domainId() == 0) {
227 cout << "Reading Grid SUCCESSFUL!" << endl;
228 }
229
230 // get the zonal BC information
231 if(m_zonal) {
232 m_windowInfo->setZonalBCInformation();
233 }
234
235 // set properties for synthetic turbulence generation method
237
238 // set the properties for bc2600 (if existing)
240
241 // initialize the postprocessing class
243
244 // print allocated scratch memory
245 if(domainId() == 0) {
246 MFloat scratchMemory = (Scratch::getTotalMemory() / 1024.0) * noDomains();
247 MString memoryUnit = " KB";
248 if(scratchMemory > 1024.0) {
249 scratchMemory /= 1024.0;
250 memoryUnit = " MB";
251 }
252 if(scratchMemory > 1024.0) {
253 scratchMemory /= 1024.0;
254 memoryUnit = " GB";
255 }
256 cout << "=== Total global scratch space memory: " << setprecision(2) << fixed << scratchMemory << memoryUnit
257 << " ===" << endl;
260 printAllocatedMemory(oldAllocatedBytes, "FvStructuredSolver", m_StructuredComm);
264template <MInt nDim>
266 RECORD_TIMER_STOP(m_timers[Timers::Structured]);
267 delete m_cells;
268}
276template <MInt nDim>
278 TRACE();
279 // count the number of needed FQ fields and allocate
280 MInt noFQFieldsNeeded = 0;
281 for(MInt i = 0; i < FQ->maxNoFQVariables; i++) {
282 noFQFieldsNeeded += FQ->neededFQVariables[i];
283 }
284
285 FQ->noFQVariables = noFQFieldsNeeded;
286
287 m_log << "Allocating " << noFQFieldsNeeded << " FQ fields for " << m_noCells << "..." << endl;
288 mAlloc(m_cells->fq, noFQFieldsNeeded, m_noCells, "m_cells->fq", F0, AT_);
289 mAlloc(FQ->loadedFromRestartFile, noFQFieldsNeeded, "FQ->loadedFromRestartFile", false, AT_);
290 m_log << "Allocating " << noFQFieldsNeeded << " FQ fields for " << m_noCells << "...SUCCESSFUL" << endl;
291
292 MInt currentPos = 0;
293 for(MInt i = 0; i < FQ->maxNoFQVariables; i++) {
294 if(FQ->neededFQVariables[i] == 0) {
295 continue;
296 }
297
298 FQ->activateFQField(i, currentPos, FQ->outputFQVariables[i], FQ->boxOutputFQVariables[i]);
299
300 FQ->noFQBoxOutput += (MInt)FQ->boxOutputFQVariables[i];
301 currentPos++;
302 }
303}
304
305template <MInt nDim>
307 if(m_movingGrid || m_bodyForce) {
308 if(m_travelingWave) {
309 mAlloc(m_tempWaveSample, (PV->noVariables + (2 * nDim - 3)), m_noCells, "m_tempWaveSample", F0, FUN_);
310 }
311 }
312
313 if(m_localTimeStep) {
314 mAlloc(m_cells->localTimeStep, m_noCells, "m_cells->localTimeStep", -1.01010101, AT_);
315 }
316
317 mAlloc(m_cells->variables, m_maxNoVariables, m_noCells, "m_cells->variables", -99999.0, AT_);
318 mAlloc(m_cells->pvariables, m_maxNoVariables, m_noCells, "m_cells->pvariables", -99999.0, AT_);
319 mAlloc(m_cells->temperature, m_noCells, "m_cells->temperature", -99999.0, AT_);
320 mAlloc(m_cells->oldVariables, m_maxNoVariables, m_noCells, "m_cells->oldVariables", -99999.0, AT_);
321 mAlloc(m_cells->dss, nDim, m_noCells, "m_cells->dss", F0, AT_);
322
323
324 // always allocate moving grid volume fluxes
325 // but leave them zero if not moving grid
326 mAlloc(m_cells->dxt, nDim, m_noCells, "m_cells->dxt", F0, AT_);
327
328 // allocate viscous flux computation variables
329 MInt noVarsFluxes = (CV->noVariables - 1 + m_rans);
330
331 m_log << "Allocating fFlux with " << (CV->noVariables - 1 + m_rans) << " variables for " << m_noCells << " cells"
332 << endl;
333
334 mAlloc(m_cells->rightHandSide, CV->noVariables, m_noCells, "m_cells->rhs", F0, AT_);
335 mAlloc(m_cells->flux, CV->noVariables, m_noCells, "m_cells->flux", 10000.0, AT_);
336 mAlloc(m_cells->eFlux, noVarsFluxes, m_noCells, "m_cells->eFlux", F0, AT_);
337 mAlloc(m_cells->fFlux, noVarsFluxes, m_noCells, "m_cells->fFlux", F0, AT_);
338 mAlloc(m_cells->gFlux, noVarsFluxes, m_noCells, "m_cells->gFlux", F0, AT_);
339 // TODO_SS labels:FV,toenhance find a better way to save porous variables
340 mAlloc(m_cells->viscousFlux, (nDim + m_porous), m_noCells, "m_cells->viscousFlux", 1000.0, AT_);
341
342 mAlloc(m_QLeft, m_maxNoVariables, "m_QLeft", F0, AT_);
343 mAlloc(m_QRight, m_maxNoVariables, "m_QRight", F0, AT_);
344
345
346 IF_CONSTEXPR(nDim == 2) {
347 if(m_viscCompact) mAlloc(m_cells->dT, 4, m_noCells, "m_cells->dT", F0, AT_);
348 }
349}
350
351
355template <MInt nDim>
357 TRACE();
358
359 m_outputIterationNumber = 0;
360 m_outputFormat = ".hdf5";
361 m_lastOutputTimeStep = -1;
362
376 m_forceOutputInterval = 0;
377 if(Context::propertyExists("forceOutputInterval", m_solverId)) {
378 m_forceOutputInterval =
379 Context::getSolverProperty<MInt>("forceOutputInterval", m_solverId, AT_, &m_forceOutputInterval);
380 } else if(Context::propertyExists("dragOutputInterval", m_solverId)) {
381 m_forceOutputInterval =
382 Context::getSolverProperty<MInt>("dragOutputInterval", m_solverId, AT_, &m_forceOutputInterval);
383 }
384
385 if(m_forceOutputInterval > 0) {
394 m_auxOutputDir = m_solutionOutput;
395 if(Context::propertyExists("auxOutputDir", m_solverId)) {
396 m_auxOutputDir = Context::getSolverProperty<MString>("auxOutputDir", m_solverId, AT_);
397
398 MString comparator = "/";
399 if(strcmp((m_auxOutputDir.substr(m_auxOutputDir.length() - 1, 1)).c_str(), comparator.c_str()) != 0) {
400 m_auxOutputDir = m_auxOutputDir + "/";
401 }
402 }
403 }
404
418 m_forceAsciiOutputInterval = 0;
419 if(Context::propertyExists("forceAsciiOutputInterval", m_solverId)) {
420 m_forceAsciiOutputInterval =
421 Context::getSolverProperty<MInt>("forceAsciiOutputInterval", m_solverId, AT_, &m_forceAsciiOutputInterval);
422 } else if(Context::propertyExists("dragAsciiOutputInterval", m_solverId)) {
423 m_forceAsciiOutputInterval =
424 Context::getSolverProperty<MInt>("dragAsciiOutputInterval", m_solverId, AT_, &m_forceAsciiOutputInterval);
425 }
426
427
441 m_forceAsciiComputeInterval = 0;
442 if(Context::propertyExists("forceAsciiComputeInterval", m_solverId)) {
443 m_forceAsciiComputeInterval =
444 Context::getSolverProperty<MInt>("forceAsciiComputeInterval", m_solverId, AT_, &m_forceAsciiComputeInterval);
445 } else if(Context::propertyExists("dragAsciiComputeInterval", m_solverId)) {
446 m_forceAsciiComputeInterval =
447 Context::getSolverProperty<MInt>("dragAsciiComputeInterval", m_solverId, AT_, &m_forceAsciiComputeInterval);
448 }
449
450 if(m_forceAsciiComputeInterval > m_forceAsciiOutputInterval) {
451 m_forceAsciiComputeInterval = m_forceAsciiOutputInterval;
452 }
453
454 if(m_forceAsciiOutputInterval > 0 && m_forceAsciiComputeInterval == 0) {
455 m_forceAsciiComputeInterval = 1;
456 }
457
470 m_forceSecondOrder = true;
471 if(Context::propertyExists("forceSecondOrder", m_solverId)) {
472 m_forceSecondOrder = Context::getSolverProperty<MBool>("forceSecondOrder", m_solverId, AT_, &m_forceSecondOrder);
473 } else if(Context::propertyExists("dragSecondOrder", m_solverId)) {
474 m_forceSecondOrder = Context::getSolverProperty<MBool>("dragSecondOrder", m_solverId, AT_, &m_forceSecondOrder);
475 }
476
477 if(m_forceSecondOrder) {
478 m_log << "Second order force computation is activated" << endl;
479 }
480
493 m_outputOffset = 0;
494 m_outputOffset = Context::getSolverProperty<MInt>("outputOffset", m_solverId, AT_, &m_outputOffset);
495
510 m_ignoreUID = 0;
511 if(Context::propertyExists("ignoreUID", m_solverId)) {
512 m_ignoreUID = Context::getSolverProperty<MBool>("ignoreUID", m_solverId, AT_, &m_ignoreUID);
513 m_log << "WARNING!!!!!!!!!!!!!!: UID was not checked. Solution and grid might not fit together" << endl;
514 }
515
528 m_restart = false;
529 m_restart = Context::getSolverProperty<MBool>("restartFile", m_solverId, AT_, &m_restart);
530
531 m_restartTimeStep = 0;
532
540 m_useNonSpecifiedRestartFile = false;
541 m_useNonSpecifiedRestartFile =
542 Context::getSolverProperty<MBool>("useNonSpecifiedRestartFile", m_solverId, AT_, &m_useNonSpecifiedRestartFile);
543
558 m_changeMa = false;
559 if(m_restart) {
560 m_changeMa = Context::getSolverProperty<MBool>("changeMa", m_solverId, AT_, &m_changeMa);
561 }
562
576 m_debugOutput = false;
577 m_debugOutput = Context::getSolverProperty<MBool>("debugOutput", m_solverId, AT_, &m_debugOutput);
578
579 if(m_debugOutput) {
580 FQ->neededFQVariables[FQ->BLOCKID] = 1;
581 FQ->neededFQVariables[FQ->CELLID] = 1;
582 }
583
584 FQ->neededFQVariables[FQ->MU_L] = 1;
585 FQ->outputFQVariables[FQ->MU_L] = false;
586 FQ->neededFQVariables[FQ->MU_T] = 1;
587 FQ->outputFQVariables[FQ->MU_T] = false;
588
602 m_savePartitionOutput = false;
603 m_savePartitionOutput =
604 Context::getSolverProperty<MBool>("savePartitionOutput", m_solverId, AT_, &m_savePartitionOutput);
605
619 m_bForce = false;
620 if(Context::propertyExists("computeForce", m_solverId)) {
621 m_bForce = Context::getSolverProperty<MBool>("computeForce", m_solverId, AT_, &m_bForce);
622 } else if(Context::propertyExists("computeCfCp", m_solverId)) {
623 m_bForce = Context::getSolverProperty<MBool>("computeCfCp", m_solverId, AT_, &m_bForce);
624 }
625
626 if(m_bForce) {
627 m_log << "<<<<< Skin-friction and Pressure Coefficient Computation: ENABLED" << endl;
628 }
629
643 m_bPower = false;
644 m_bPower = Context::getSolverProperty<MBool>("computePower", m_solverId, AT_, &m_bPower);
645 if(m_bPower) {
646 m_log << "<<<<< Power Computation: ENABLED" << endl;
647 }
648
662 m_detailAuxData = false;
663 m_detailAuxData = Context::getSolverProperty<MBool>("detailAuxData", m_solverId, AT_, &m_detailAuxData);
664
678 m_bForceLineAverage = false;
679 if(Context::propertyExists("computeForceLineAverage", m_solverId)) {
680 m_bForceLineAverage =
681 Context::getSolverProperty<MBool>("computeForceLineAverage", m_solverId, AT_, &m_bForceLineAverage);
682 } else if(Context::propertyExists("computeCpLineAverage", m_solverId)) {
683 m_bForceLineAverage =
684 Context::getSolverProperty<MBool>("computeCpLineAverage", m_solverId, AT_, &m_bForceLineAverage);
685 }
686
701 m_forceAveragingDir = 0;
702 if(Context::propertyExists("forceAveragingDir", m_solverId)) {
703 m_forceAveragingDir = Context::getSolverProperty<MInt>("forceAveragingDir", m_solverId, AT_, &m_forceAveragingDir);
704 } else if(Context::propertyExists("cpAveragingDir", m_solverId)) {
705 m_forceAveragingDir = Context::getSolverProperty<MInt>("cpAveragingDir", m_solverId, AT_, &m_forceAveragingDir);
706 }
707
721 m_auxDataCoordinateLimits = false;
722 m_auxDataCoordinateLimits =
723 Context::getSolverProperty<MBool>("auxDataCoordinateLimits", m_solverId, AT_, &m_auxDataCoordinateLimits);
724
725 // verify the conditions for auxilary data computation, i.e., when force output is higher than 1 then cp and cf should
726 // be enabled
727 if(m_forceOutputInterval || m_forceAsciiOutputInterval) {
728 if(!m_bForce) {
729 m_bForce = true;
730 }
731 }
732
733 if(m_auxDataCoordinateLimits) {
734 m_auxDataLimits = nullptr;
735 MInt noAuxDataLimits = 4;
736 mAlloc(m_auxDataLimits, noAuxDataLimits, "m_auxDataLimits", F0, AT_);
737
738 for(MInt i = 0; i < noAuxDataLimits; ++i) {
752 m_auxDataLimits[i] = -99999.9;
753 m_auxDataLimits[i] = Context::getSolverProperty<MFloat>("auxDataLimits", m_solverId, AT_, &m_auxDataLimits[i], i);
754 }
755
756 m_log << "AuxData limited area"
757 << ", lower x-limit: " << m_auxDataLimits[0] << ", upper x-limit: " << m_auxDataLimits[1]
758 << ", lower z-limit: " << m_auxDataLimits[2] << ", upper z-limit: " << m_auxDataLimits[3] << endl;
759 }
760
774 m_computeLambda2 = false;
775 m_computeLambda2 = Context::getSolverProperty<MBool>("computeLambda2", m_solverId, AT_, &m_computeLambda2);
776 if(m_computeLambda2) {
777 FQ->neededFQVariables[FQ->LAMBDA2] = 1;
778 FQ->boxOutputFQVariables[FQ->LAMBDA2] = 1;
779 }
780
781
794 m_vorticityOutput = false;
795 m_vorticityOutput = Context::getSolverProperty<MBool>("vorticityOutput", m_solverId, AT_, &m_vorticityOutput);
796
797
810 m_averageVorticity = false;
811 m_averageVorticity = Context::getSolverProperty<MBool>("pp_averageVorticity", m_solverId, AT_, &m_averageVorticity);
812
813 if(m_vorticityOutput || m_averageVorticity) {
814 for(MInt v = 0; v < nDim; v++) {
815 FQ->neededFQVariables[FQ->VORTX + v] = 1;
816 }
817 }
818 // if no vorticity output is activated but averaged vorticity is on then output
819 // is deactivated for solution output
820 if(!m_vorticityOutput) {
821 for(MInt v = 0; v < nDim; v++) {
822 FQ->outputFQVariables[FQ->VORTX + v] = false;
823 }
824 }
825
826
830 mAlloc(m_variableNames, m_maxNoVariables, "m_variableNames", AT_);
831 switch(nDim) {
832 case 1: {
833 m_variableNames[CV->RHO_U] = "rhoU";
834 m_variableNames[CV->RHO_E] = "rhoE";
835 m_variableNames[CV->RHO] = "rho";
836 break;
837 }
838 case 2: {
839 m_variableNames[CV->RHO_U] = "rhoU";
840 m_variableNames[CV->RHO_V] = "rhoV";
841 m_variableNames[CV->RHO_E] = "rhoE";
842 m_variableNames[CV->RHO] = "rho";
843 break;
844 }
845 case 3: {
846 m_variableNames[CV->RHO_U] = "rhoU";
847 m_variableNames[CV->RHO_V] = "rhoV";
848 m_variableNames[CV->RHO_W] = "rhoW";
849 m_variableNames[CV->RHO_E] = "rhoE";
850 m_variableNames[CV->RHO] = "rho";
851 break;
852 }
853 default: {
854 mTerm(1, AT_, "spatial dimension not implemented for m_variableNames");
855 break;
856 }
857 }
858
859 // fill up the rest of the variales for the species
860 if(nDim + 2 < CV->noVariables) {
861 m_variableNames[nDim + 2] = "rhoZ";
862 for(MInt i = nDim + 2; i < CV->noVariables; ++i) {
863 stringstream number;
864 number << i - (nDim + 2);
865 MString varName = "rho" + number.str();
866 m_variableNames[i] = varName;
867 }
868 }
869
870 mAlloc(m_pvariableNames, m_maxNoVariables, "m_pvariableNames", AT_);
871 switch(nDim) {
872 case 1: {
873 m_pvariableNames[PV->U] = "u";
874 m_pvariableNames[PV->P] = "p";
875 m_pvariableNames[PV->RHO] = "rho";
876 break;
877 }
878 case 2: {
879 m_pvariableNames[PV->U] = "u";
880 m_pvariableNames[PV->V] = "v";
881 m_pvariableNames[PV->P] = "p";
882 m_pvariableNames[PV->RHO] = "rho";
883 break;
884 }
885 case 3: {
886 m_pvariableNames[PV->U] = "u";
887 m_pvariableNames[PV->V] = "v";
888 m_pvariableNames[PV->W] = "w";
889 m_pvariableNames[PV->P] = "p";
890 m_pvariableNames[PV->RHO] = "rho";
891 break;
893 default: {
894 mTerm(1, AT_, "spatial dimension not implemented for m_variableNames");
895 break;
896 }
897 }
898
899 // fill up the rest of the variales for the species
900 if(nDim + 2 < m_maxNoVariables) {
901 for(MInt i = nDim + 2; i < m_maxNoVariables; ++i) {
902 stringstream number;
903 number << i - (nDim + 2);
904 MString varName = "rans" + number.str();
905 m_pvariableNames[i] = varName;
906 }
921 m_residualOutputInterval = 1;
922 m_residualOutputInterval =
923 Context::getSolverProperty<MInt>("residualOutputInterval", m_solverId, AT_, &m_residualOutputInterval);
924
925 m_residualFileExist = false;
926
930
931 m_intpPointsStart = nullptr;
932 m_intpPointsDelta = nullptr;
933 m_intpPointsDelta2D = nullptr;
934 m_intpPointsNoPoints = nullptr;
935 m_intpPointsNoPoints2D = nullptr;
936 m_intpPointsCoordinates = nullptr;
937 m_intpPointsHasPartnerGlobal = nullptr;
938 m_intpPointsHasPartnerLocal = nullptr;
939 m_intpPointsVarsGlobal = nullptr;
940 m_intpPointsVarsLocal = nullptr;
941 m_intpPointsNoPointsTotal = 0;
942 m_intpPointsNoLines = 0;
943 m_intpPointsNoLines2D = 0;
944
957 m_intpPointsOutputInterval = 0;
958 m_intpPointsOutputInterval =
959 Context::getSolverProperty<MInt>("intpPointsOutputInterval", m_solverId, AT_, &m_intpPointsOutputInterval);
960
961 if(m_intpPointsOutputInterval > 0) {
974 m_intpPointsOutputDir = m_solutionOutput;
975 if(Context::propertyExists("intpPointsOutputDir", m_solverId)) {
976 m_intpPointsOutputDir = Context::getSolverProperty<MString>("intpPointsOutputDir", m_solverId, AT_);
977
978 MString comparator = "/";
979 if(strcmp((m_intpPointsOutputDir.substr(m_intpPointsOutputDir.length() - 1, 1)).c_str(), comparator.c_str())
980 != 0) {
981 m_intpPointsOutputDir = m_intpPointsOutputDir + "/";
982 }
983 }
984
997 MInt noLineStartX = Context::propertyLength("intpPointsStartX", m_solverId);
998
1011 MInt noLineStartY = Context::propertyLength("intpPointsStartY", m_solverId);
1012
1025 MInt noLineStartZ = Context::propertyLength("intpPointsStartZ", m_solverId);
1026
1039 MInt noLineDeltaX = Context::propertyLength("intpPointsDeltaX", m_solverId);
1040
1053 MInt noLineDeltaY = Context::propertyLength("intpPointsDeltaY", m_solverId);
1054
1067 MInt noLineDeltaZ = Context::propertyLength("intpPointsDeltaZ", m_solverId);
1068
1081 MInt noLineNoPoints = Context::propertyLength("intpPointsNoPoints", m_solverId);
1082
1083 m_intpPointsNoLines = noLineStartX;
1084
1085 if(m_intpPointsNoLines != noLineStartX || m_intpPointsNoLines != noLineStartY || m_intpPointsNoLines != noLineStartZ
1086 || m_intpPointsNoLines != noLineDeltaX || m_intpPointsNoLines != noLineDeltaY
1087 || m_intpPointsNoLines != noLineDeltaZ || m_intpPointsNoLines != noLineNoPoints) {
1088 mTerm(1, AT_,
1089 "The number of Entries for 'intpPointsStartX', 'intpPointsStartY',"
1090 "'intpPointsStartZ', 'intpPointsDeltaX', 'intpPointsDeltaY' and "
1091 "'intpPointsDeltaZ' do not coincide!! Please check");
1092 }
1093
1094 // set number of intpPointss in second direction
1095 if(Context::propertyExists("intpPointsDeltaX2D", m_solverId)
1096 && Context::propertyExists("intpPointsDeltaY2D", m_solverId)
1097 && Context::propertyExists("intpPointsDeltaZ2D", m_solverId)
1098 && Context::propertyExists("intpPointsNoPoints2D", m_solverId)) {
1112 MInt noLineDeltaX2d = Context::propertyLength("intpPointsDeltaX2D", m_solverId);
1113
1127 MInt noLineDeltaY2d = Context::propertyLength("intpPointsDeltaY2D", m_solverId);
1128
1142 MInt noLineDeltaZ2d = Context::propertyLength("intpPointsDeltaZ2D", m_solverId);
1143
1157 MInt noLineNoPoints2D = Context::propertyLength("intpPointsNoPoints2D", m_solverId);
1158
1159 m_intpPointsNoLines2D = noLineNoPoints2D;
1160
1161 if(m_intpPointsNoLines2D != noLineDeltaX2d || m_intpPointsNoLines2D != noLineDeltaY2d
1162 || m_intpPointsNoLines2D != noLineDeltaZ2d || m_intpPointsNoLines2D != noLineNoPoints2D) {
1163 cout << "no2dLines: " << m_intpPointsNoLines2D << " lineDeltaY2D: " << noLineDeltaY2d
1164 << " lineDeltaX2D: " << noLineDeltaX2d << " lineDeltaZ2D: " << noLineDeltaZ2d << endl;
1165 mTerm(1, AT_,
1166 "The number of Entries for 'lineDeltaX2D', 'lineDeltaY2D' and 'lineDeltaZ2D' do not coincide!! "
1167 "Please check");
1168 }
1169
1170 } else {
1171 m_intpPointsNoLines2D = m_intpPointsNoLines; // just to solve allocating problems
1172 }
1173
1174 mAlloc(m_intpPointsStart, nDim, m_intpPointsNoLines, "m_intpPointsStart", F0, AT_);
1175 mAlloc(m_intpPointsDelta, nDim, m_intpPointsNoLines, "m_intpPointsDelta", F0, AT_);
1176 mAlloc(m_intpPointsNoPoints, m_intpPointsNoLines, "m_intpPointsNoPoints", 0, AT_);
1177 mAlloc(m_intpPointsNoPoints2D, m_intpPointsNoLines2D, "m_intpPointsNoPoints2D", 0, AT_);
1178 mAlloc(m_intpPointsDelta2D, nDim, m_intpPointsNoLines2D, "m_intpPointsDelta2D", F0, AT_);
1179 mAlloc(m_intpPointsOffsets, m_intpPointsNoLines, "m_intpPointsOffsets", 0, AT_);
1180
1181 // for every "first direction" line there is only one field although there are more possibilities to combine the
1182 // "first and second direction" lines therefore the fieldOffset is equally sized to the number of "first direction"
1183 // lines (m_intpPointsNoLines)
1184
1185 // read in the values for the startpoints and directionVectors
1186
1187 // first direction
1188 for(MInt i = 0; i < m_intpPointsNoLines; ++i) {
1189 // initialize with unrealistic values
1190 for(MInt dim = 0; dim < nDim; dim++) {
1191 m_intpPointsStart[dim][i] = -99999.9;
1192 m_intpPointsDelta[dim][i] = -99999.9;
1193 }
1194 m_intpPointsNoPoints[i] = -1;
1195
1196 m_intpPointsStart[0][i] =
1197 Context::getSolverProperty<MFloat>("intpPointsStartX", m_solverId, AT_, &m_intpPointsStart[0][i], i);
1198 m_intpPointsStart[1][i] =
1199 Context::getSolverProperty<MFloat>("intpPointsStartY", m_solverId, AT_, &m_intpPointsStart[1][i], i);
1200 m_intpPointsStart[2][i] =
1201 Context::getSolverProperty<MFloat>("intpPointsStartZ", m_solverId, AT_, &m_intpPointsStart[2][i], i);
1202 m_intpPointsDelta[0][i] =
1203 Context::getSolverProperty<MFloat>("intpPointsDeltaX", m_solverId, AT_, &m_intpPointsDelta[0][i], i);
1204 m_intpPointsDelta[1][i] =
1205 Context::getSolverProperty<MFloat>("intpPointsDeltaY", m_solverId, AT_, &m_intpPointsDelta[1][i], i);
1206 m_intpPointsDelta[2][i] =
1207 Context::getSolverProperty<MFloat>("intpPointsDeltaZ", m_solverId, AT_, &m_intpPointsDelta[2][i], i);
1208 m_intpPointsNoPoints[i] =
1209 Context::getSolverProperty<MInt>("intpPointsNoPoints", m_solverId, AT_, &m_intpPointsNoPoints[i], i);
1210 }
1211
1212 m_intpPoints = false;
1213 // second direction
1214 if(Context::propertyExists("intpPointsDeltaX2D", m_solverId)
1215 && Context::propertyExists("intpPointsDeltaY2D", m_solverId)
1216 && Context::propertyExists("intpPointsDeltaZ2D", m_solverId)
1217 && Context::propertyExists("intpPointsNoPoints2D", m_solverId)) {
1218 m_intpPoints = true;
1219
1220 for(MInt i = 0; i < m_intpPointsNoLines2D; ++i) {
1221 // initialize with unrealistic values
1222 for(MInt dim = 0; dim < nDim; dim++) {
1223 m_intpPointsDelta2D[dim][i] = -99999.9;
1224 }
1225 m_intpPointsNoPoints2D[i] = -1;
1226
1227 m_intpPointsDelta2D[0][i] =
1228 Context::getSolverProperty<MFloat>("intpPointsDeltaX2D", m_solverId, AT_, &m_intpPointsDelta2D[0][i], i);
1229 m_intpPointsDelta2D[1][i] =
1230 Context::getSolverProperty<MFloat>("intpPointsDeltaY2D", m_solverId, AT_, &m_intpPointsDelta2D[1][i], i);
1231 m_intpPointsDelta2D[2][i] =
1232 Context::getSolverProperty<MFloat>("intpPointsDeltaZ2D", m_solverId, AT_, &m_intpPointsDelta2D[2][i], i);
1233 m_intpPointsNoPoints2D[i] =
1234 Context::getSolverProperty<MInt>("intpPointsNoPoints2D", m_solverId, AT_, &m_intpPointsNoPoints2D[i], i);
1235 }
1236
1237 } else {
1238 for(MInt i = 0; i < m_intpPointsNoLines2D; i++) {
1239 m_intpPointsNoPoints2D[i] = 1;
1240 }
1241 for(MInt fieldId = 0; fieldId < m_intpPointsNoLines; fieldId++) {
1242 for(MInt dim = 0; dim < nDim; dim++) {
1243 m_intpPointsDelta2D[dim][fieldId] = 0;
1244 }
1245 }
1246 }
1247
1248 for(MInt i = 0; i < m_intpPointsNoLines; i++) {
1249 m_intpPointsNoPointsTotal += m_intpPointsNoPoints[i] * m_intpPointsNoPoints2D[i];
1250 }
1251
1252 mAlloc(m_intpPointsCoordinates, nDim, m_intpPointsNoPointsTotal, "m_intpPointsCoordinates", F0, AT_);
1253 mAlloc(m_intpPointsHasPartnerGlobal, m_intpPointsNoPointsTotal, "m_intpPointsHasPartnerGlobal", 0, AT_);
1254 mAlloc(m_intpPointsHasPartnerLocal, m_intpPointsNoPointsTotal, "m_intpPointsHasPartnerLocal", 0, AT_);
1255 mAlloc(m_intpPointsVarsLocal, CV->noVariables, m_intpPointsNoPointsTotal, "m_intpPointsVarsLocal", F0, AT_);
1256 mAlloc(m_intpPointsVarsGlobal, CV->noVariables, m_intpPointsNoPointsTotal, "m_intpPointsVarsGlobal", F0, AT_);
1257
1258 // all fields are in ONE array (m_intpPointsCoordinates)
1259 MInt offset = 0;
1260
1261 // putting startpoints at the right place and generating the field
1262 for(MInt fieldId = 0; fieldId < m_intpPointsNoLines; fieldId++) {
1263 m_intpPointsOffsets[fieldId] = offset;
1264
1265 for(MInt pointId2d = 0; pointId2d < m_intpPointsNoPoints2D[fieldId]; pointId2d++) {
1266 for(MInt pointId = 0; pointId < m_intpPointsNoPoints[fieldId]; pointId++) {
1267 for(MInt dim = 0; dim < nDim; dim++) {
1268 m_intpPointsCoordinates[dim][offset] = m_intpPointsStart[dim][fieldId]
1269 + pointId * m_intpPointsDelta[dim][fieldId]
1270 + pointId2d * m_intpPointsDelta2D[dim][fieldId];
1271 }
1272 offset++;
1273 }
1274 }
1275 }
1276
1277 // Finished reading in the line output properties and generating the lines
1278 }
1279
1280
1284
1285 // this method writes out a defined sub-volume of the
1286 // computational domain. The subvolume is defined by
1287 // an starting point/offset coordinate (i,j,k) and
1288 // a size (also in computational coordinates)
1289 // The cell-center coordinates can also be written out
1290 // which is useful for visualization, especially for
1291 // moving grids
1292
1305 m_boxOutputInterval = 0;
1306 m_boxOutputInterval = Context::getSolverProperty<MInt>("boxOutputInterval", m_solverId, AT_, &m_boxOutputInterval);
1307
1308 if(m_boxOutputInterval > 0) {
1321 m_boxNoBoxes = Context::propertyLength("boxBlock", m_solverId); // number of Boxes to be written out
1322
1335 m_boxWriteCoordinates = false;
1336 m_boxWriteCoordinates =
1337 Context::getSolverProperty<MBool>("boxWriteCoordinates", m_solverId, AT_, &m_boxWriteCoordinates);
1338
1351 m_boxOutputDir = m_solutionOutput;
1352 if(Context::propertyExists("boxOutputDir", m_solverId)) {
1353 m_boxOutputDir = Context::getSolverProperty<MString>("boxOutputDir", m_solverId, AT_);
1354
1355 MString comparator = "/";
1356 if(strcmp((m_boxOutputDir.substr(m_boxOutputDir.length() - 1, 1)).c_str(), comparator.c_str()) != 0) {
1357 m_boxOutputDir = m_boxOutputDir + "/";
1358 }
1359 }
1360
1361 mAlloc(m_boxBlock, m_boxNoBoxes, "m_boxBlock", 0, AT_);
1362 mAlloc(m_boxOffset, m_boxNoBoxes, nDim, "m_boxOffset", 0, AT_);
1363 mAlloc(m_boxSize, m_boxNoBoxes, nDim, "m_boxSize", 0, AT_);
1364
1365 for(MInt i = 0; i < m_boxNoBoxes; ++i) {
1366 m_boxBlock[i] = -1;
1367
1368 for(MInt dim = 0; dim < nDim; dim++) {
1369 m_boxOffset[i][dim] = -1;
1370 m_boxSize[i][dim] = -1;
1371 }
1372
1373 m_boxBlock[i] = Context::getSolverProperty<MInt>("boxBlock", m_solverId, AT_, &m_boxBlock[i], i);
1374
1387 IF_CONSTEXPR(nDim == 3) {
1388 m_boxOffset[i][0] = Context::getSolverProperty<MInt>("boxOffsetK", m_solverId, AT_, &m_boxOffset[i][0], i);
1389 }
1390
1404 m_boxOffset[i][nDim - 2] = Context::getSolverProperty<MInt>("boxOffsetJ", m_solverId, AT_, &m_boxOffset[i][1], i);
1405
1418 m_boxOffset[i][nDim - 1] = Context::getSolverProperty<MInt>("boxOffsetI", m_solverId, AT_, &m_boxOffset[i][2], i);
1419
1432 IF_CONSTEXPR(nDim == 3) {
1433 m_boxSize[i][0] = Context::getSolverProperty<MInt>("boxSizeK", m_solverId, AT_, &m_boxSize[i][0], i);
1434 }
1435
1448 m_boxSize[i][nDim - 2] = Context::getSolverProperty<MInt>("boxSizeJ", m_solverId, AT_, &m_boxSize[i][1], i);
1449
1462 m_boxSize[i][nDim - 1] = Context::getSolverProperty<MInt>("boxSizeI", m_solverId, AT_, &m_boxSize[i][2], i);
1463 }
1464 }
1465
1466
1470
1471
1472 // this method is similar to the standard box output
1473 // such that you choose a subvolume of your domain to
1474 // write out at a given sampling rate. Here, the variables
1475 // are interpolated to the grid-nodes which are then written out
1476 // instead of the cell-center values (as in the standard box method)
1477
1490 m_nodalBoxOutputInterval = 0;
1491 m_nodalBoxOutputInterval =
1492 Context::getSolverProperty<MInt>("nodalBoxOutputInterval", m_solverId, AT_, &m_nodalBoxOutputInterval);
1493
1494 if(m_nodalBoxOutputInterval > 0) {
1495 m_nodalBoxInitialized = false;
1496 m_nodalBoxTotalLocalSize = -1;
1497
1510 m_nodalBoxNoBoxes = Context::propertyLength("nodalBoxBlock", m_solverId); // number of NodalBoxes to be written out
1511
1524 m_nodalBoxWriteCoordinates = false;
1525 m_nodalBoxWriteCoordinates =
1526 Context::getSolverProperty<MBool>("nodalBoxWriteCoordinates", m_solverId, AT_, &m_nodalBoxWriteCoordinates);
1527
1540 m_nodalBoxOutputDir = m_solutionOutput;
1541 if(Context::propertyExists("nodalBoxOutputDir", m_solverId)) {
1542 m_nodalBoxOutputDir = Context::getSolverProperty<MString>("nodalBoxOutputDir", m_solverId, AT_);
1543
1544 MString comparator = "/";
1545 if(strcmp((m_nodalBoxOutputDir.substr(m_nodalBoxOutputDir.length() - 1, 1)).c_str(), comparator.c_str()) != 0) {
1546 m_nodalBoxOutputDir = m_nodalBoxOutputDir + "/";
1547 }
1548 }
1549
1550 mAlloc(m_nodalBoxBlock, m_nodalBoxNoBoxes, "m_nodalBoxBlock", 0, AT_);
1551 mAlloc(m_nodalBoxOffset, m_nodalBoxNoBoxes, nDim, "m_nodalBoxOffset", 0, AT_);
1552 mAlloc(m_nodalBoxPoints, m_nodalBoxNoBoxes, nDim, "m_nodalBoxPoints", 0, AT_);
1553
1554 for(MInt i = 0; i < m_nodalBoxNoBoxes; ++i) {
1555 m_nodalBoxBlock[i] = -1;
1556
1557 for(MInt dim = 0; dim < nDim; dim++) {
1558 m_nodalBoxOffset[i][dim] = -1;
1559 m_nodalBoxPoints[i][dim] = -1;
1560 }
1561
1562 m_nodalBoxBlock[i] = Context::getSolverProperty<MInt>("nodalBoxBlock", m_solverId, AT_, &m_nodalBoxBlock[i], i);
1563
1576 m_nodalBoxOffset[i][0] =
1577 Context::getSolverProperty<MInt>("nodalBoxOffsetK", m_solverId, AT_, &m_nodalBoxOffset[i][0], i);
1578
1591 m_nodalBoxOffset[i][1] =
1592 Context::getSolverProperty<MInt>("nodalBoxOffsetJ", m_solverId, AT_, &m_nodalBoxOffset[i][1], i);
1593
1606 m_nodalBoxOffset[i][2] =
1607 Context::getSolverProperty<MInt>("nodalBoxOffsetI", m_solverId, AT_, &m_nodalBoxOffset[i][2], i);
1608
1621 m_nodalBoxPoints[i][0] =
1622 Context::getSolverProperty<MInt>("nodalBoxPointsK", m_solverId, AT_, &m_nodalBoxPoints[i][0], i);
1623
1636 m_nodalBoxPoints[i][1] =
1637 Context::getSolverProperty<MInt>("nodalBoxPointsJ", m_solverId, AT_, &m_nodalBoxPoints[i][1], i);
1638
1651 m_nodalBoxPoints[i][2] =
1652 Context::getSolverProperty<MInt>("nodalBoxPointsI", m_solverId, AT_, &m_nodalBoxPoints[i][2], i);
1653 }
1654 }
1655
1656
1660
1661
1662 // this method is useful for high-frequency writing values of
1663 // given points to an ASCII file. The points can be given by
1664 // physical coordinates onto which one of the chosen variables
1665 // is then interpolated to
1666
1680 m_pointsToAsciiOutputInterval = 0;
1681 m_pointsToAsciiOutputInterval =
1682 Context::getSolverProperty<MInt>("pointsToAsciiOutputInterval", m_solverId, AT_, &m_pointsToAsciiOutputInterval);
1683
1684
1698 m_pointsToAsciiComputeInterval = 0;
1699 m_pointsToAsciiComputeInterval = Context::getSolverProperty<MInt>("pointsToAsciiComputeInterval", m_solverId, AT_,
1700 &m_pointsToAsciiComputeInterval);
1701
1702 if(m_pointsToAsciiComputeInterval > m_pointsToAsciiOutputInterval) {
1703 m_pointsToAsciiComputeInterval = m_pointsToAsciiOutputInterval;
1704 }
1705
1706 if(m_pointsToAsciiOutputInterval > 0 && m_pointsToAsciiComputeInterval == 0) {
1707 m_pointsToAsciiComputeInterval = 1;
1708 }
1709
1710 if(m_pointsToAsciiOutputInterval > 0) {
1711 m_pointsToAsciiVarId = 0;
1712 m_pointsToAsciiVarId =
1713 Context::getSolverProperty<MInt>("pointsToAsciiVarId", m_solverId, AT_, &m_pointsToAsciiVarId);
1714
1715 m_pointsToAsciiLastOutputStep = 0;
1716 m_pointsToAsciiLastComputationStep = 0;
1717
1718 m_pointsToAsciiNoPoints = Context::propertyLength("pointsToAsciiX", m_solverId);
1719
1720 mAlloc(m_pointsToAsciiCoordinates, nDim, m_pointsToAsciiNoPoints, "m_pointsToAsciiCoordinates", 0.0, AT_);
1721 mAlloc(m_pointsToAsciiHasPartnerLocal, m_pointsToAsciiNoPoints, "m_pointsToAsciiHasPartnerLocal", 0, AT_);
1722 mAlloc(m_pointsToAsciiHasPartnerGlobal, m_pointsToAsciiNoPoints, "m_pointsToAsciiHasPartnerGlobal", 0, AT_);
1723 mAlloc(m_pointsToAsciiVars, m_pointsToAsciiOutputInterval, m_pointsToAsciiNoPoints + 3, "m_pointsToAsciiVars", 0.0,
1724 AT_);
1725
1726 if(domainId() == 0) {
1727 cout << "noAsciiCells: " << m_pointsToAsciiNoPoints << endl;
1728 }
1729
1730 for(MInt i = 0; i < m_pointsToAsciiNoPoints; ++i) {
1731 for(MInt dim = 0; dim < nDim; dim++) {
1732 m_pointsToAsciiCoordinates[dim][i] = -1.0;
1733 }
1734
1747 m_pointsToAsciiCoordinates[0][i] =
1748 Context::getSolverProperty<MFloat>("pointsToAsciiX", m_solverId, AT_, &m_pointsToAsciiCoordinates[0][i], i);
1749
1762 m_pointsToAsciiCoordinates[1][i] =
1763 Context::getSolverProperty<MFloat>("pointsToAsciiY", m_solverId, AT_, &m_pointsToAsciiCoordinates[1][i], i);
1764
1777 m_pointsToAsciiCoordinates[2][i] =
1778 Context::getSolverProperty<MFloat>("pointsToAsciiZ", m_solverId, AT_, &m_pointsToAsciiCoordinates[2][i], i);
1779 }
1780 }
1781
1782
1786
1801 m_useConvectiveUnitWrite = false;
1802 m_useConvectiveUnitWrite =
1803 Context::getSolverProperty<MBool>("useConvectiveUnitWrite", m_solverId, AT_, &m_useConvectiveUnitWrite);
1804
1805 if(m_useConvectiveUnitWrite) {
1819 m_convectiveUnitInterval = 1.0;
1820 m_convectiveUnitInterval =
1821 Context::getSolverProperty<MFloat>("convectiveUnitInterval", m_solverId, AT_, &m_convectiveUnitInterval);
1822
1823 m_noConvectiveOutputs = 0;
1824
1839 m_sampleSolutionFiles = false;
1840 m_sampleSolutionFiles =
1841 Context::getSolverProperty<MBool>("sampleSolutionFiles", m_solverId, AT_, &m_sampleSolutionFiles);
1842 }
1843
1847
1861 m_restartInterpolation = false;
1862 m_restartInterpolation =
1863 Context::getSolverProperty<MBool>("restartInterpolation", m_solverId, AT_, &m_restartInterpolation);
1864}
1865
1870template <MInt nDim>
1872 TRACE();
1873
1874 (void)propertiesGroups;
1875
1889 m_noSpecies = 0;
1890 m_noSpecies = Context::getSolverProperty<MInt>("noSpecies", m_solverId, AT_, &m_noSpecies);
1891
1892 FQ = make_unique<StructuredFQVariables>();
1893
1894 // allocate the array for counting the needed fq fields
1895 mAlloc(FQ->neededFQVariables, FQ->maxNoFQVariables, "FQ->neededFQVariables", 0, AT_);
1896 mAlloc(FQ->outputFQVariables, FQ->maxNoFQVariables, "FQ->outputFQVariables", true, AT_);
1897 mAlloc(FQ->boxOutputFQVariables, FQ->maxNoFQVariables, "FQ->boxOutputFQVariables", false, AT_);
1898
1899 m_timeStep = 0;
1900 m_periodicConnection = 0;
1901}
1902
1907template <MInt nDim>
1923 m_referenceLength = F1;
1924 m_referenceLength = Context::getSolverProperty<MFloat>("referenceLength", m_solverId, AT_, &m_referenceLength);
1925
1926 if(fabs(m_referenceLength - F1) > m_eps) {
1927 m_log << "WARNING: referenceLength != 1.0. The correct implementation of this is not checked. Don't use it "
1928 "unless you REALLY know what you are doing."
1929 << endl;
1930 }
1931
1944 m_physicalReferenceLength = F1;
1945 m_physicalReferenceLength =
1946 Context::getSolverProperty<MFloat>("physicalReferenceLength", m_solverId, AT_, &m_physicalReferenceLength);
1947
1966 m_Re = Context::getSolverProperty<MFloat>("Re", m_solverId, AT_) / m_referenceLength;
1967
1981 m_Pr = 0.72;
1982 m_Pr = Context::getSolverProperty<MFloat>("Pr", m_solverId, AT_, &m_Pr);
1983 m_rPr = 1. / m_Pr;
1984
1998 m_ReTau = Context::getSolverProperty<MFloat>("ReTau", m_solverId, AT_) / m_referenceLength;
1999
2012 m_Ma = Context::getSolverProperty<MFloat>("Ma", m_solverId, AT_);
2013
2026 mAlloc(m_angle, nDim, "m_angle", F0, AT_);
2027 if(Context::propertyExists("angle", m_solverId)) {
2028 for(MInt i = 0; i < (nDim - 1); i++) {
2029 m_angle[i] = Context::getSolverProperty<MFloat>("angle", m_solverId, AT_, i);
2030 m_angle[i] *= PI / 180.0;
2031 }
2032 }
2033
2047 mAlloc(m_volumeForce, nDim, "m_volumeAcceleration", F0, AT_);
2048 m_considerVolumeForces = false;
2049 m_considerVolumeForces =
2050 Context::getSolverProperty<MBool>("considerVolumeForces", m_solverId, AT_, &m_considerVolumeForces);
2051
2052 if(m_considerVolumeForces) {
2053 for(MInt i = 0; i < nDim; i++) {
2067 m_volumeForce[i] = Context::getSolverProperty<MFloat>("volumeForce", m_solverId, AT_, i);
2068 }
2069 }
2070
2083 m_gamma = 1.4;
2084 m_gamma = Context::getSolverProperty<MFloat>("gamma", m_solverId, AT_, &m_gamma);
2085
2086 m_gammaMinusOne = m_gamma - F1;
2087 m_fgammaMinusOne = F1 / (m_gammaMinusOne);
2088
2101 m_initialCondition = Context::getSolverProperty<MInt>("initialCondition", m_solverId, AT_);
2102
2103 m_channelFullyPeriodic = false;
2104 m_channelFullyPeriodic =
2105 Context::getSolverProperty<MBool>("channelFullyPeriodic", m_solverId, AT_, &m_channelFullyPeriodic);
2106 if(m_channelFullyPeriodic && (m_initialCondition == 1233 || m_initialCondition == 1234))
2107 mTerm(1, "Fully periodic channel computation works with volume forces and not a pressure gradient!");
2108 m_channelHeight = -F1;
2109 m_channelWidth = -F1;
2110 m_channelLength = -F1;
2111 m_channelInflowPlaneCoordinate = -111111.1111111;
2112 m_channelC1 = 5.0;
2113 m_channelC2 = -3.05;
2114 m_channelC3 = 2.5;
2115 m_channelC4 = 5.5;
2116 if(m_channelFullyPeriodic) {
2117 m_considerVolumeForces = true;
2118 m_volumeForceMethod = Context::getSolverProperty<MInt>("volumeForceMethod", m_solverId, AT_);
2119 m_volumeForceUpdateInterval = Context::getSolverProperty<MInt>("volumeForceUpdateInterval", m_solverId, AT_);
2120 }
2121 switch(m_initialCondition) {
2122 case 1233:
2123 case 1234: { // we are dealing with channel flows
2124
2138 m_channelHeight = Context::getSolverProperty<MFloat>("channelHeight", m_solverId, AT_);
2139
2153 m_channelWidth = Context::getSolverProperty<MFloat>("channelWidth", m_solverId, AT_);
2154
2168 m_channelLength = Context::getSolverProperty<MFloat>("channelLength", m_solverId, AT_);
2169
2182 m_channelInflowPlaneCoordinate = Context::getSolverProperty<MFloat>("channelInflowCoordinate", m_solverId, AT_);
2183
2196 m_channelC1 = Context::getSolverProperty<MFloat>("loglawC1", m_solverId, AT_, &m_channelC1);
2197
2210 m_channelC2 = Context::getSolverProperty<MFloat>("loglawC2", m_solverId, AT_, &m_channelC1);
2211
2224 m_channelC3 = Context::getSolverProperty<MFloat>("loglawC3", m_solverId, AT_, &m_channelC1);
2225
2238 m_channelC4 = Context::getSolverProperty<MFloat>("loglawC4", m_solverId, AT_, &m_channelC1);
2239 m_log << "============= Channel flow activated =============" << endl;
2240 m_log << "-> channelHeight: " << m_channelHeight << endl;
2241 m_log << "-> channelWidth: " << m_channelWidth << endl;
2242 m_log << "-> channelLength: " << m_channelLength << endl;
2243 m_log << "-> channelInflowPlaneCoordinate: " << m_channelInflowPlaneCoordinate << endl;
2244 m_log << "-> Log law properties: " << endl;
2245 m_log << "--> C1: " << m_channelC1 << endl;
2246 m_log << "--> C2: " << m_channelC2 << endl;
2247 m_log << "--> C3: " << m_channelC3 << endl;
2248 m_log << "--> C4: " << m_channelC4 << endl;
2249 m_log << "============= Channel flow summary finished =============" << endl;
2250 break;
2251 }
2252 case 1236: { // we are dealing with pipe flows
2253 // comment:
2254 // since channel and pipe have the same boundary conditions, the variable names are "recycled".
2255 // They stay distinguishable in the input property file
2256
2269 m_channelHeight = Context::getSolverProperty<MFloat>("pipeDiameter", m_solverId, AT_);
2270 m_channelWidth = m_channelHeight;
2271
2284 m_channelLength = Context::getSolverProperty<MFloat>("pipeLength", m_solverId, AT_);
2285
2298 m_channelInflowPlaneCoordinate = Context::getSolverProperty<MFloat>("pipeInflowCoordinate", m_solverId, AT_);
2299 m_channelC1 = Context::getSolverProperty<MFloat>("loglawC1", m_solverId, AT_, &m_channelC1);
2300 m_channelC2 = Context::getSolverProperty<MFloat>("loglawC2", m_solverId, AT_, &m_channelC1);
2301 m_channelC3 = Context::getSolverProperty<MFloat>("loglawC3", m_solverId, AT_, &m_channelC1);
2302 m_channelC4 = Context::getSolverProperty<MFloat>("loglawC4", m_solverId, AT_, &m_channelC1);
2303 m_log << "============= Pipe flow activated =============" << endl;
2304 m_log << "-> pipeRadius: " << m_channelHeight << endl;
2305 m_log << "-> pipeLength: " << m_channelLength << endl;
2306 m_log << "-> pipeInflowPlaneCoordinate: " << m_channelInflowPlaneCoordinate << endl;
2307 m_log << "-> Log law properties: " << endl;
2308 m_log << "--> C1: " << m_channelC1 << endl;
2309 m_log << "--> C2: " << m_channelC2 << endl;
2310 m_log << "--> C3: " << m_channelC3 << endl;
2311 m_log << "--> C4: " << m_channelC4 << endl;
2312 m_log << "============= Pipe flow summary finished =============" << endl;
2313 break;
2314 }
2315 default:
2316 break;
2317 }
2318
2319
2334 m_referenceTemperature = 273.15;
2335 m_referenceTemperature =
2336 Context::getSolverProperty<MFloat>("referenceTemperature", m_solverId, AT_, &m_referenceTemperature);
2337
2350 m_sutherlandConstant = 110.4;
2351 m_sutherlandConstant =
2352 Context::getSolverProperty<MFloat>("sutherlandConstant", m_solverId, AT_, &m_sutherlandConstant);
2353 m_sutherlandConstant /= m_referenceTemperature;
2354 m_sutherlandPlusOne = m_sutherlandConstant + F1;
2355
2368 m_useSandpaperTrip = false;
2369 if(Context::propertyExists("tripSandpaper", m_solverId)) {
2370 m_useSandpaperTrip = Context::getSolverProperty<MBool>("tripSandpaper", m_solverId, AT_, &m_useSandpaperTrip);
2371 }
2372
2373 MString govEqs = "NAVIER_STOKES";
2374 govEqs = Context::getSolverProperty<MString>("govEqs", m_solverId, AT_, &govEqs);
2375
2376 m_euler = false;
2377 if(string2enum(govEqs) == EULER) {
2378 m_euler = true;
2379 }
2380
2381
2394 m_fsc = 0;
2395 m_fsc = Context::getSolverProperty<MInt>("fsc", m_solverId, AT_, &m_fsc);
2396 m_fsc = m_fsc ? 1 : 0;
2397 if(m_fsc) {
2398 if(!approx(m_angle[0], F0, MFloatEps))
2399 mTerm(1, "angle[0] is not zero. Refer to the description of the fsc property");
2400 m_Re /= cos(m_angle[1]);
2401 initFsc();
2402 }
2403
2404 m_useBlasius = false;
2405 m_useBlasius = Context::getSolverProperty<MBool>("useBlasius", m_solverId, AT_, &m_useBlasius);
2406 if(m_useBlasius) {
2407 initBlasius();
2408 }
2409}
2410
2414template <MInt nDim>
2416 TRACE();
2417
2418 m_movingGridTimeOffset = F0;
2419 m_movingGridStepOffset = 0;
2420 m_movingGridInitialStart = true;
2421 m_gridMovingMethod = 0;
2422 m_movingGrid = false;
2423 m_wallVel = F0;
2424
2425 m_travelingWave = false;
2426 m_streamwiseTravelingWave = false;
2427 m_waveTimeStepComputed = false;
2428 m_waveSpeed = 0.0;
2429 m_waveBeginTransition = 0.0;
2430 m_waveEndTransition = 0.0;
2431 m_waveRestartFadeIn = false;
2432 m_waveLength = 0.0;
2433 m_waveAmplitude = 0.0;
2434 m_waveTime = 0.0;
2435 m_waveCellsPerWaveLength = -1;
2436 m_waveNoStepsPerCell = -1;
2437
2438
2452 if(Context::propertyExists("movingGrid", m_solverId)) {
2453 m_movingGrid = Context::getSolverProperty<MBool>("movingGrid", m_solverId, AT_, &m_movingGrid);
2454 }
2455
2456
2457 if(m_movingGrid) {
2458 m_mgExchangeCoordinates = true;
2459 if(Context::propertyExists("mgExchangeCoordinates", m_solverId)) {
2460 m_mgExchangeCoordinates =
2461 Context::getSolverProperty<MBool>("mgExchangeCoordinates", m_solverId, AT_, &m_mgExchangeCoordinates);
2462 }
2463
2477 m_gridMovingMethod = Context::getSolverProperty<MInt>("gridMovingMethod", m_solverId, AT_);
2478
2492 if(Context::propertyExists("wallVel", m_solverId)) {
2493 m_wallVel = Context::getSolverProperty<MFloat>("wallVel", m_solverId, AT_);
2494 }
2495
2509 if(Context::propertyExists("movingGridTimeOffset", m_solverId)) {
2510 m_movingGridTimeOffset =
2511 Context::getSolverProperty<MFloat>("movingGridTimeOffset", m_solverId, AT_, &m_movingGridTimeOffset);
2512 }
2513
2528 m_movingGridSaveGrid = 0;
2529 if(Context::propertyExists("movingGridSaveGrid", m_solverId)) {
2530 m_movingGridSaveGrid =
2531 Context::getSolverProperty<MBool>("movingGridSaveGrid", m_solverId, AT_, &m_movingGridSaveGrid);
2532 }
2533
2534
2549 m_synchronizedMGOutput = false;
2550 m_synchronizedMGOutput =
2551 Context::getSolverProperty<MBool>("synchronizedMGOutput", m_solverId, AT_, &m_synchronizedMGOutput);
2552
2553 m_log << "synchronizedMGOutput is activated? " << m_synchronizedMGOutput << endl;
2554
2555 if(m_gridMovingMethod == 9 || m_gridMovingMethod == 10 || m_gridMovingMethod == 11 || m_gridMovingMethod == 13) {
2556 m_travelingWave = true;
2557 m_constantTimeStep = true;
2558 }
2559
2560 if(m_gridMovingMethod == 12 || m_gridMovingMethod == 15) {
2561 m_streamwiseTravelingWave = true;
2562 m_constantTimeStep = true;
2563 }
2564 }
2565}
2566
2570template <MInt nDim>
2572 TRACE();
2573
2587 m_bodyForce = false;
2588 if(Context::propertyExists("bodyForce", m_solverId)) {
2589 m_bodyForce = Context::getSolverProperty<MBool>("bodyForce", m_solverId, AT_, &m_bodyForce);
2590 }
2591
2592 if(m_bodyForce) {
2593 m_movingGridTimeOffset = F0;
2594 m_movingGridStepOffset = 0;
2595 m_movingGridInitialStart = true;
2596 m_bodyForceMethod = 0;
2597 m_movingGridTimeOffset = F0;
2598
2599 m_travelingWave = false;
2600 m_waveTimeStepComputed = false;
2601 m_waveSpeed = 0.0;
2602 m_waveBeginTransition = 0.0;
2603 m_waveEndTransition = 0.0;
2604 m_waveRestartFadeIn = false;
2605 m_waveLength = 0.0;
2606 m_waveAmplitude = 0.0;
2607 m_waveTime = 0.0;
2608 m_waveCellsPerWaveLength = -1;
2609 m_waveNoStepsPerCell = -1;
2610 m_synchronizedMGOutput = 0;
2611
2612 m_mgExchangeCoordinates = true;
2613 if(Context::propertyExists("mgExchangeCoordinates", m_solverId)) {
2614 m_mgExchangeCoordinates =
2615 Context::getSolverProperty<MBool>("mgExchangeCoordinates", m_solverId, AT_, &m_mgExchangeCoordinates);
2616 }
2617
2631 m_bodyForceMethod = Context::getSolverProperty<MInt>("bodyForceMethod", m_solverId, AT_);
2632
2646 if(Context::propertyExists("wavePenetrationHeight", m_solverId)) {
2647 m_wavePenetrationHeight = Context::getSolverProperty<MFloat>("wavePenetrationHeight", m_solverId, AT_);
2648 }
2649
2663 if(Context::propertyExists("movingGridTimeOffset", m_solverId)) {
2664 m_movingGridTimeOffset =
2665 Context::getSolverProperty<MFloat>("movingGridTimeOffset", m_solverId, AT_, &m_movingGridTimeOffset);
2666 }
2667
2682 m_synchronizedMGOutput = false;
2683 m_synchronizedMGOutput =
2684 Context::getSolverProperty<MBool>("synchronizedMGOutput", m_solverId, AT_, &m_synchronizedMGOutput);
2685
2686 m_log << "synchronizedMGOutput is activated? " << m_synchronizedMGOutput << endl;
2687
2688
2689 if(m_bodyForceMethod == 10 || m_bodyForceMethod == 11) {
2690 m_travelingWave = true;
2691 m_constantTimeStep = true;
2692 }
2693 }
2694}
2695
2699template <MInt nDim>
2701 TRACE();
2702
2703
2718 m_constantTimeStep = true; // default is set to true
2719 m_constantTimeStep = Context::getSolverProperty<MBool>("constantTimeStep", m_solverId, AT_, &m_constantTimeStep);
2720
2734 m_localTimeStep = false;
2735 m_localTimeStep = Context::getSolverProperty<MBool>("localTimeStep", m_solverId, AT_, &m_localTimeStep);
2736
2750 m_timeStepComputationInterval = 1; // time step computation interval
2751 if(!m_constantTimeStep) {
2752 m_timeStepComputationInterval = Context::getSolverProperty<MInt>("timeStepComputationInterval", m_solverId, AT_,
2753 &m_timeStepComputationInterval);
2754 }
2755
2769 m_noGhostLayers = Context::getSolverProperty<MInt>("noGhostLayers", m_solverId, AT_);
2770
2771
2786 m_cfl = Context::getSolverProperty<MFloat>("cfl", m_solverId, AT_);
2787
2800 m_limiter = false;
2801 m_limiter = Context::getSolverProperty<MBool>("limiter", m_solverId, AT_, &m_limiter);
2802
2803 if(m_limiter) {
2816 m_limiterMethod = "ALBADA";
2817 m_limiterMethod = Context::getSolverProperty<MString>("limiterMethod", m_solverId, AT_);
2818 }
2819
2832 // NOTE: with enabled viscous limiter the simulation is no longer conservative
2833 m_limiterVisc = false;
2834 m_limiterVisc = Context::getSolverProperty<MBool>("limiterVisc", m_solverId, AT_, &m_limiterVisc);
2835
2836 if(m_limiterVisc) {
2837 ASSERT(nDim == 2, "Only available in 2D by now!");
2838 m_CFLVISC = Context::getSolverProperty<MFloat>("cfl_visc", m_solverId, AT_); // Maybe it is a stupid name
2839 FQ->neededFQVariables[FQ->LIMITERVISC] = 1;
2840 FQ->outputFQVariables[FQ->LIMITERVISC] = false;
2841 }
2842
2867 m_musclScheme = "Standard";
2868 m_musclScheme = Context::getSolverProperty<MString>("musclScheme", m_solverId, AT_, &m_musclScheme);
2869
2894 m_ausmScheme = "Standard";
2895 m_ausmScheme = Context::getSolverProperty<MString>("ausmScheme", m_solverId, AT_, &m_ausmScheme);
2896
2909 m_convergenceCriterion = 1e-12;
2910 m_convergenceCriterion =
2911 Context::getSolverProperty<MFloat>("convergenceCriterion", m_solverId, AT_, &m_convergenceCriterion);
2912
2925 m_chi = 0.0;
2926 m_chi = Context::getSolverProperty<MFloat>("upwindCoefficient", m_solverId, AT_);
2927
2940 m_viscCompact = false;
2941 m_viscCompact = Context::getSolverProperty<MBool>("viscCompact", m_solverId, AT_, &m_viscCompact);
2942}
2943
2944
2949template <MInt nDim>
2951 TRACE();
2952
2965 m_porous = false;
2966 if(Context::propertyExists("porous", m_solverId)) {
2967 m_porous = Context::getSolverProperty<MBool>("porous", m_solverId, AT_);
2968 }
2969
2970 if(!m_porous) return;
2971
2972 m_blockType = "fluid";
2984 const MInt noPorousSolvers = Context::propertyLength("porousSolvers", m_solverId);
2985 m_porousBlockIds.resize(/*m_noBlocks*/ m_grid->getNoBlocks(), -1);
2986 // m_porousID = -1; //in property file different porous solvers can be assigned different props
2987 const MInt inputBoxID = m_grid->getMyBlockId();
2988 for(MInt i = 0; i < noPorousSolvers; ++i) {
2989 const MInt porousSolver = Context::getSolverProperty<MInt>("porousSolvers", m_solverId, AT_, i);
2990 m_porousBlockIds[porousSolver] = i;
2991 if(inputBoxID == porousSolver) m_blockType = "porous";
2992
2993 // m_porousSolvers[i] = Context::getSolverProperty<MInt>("porousSolvers", m_solverId, AT_,
2994 // &m_porousSolvers[i], i);
2995 // if (inputBoxID == m_porousSolvers[i]) {
2996 // m_blockType = "porous";
2997 // m_porousID = i;
2998 // }
2999 }
3000
3001 // TODO_SS labels:FV later only allocate FQ->POROSITY if m_blockType=="porous"
3002 FQ->neededFQVariables[FQ->POROSITY] = 1;
3003 FQ->outputFQVariables[FQ->POROSITY] = false;
3004
3005 if(m_blockType == "porous") {
3006 m_log << "Domain " << domainId()
3007 << " belongs to a " + m_blockType + " solver. PorousId=" << m_porousBlockIds[inputBoxID]
3008 << endl; // m_porousID << endl;
3009 // FQ->neededFQVariables[FQ->DARCY] = 1;
3010 // FQ->outputFQVariables[FQ->DARCY] = false;
3011 // FQ->neededFQVariables[FQ->FORCH] = 1;
3012 // FQ->outputFQVariables[FQ->FORCH] = false;
3013 }
3014 // Actually the following variables are only required if m_blockType=="porous"
3015 FQ->neededFQVariables[FQ->DARCY] = 1;
3016 FQ->outputFQVariables[FQ->DARCY] = false;
3017 FQ->neededFQVariables[FQ->FORCH] = 1;
3018 FQ->outputFQVariables[FQ->FORCH] = false;
3019 for(MInt d = 0; d < nDim; ++d) {
3020 FQ->neededFQVariables[FQ->NORMAL[d]] = 1;
3021 FQ->outputFQVariables[FQ->NORMAL[d]] = false;
3022 }
3023}
3024
3025
3026template <MInt nDim>
3028 TRACE();
3029
3030 // Assign defaults
3031 m_c_Dp = 0.2;
3032 m_c_Dp_eps = 0.2;
3033 m_c_wd = 5.0;
3034 m_c_t = 0.0;
3035 m_c_eps = 0.0;
3036
3037 // Read in from property file
3038 m_c_Dp = Context::getSolverProperty<MFloat>("c_Dp", m_solverId, AT_, &m_c_Dp);
3039 m_c_Dp_eps = Context::getSolverProperty<MFloat>("c_Dp_eps", m_solverId, AT_, &m_c_Dp_eps);
3040 m_c_wd = Context::getSolverProperty<MFloat>("c_wd", m_solverId, AT_, &m_c_wd);
3041 m_c_t = Context::getSolverProperty<MFloat>("c_t", m_solverId, AT_, &m_c_t);
3042 m_c_eps = Context::getSolverProperty<MFloat>("c_eps", m_solverId, AT_, &m_c_eps);
3043
3044 // Fill porosity, Da, Forch (By now each porous solver is homogeneous)
3045 if(m_blockType == "porous") {
3046 const MInt inputBoxID = m_grid->getMyBlockId();
3047 const MFloat por = Context::getSolverProperty<MFloat>("porosity", m_solverId, AT_,
3048 m_porousBlockIds[inputBoxID]); // m_porousID);
3049 const MFloat Da =
3050 Context::getSolverProperty<MFloat>("Da", m_solverId, AT_, m_porousBlockIds[inputBoxID]); // m_porousID);
3051 const MFloat cf =
3052 Context::getSolverProperty<MFloat>("cf", m_solverId, AT_, m_porousBlockIds[inputBoxID]); // m_porousID);
3053 for(MInt cellId = 0; cellId < m_noCells; ++cellId) {
3054 m_cells->fq[FQ->POROSITY][cellId] = por;
3055 m_cells->fq[FQ->DARCY][cellId] = Da;
3056 m_cells->fq[FQ->FORCH][cellId] = cf;
3057 }
3058 } else {
3059 // Fluid solver has only porosity
3060 for(MInt cellId = 0; cellId < m_noCells; ++cellId) {
3061 m_cells->fq[FQ->POROSITY][cellId] = 1.0;
3062 m_cells->fq[FQ->DARCY][cellId] = std::numeric_limits<MFloat>::max();
3063 }
3064 }
3065
3066 // TODO_SS labels:FV,toenhance Move stuff from initBc6002 into here
3067}
3068
3069
3070template <MInt nDim>
3072 TRACE();
3073
3074 // Abort if timers not initialized
3075 if(!m_isInitTimers) {
3076 TERMM(1, "Timers were not initialized.");
3077 }
3078
3079 return m_timers[timerId];
3080}
3081
3082template <MInt nDim>
3084 TRACE();
3085 m_timers.fill(-1);
3086
3087 NEW_TIMER_GROUP_NOCREATE(m_timerGroup, "Structured Solver");
3088 NEW_TIMER_NOCREATE(m_timers[Timers::Structured], "total object lifetime", m_timerGroup);
3089 RECORD_TIMER_START(m_timers[Timers::Structured]);
3090
3091 // Create & start constructor timer
3092 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Constructor], "Constructor", m_timers[Timers::Structured]);
3093 RECORD_TIMER_START(m_timers[Timers::Constructor]);
3094
3095 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::GridDecomposition], "Grid Decomposition", m_timers[Timers::Constructor]);
3096 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::GridReading], "Grid reading", m_timers[Timers::Constructor]);
3097 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::BuildUpSponge], "Build up sponge", m_timers[Timers::Constructor]);
3098 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ComputeMetrics], "Compute Metrics", m_timers[Timers::Constructor]);
3099 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ComputeJacobian], "Compute Jacobian", m_timers[Timers::Constructor]);
3100
3101 // Create regular solver-wide timers
3102 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::RunInit], "Init", m_timers[Timers::Structured]);
3103 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LoadRestart], "Load restart", m_timers[Timers::RunInit]);
3104 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LoadVariables], "load restart variables", m_timers[Timers::LoadRestart]);
3105 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LoadSponge], "load sponge", m_timers[Timers::LoadRestart]);
3106 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LoadSTG], "load STG", m_timers[Timers::LoadRestart]);
3107
3108
3109 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Run], "Run function", m_timers[Timers::Structured]);
3110 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MainLoop], "Main loop", m_timers[Timers::Run]);
3111 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ConvectiveFlux], "Convective Flux", m_timers[Timers::MainLoop]);
3112 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ViscousFlux], "Viscous Flux", m_timers[Timers::MainLoop]);
3113 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGVolumeFlux], "Volume Flux", m_timers[Timers::MainLoop]);
3114 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SandpaperTrip], "Sandpaper tripping", m_timers[Timers::MainLoop]);
3115
3116 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MovingGrid], "Moving Grid", m_timers[Timers::MainLoop]);
3117 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGVolumeFlux], "MG Volume Flux", m_timers[Timers::MovingGrid]);
3118 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGMoveGrid], "MG Move Grid", m_timers[Timers::MovingGrid]);
3119 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGExchange], "MG Exchange", m_timers[Timers::MGMoveGrid]);
3120 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGCellCenterCoordinates], "MG Cell Center Coordinates",
3121 m_timers[Timers::MGMoveGrid]);
3122 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGMetrics], "MG Metrics", m_timers[Timers::MGMoveGrid]);
3123 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGSurfaceMetrics], "MG Surface Metrics", m_timers[Timers::MGMetrics]);
3124 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGCellMetrics], "MG Cell Metrics", m_timers[Timers::MGMetrics]);
3125 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGCornerMetrics], "MG Corner Metrics", m_timers[Timers::MGMetrics]);
3126 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGJacobian], "MG Jacobian", m_timers[Timers::MGMoveGrid]);
3127
3128 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::MGSaveGrid], "MG Save Grid", m_timers[Timers::MovingGrid]);
3129
3130 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Exchange], "Exchange", m_timers[Timers::MainLoop]);
3131 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Gather], "Gather", m_timers[Timers::Exchange]);
3132 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Send], "Send", m_timers[Timers::Exchange]);
3133 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SendWait], "SendWait", m_timers[Timers::Exchange]);
3134 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Receive], "Receive", m_timers[Timers::Exchange]);
3135 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ReceiveWait], "ReceiveWait", m_timers[Timers::Exchange]);
3136 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Scatter], "Scatter", m_timers[Timers::Exchange]);
3137 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Receive], "Receive", m_timers[Timers::Exchange]);
3138
3139 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::BoundaryCondition], "Boundary Conditions", m_timers[Timers::MainLoop]);
3140
3141 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::RungeKutta], "RungeKutta", m_timers[Timers::MainLoop]);
3142
3143 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveOutput], "Save output", m_timers[Timers::Run]);
3144 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveSolution], "Save solution", m_timers[Timers::SaveOutput]);
3145 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveForces], "Save forces", m_timers[Timers::SaveOutput]);
3146 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveAuxdata], "Save auxdata", m_timers[Timers::SaveOutput]);
3147 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveBoxes], "Save boxes", m_timers[Timers::SaveOutput]);
3148 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SaveIntpPoints], "Save lines", m_timers[Timers::SaveOutput]);
3149
3150
3151 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::SetTimeStep], "Set Time Step", m_timers[Timers::MainLoop]);
3152 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::UpdateSponge], "Update sponge", m_timers[Timers::MainLoop]);
3153
3154 // Set status to initialized
3155 m_isInitTimers = true;
3156}
3157
3158template <MInt nDim>
3160 // Channel Communication
3161 mAlloc(m_channelRoots, 4, "m_channelRoots", -1, AT_);
3162
3163 // Periodic rotation boundary condtions communicators
3164 mAlloc(m_commPerRotRoots, 4, "m_commPerRotRoots", -1, AT_);
3165
3169 if(m_zonal) {
3170 mAlloc(m_commZonal, m_noBlocks, "m_commZonal", AT_);
3171 mAlloc(m_commZonalRoot, m_noBlocks, "m_commZonalRoot", -1, AT_);
3172 mAlloc(m_commZonalRootGlobal, m_noBlocks, "m_commZonalRoot", -1, AT_);
3173
3174 m_commZonalMyRank = -1;
3175 m_zonalRootRank = false;
3176
3177
3178 // first collect the ranks of each input solver in one array and count the number
3179 for(MInt i = 0; i < m_noBlocks; i++) {
3180 MPI_Group groupZonal, newGroupZonal;
3181 vector<MInt> tmpPartitions;
3182 MInt blockDomainId = 0;
3183 MInt hasBlockDomain = 0;
3184 MInt hasBlockDomainGlobal = 0;
3185 MIntScratchSpace nblockDomainArray(noDomains(), AT_, "nblockDomainArray");
3186 MIntScratchSpace nblockDomainOffset(noDomains(), AT_, "nblockDomainOffset");
3187 if(m_blockId == i) {
3188 blockDomainId = domainId();
3189 hasBlockDomain = 1;
3190 }
3191 MPI_Allreduce(&hasBlockDomain, &hasBlockDomainGlobal, 1, MPI_INT, MPI_SUM, m_StructuredComm, AT_,
3192 "hasBlockDomain", "hasBlockDomainGlobal");
3193 MPI_Allgather(&hasBlockDomain, 1, MPI_INT, &nblockDomainArray[0], 1, MPI_INT, m_StructuredComm, AT_,
3194 "hasBlockDomain", "nblockDomainArray[0]");
3195 nblockDomainOffset[0] = 0;
3196 for(MInt j = 1; j < noDomains(); j++) {
3197 nblockDomainOffset[j] = nblockDomainOffset[j - 1] + nblockDomainArray[j - 1];
3198 }
3199 MIntScratchSpace zonalRanks(hasBlockDomainGlobal, AT_, "zonalRanks");
3200 MPI_Allgatherv(&blockDomainId, nblockDomainArray[domainId()], MPI_INT, &zonalRanks[0], &nblockDomainArray[0],
3201 &nblockDomainOffset[0], MPI_INT, m_StructuredComm, AT_, "blockDomainId", "zonalRanks[0]");
3202
3203
3204 MInt zonalcommsize = hasBlockDomainGlobal;
3205
3206 MPI_Comm_group(m_StructuredComm, &groupZonal, AT_, "groupZonal");
3207 MPI_Group_incl(groupZonal, zonalcommsize, &zonalRanks[0], &newGroupZonal, AT_);
3208 MPI_Comm_create(m_StructuredComm, newGroupZonal, &m_commZonal[i], AT_, "m_commZonal[i]");
3209
3210 if(domainId() == zonalRanks[0]) {
3211 MPI_Comm_rank(m_commZonal[i], &m_commZonalRoot[i]);
3212 MPI_Comm_rank(m_StructuredComm, &m_commZonalRootGlobal[i]);
3213 m_zonalRootRank = true;
3214 }
3215
3216 MPI_Bcast(&m_commZonalRoot[0], m_noBlocks, MPI_INT, zonalRanks[0], m_StructuredComm, AT_, "m_commZonalRoot[0]");
3217 MPI_Bcast(&m_commZonalRootGlobal[0], m_noBlocks, MPI_INT, zonalRanks[0], m_StructuredComm, AT_,
3218 "m_commZonalRootGlobal[0]");
3219 }
3220 }
3221}
3222
3228template <MInt nDim>
3230 TRACE();
3231
3247 // 0->only solids (default)
3248 // 1->fluid-porous interfaces and solids
3249 // 2->only fluid-porous interfaces
3250 // 3->specific windows only
3251 MInt auxDataType = 0;
3252 auxDataType = Context::getSolverProperty<MInt>("auxDataType", m_solverId, AT_, &auxDataType);
3253
3254 std::vector<MInt> auxDataWindowIds;
3255 if(auxDataType == 3) {
3256 if(!Context::propertyExists("auxDataWindowIds", m_solverId))
3257 mTerm(1, "auxDataType==3 requires the property 'auxDataWindowIds'!");
3258 const MInt noAuxDataWindowIds = Context::propertyLength("auxDataWindowIds", m_solverId);
3259 auxDataWindowIds.resize(noAuxDataWindowIds);
3260 for(MInt i = 0; i < noAuxDataWindowIds; ++i) {
3261 auxDataWindowIds[i] =
3262 Context::getSolverProperty<MInt>("auxDataWindowIds", m_solverId, AT_, &auxDataWindowIds[i], i);
3263 }
3264 }
3265
3266 // If force==true: solids and fluid-porous interfaces will be added to m_physicalAuxDataMap regardless of auxDataType;
3267 // but m_auxDataWindowIds will contain only those as specified by auxDataType; later all kinds of
3268 // outputs of the auxData will only include those maps which are in m_auxDataWindowIds, so those as
3269 // specified by auxDataType
3270 MBool force = false;
3271 if(m_rans && m_ransMethod == RANS_KEPSILON) force = true;
3272
3273 m_windowInfo->createAuxDataMap(auxDataType, m_blockType, m_porousBlockIds, auxDataWindowIds, force);
3274}
3275
3276
3277template <MInt nDim>
3279 TRACE();
3280
3281 // initialize the values for the Sponge!
3282 m_spongeLayerThickness = nullptr;
3283 m_betaSponge = nullptr;
3284 m_sigmaSponge = nullptr;
3285 m_noSpongeDomainInfos = 0; // number of bc/windows for bc
3286 m_spongeLayerType = 1;
3287 m_targetDensityFactor = F0;
3288 m_computeSpongeFactor = true;
3289 MBool readSpongeFromBc = true;
3290
3303 m_useSponge = false;
3304 m_useSponge = Context::getSolverProperty<MBool>("useSponge", m_solverId, AT_, &m_useSponge);
3305
3306 if(m_useSponge) { // yes
3307 FQ->neededFQVariables[FQ->SPONGE_FACTOR] = 1;
3308
3323 readSpongeFromBc = Context::getSolverProperty<MBool>("readSpongeFromBC", m_solverId, AT_, &readSpongeFromBc);
3324
3325 MInt noSpongeIds;
3326 if(readSpongeFromBc) {
3340 noSpongeIds = Context::propertyLength("spongeBndryCndIds", m_solverId);
3341 } else {
3354 noSpongeIds = Context::propertyLength("spongeWindowIds", m_solverId);
3355 }
3356 m_noSpongeDomainInfos = noSpongeIds;
3357
3371 m_spongeLayerType = Context::getSolverProperty<MInt>("spongeLayerType", m_solverId, AT_, &m_spongeLayerType);
3372
3373
3374 MInt noSpongeBeta = Context::propertyLength("betaSponge", m_solverId);
3375 MInt noSpongeSigma = Context::propertyLength("sigmaSponge", m_solverId);
3376
3377 // The programm aborts if number of sponge properties does not fit together
3378 if(m_noSpongeDomainInfos != noSpongeBeta || m_noSpongeDomainInfos != noSpongeSigma) {
3379 mTerm(1, AT_, "The number of sponge properties does not match");
3380 }
3381
3382 // else we can allocate the memory necessary for the sponge etc'
3383 mAlloc(m_spongeLayerThickness, m_noSpongeDomainInfos, "m_spongeLayerThicknesses", F0, AT_);
3384 mAlloc(m_sigmaSponge, m_noSpongeDomainInfos, "m_sigmaSponge", AT_);
3385 mAlloc(m_betaSponge, m_noSpongeDomainInfos, "m_betaSponge", AT_);
3386 mAlloc(m_spongeBcWindowInfo, m_noSpongeDomainInfos, "m_spongeBcWindowInfo", AT_);
3387
3388 // read all the parameters
3389 for(MInt i = 0; i < m_noSpongeDomainInfos; ++i) {
3404 m_spongeLayerThickness[i] = -1.0;
3405 m_spongeLayerThickness[i] =
3406 Context::getSolverProperty<MFloat>("spongeLayerThickness", m_solverId, AT_, &m_spongeLayerThickness[i], i);
3407
3420 m_betaSponge[i] = F0;
3421 m_betaSponge[i] =
3422 Context::getSolverProperty<MFloat>("betaSponge", m_solverId, AT_, &m_spongeLayerThickness[i], i);
3423
3436 m_sigmaSponge[i] = F0;
3437 m_sigmaSponge[i] =
3438 Context::getSolverProperty<MFloat>("sigmaSponge", m_solverId, AT_, &m_spongeLayerThickness[i], i);
3439 }
3440
3441
3442 if(readSpongeFromBc) {
3443 for(MInt i = 0; i < m_noSpongeDomainInfos; ++i) {
3444 m_spongeBcWindowInfo[i] = -1;
3445 m_spongeBcWindowInfo[i] =
3446 Context::getSolverProperty<MInt>("spongeBndryCndIds", m_solverId, AT_, &m_spongeBcWindowInfo[i], i);
3447 }
3448 } else {
3449 for(MInt i = 0; i < m_noSpongeDomainInfos; ++i) {
3450 m_spongeBcWindowInfo[i] = -1;
3451 m_spongeBcWindowInfo[i] =
3452 Context::getSolverProperty<MInt>("spongeWindowIds", m_solverId, AT_, &m_spongeBcWindowInfo[i], i);
3453 }
3454 }
3455
3474 m_targetDensityFactor = F1;
3475 m_targetDensityFactor =
3476 Context::getSolverProperty<MFloat>("targetDensityFactor", m_solverId, AT_, &m_targetDensityFactor);
3477
3478 m_windowInfo->setSpongeInformation(m_noSpongeDomainInfos, m_betaSponge, m_sigmaSponge, m_spongeLayerThickness,
3479 m_spongeBcWindowInfo, readSpongeFromBc);
3480
3495 m_computeSpongeFactor = true;
3496 if(Context::propertyExists("computeSpongeFactor", m_solverId)) {
3497 m_computeSpongeFactor =
3498 Context::getSolverProperty<MBool>("computeSpongeFactor", m_solverId, AT_, &m_computeSpongeFactor);
3499 }
3500
3501 // we now have the spongeProperties save in m_windowInfo->m_spongeInfoMap
3502 // allocating and other stuff can be handled in the boundaryCondition constructor
3503
3504 if(m_spongeLayerType == 2) {
3505 // active the two sponge layer FQ fields for rho and rhoE
3506 FQ->neededFQVariables[FQ->SPONGE_RHO] = 1;
3507 FQ->neededFQVariables[FQ->SPONGE_RHO_E] = 1;
3508 }
3509
3510 if(m_spongeLayerType == 4) {
3511 // active the two sponge layer FQ fields for rho and rhoE
3512 FQ->neededFQVariables[FQ->SPONGE_RHO] = 1;
3513 }
3514 }
3515}
3516
3517
3523template <MInt nDim>
3525 TRACE();
3526
3540 m_noRKSteps = 5;
3541 m_noRKSteps = Context::getSolverProperty<MInt>("noRKSteps", m_solverId, AT_, &m_noRKSteps);
3542
3543 mDeallocate(m_RKalpha);
3544 mAlloc(m_RKalpha, m_noRKSteps, "m_RKalpha", -F1, AT_);
3545
3558 if(m_noRKSteps == 5) { // default only valid m_noRKSteps == 5
3559 MFloat RK5DefaultCoeffs[5] = {0.25, 0.16666666666, 0.375, 0.5, 1.};
3560 for(MInt i = 0; i < m_noRKSteps; i++) {
3561 m_RKalpha[i] =
3562 Context::getSolverProperty<MFloat>("rkalpha-step", m_solverId, AT_, (MFloat*)&RK5DefaultCoeffs[i], i);
3563 }
3564 }
3565
3566 if(m_noRKSteps == 1) m_RKalpha[0] = 1.0;
3567
3568 // in case of zonal computations
3569 // different rk coefficients can be
3570 // set for the RANS zones
3571 if(m_rans) {
3572 if(Context::propertyExists("rkalpha-step-rans", m_solverId)) {
3573 MFloat RK5DefaultCoeffs[5] = {0.059, 0.14, 0.273, 0.5, 1.0};
3574 for(MInt i = 0; i < m_noRKSteps; i++) {
3575 m_RKalpha[i] =
3576 Context::getSolverProperty<MFloat>("rkalpha-step-rans", m_solverId, AT_, &RK5DefaultCoeffs[i], i);
3577 }
3578 }
3579 }
3580
3594 m_rungeKuttaOrder = 2;
3595 m_rungeKuttaOrder = Context::getSolverProperty<MInt>("rungeKuttaOrder", m_solverId, AT_, &m_rungeKuttaOrder);
3596}
3597
3598
3599template <MInt nDim>
3601 TRACE();
3602 setRungeKuttaProperties();
3603
3604 if(!m_restart) {
3605 m_time = F0;
3606 m_physicalTime = F0;
3607 globalTimeStep = 0;
3608 } else {
3609 m_time = -1.0;
3610 m_physicalTime = -1.0;
3611 }
3612
3613 m_RKStep = 0;
3614
3615 // this is used to initialize the counter the very first time this is called
3616 // and to initialize the very first residual
3617 if(approx(m_time, F0, m_eps)) {
3618 m_workload = 0;
3619 m_workloadIncrement = 1;
3620 m_firstMaxResidual = F0;
3621 m_firstAvrgResidual = F0;
3622 }
3623}
3624
3625
3626template <MInt nDim>
3628 TRACE();
3629 m_stgIsActive = false;
3630 m_stgInitialStartup = false;
3631 m_stgFace = 0;
3632
3633 IF_CONSTEXPR(nDim < 3) { return; }
3634
3647 m_stgIsActive = false;
3648 if(Context::propertyExists("useSTG", m_solverId)) {
3649 m_stgIsActive = Context::getSolverProperty<MBool>("useSTG", m_solverId, AT_, &m_stgIsActive);
3650 }
3651
3652 // switch this on for zonal computation
3653 if(m_zonal) {
3654 m_stgIsActive = true;
3655 }
3656
3657 if(m_stgIsActive) {
3658 m_stgLocal = false;
3659 m_stgRootRank = false;
3660
3661 for(MInt i = 0; i < abs((MInt)m_windowInfo->physicalBCMap.size()); ++i) {
3662 if(m_windowInfo->physicalBCMap[i]->BC == 7909) {
3663 m_stgLocal = true;
3664 m_stgFace = m_windowInfo->physicalBCMap[i]->face;
3665 break;
3666 }
3667 }
3668
3669 if(m_stgLocal) {
3670 MPI_Comm_rank(m_commStg, &m_commStgMyRank);
3671 } else {
3672 m_commStgMyRank = -1;
3673 }
3674
3688 m_stgSubSup = false;
3689 if(Context::propertyExists("stgSubSup", m_solverId)) {
3690 m_stgSubSup = Context::getSolverProperty<MBool>("stgSubSup", m_solverId, AT_, &m_stgSubSup);
3691 }
3692
3705 m_stgSupersonic = false;
3706 if(Context::propertyExists("stgSupersonic", m_solverId)) {
3707 m_stgSupersonic = Context::getSolverProperty<MBool>("stgSupersonic", m_solverId, AT_, &m_stgSupersonic);
3708
3709 if(m_stgSupersonic && m_stgSubSup) {
3710 m_stgSubSup = false;
3711 if(domainId() == 0) {
3712 cout << "WARNING: You activated conflicting properties stgSubSup "
3713 << "and stgSupersonic, thus only the pure supersonic formulation will be used. "
3714 << "Switch off stgSupersonic to get the mixed formulation" << endl;
3715 }
3716 }
3717 }
3718
3733 m_stgBLT1 = 1.0;
3734 m_stgBLT1 = Context::getSolverProperty<MFloat>("BLT1", m_solverId, AT_, &m_stgBLT1);
3735
3750 m_stgBLT2 = 1.1;
3751 m_stgBLT2 = Context::getSolverProperty<MFloat>("BLT2", m_solverId, AT_, &m_stgBLT2);
3752
3767 m_stgBLT3 = 1.0;
3768 m_stgBLT3 = Context::getSolverProperty<MFloat>("BLT3", m_solverId, AT_, &m_stgBLT3);
3769
3782 m_stgDelta99Inflow = -1.0;
3783 m_stgDelta99Inflow = Context::getSolverProperty<MFloat>("deltaIn", m_solverId, AT_, &m_stgDelta99Inflow);
3784
3785 m_stgBLT1 = m_stgBLT1 * m_stgDelta99Inflow;
3786 m_stgBLT2 = m_stgBLT2 * m_stgDelta99Inflow;
3787
3788 mAlloc(m_stgLengthFactors, 3, "m_solver->m_stgLengthFactors", F0, AT_);
3789 m_stgLengthFactors[0] = 1.0;
3790 m_stgLengthFactors[1] = 0.6;
3791 m_stgLengthFactors[2] = 1.5;
3792
3808 if(Context::propertyExists("stgLengthFactors", m_solverId)) {
3809 for(MInt i = 0; i < 3; i++) {
3810 m_stgLengthFactors[i] =
3811 Context::getSolverProperty<MFloat>("stgLengthFactors", m_solverId, AT_, &m_stgLengthFactors[i], i);
3812 }
3813 }
3814
3815 mAlloc(m_stgRSTFactors, 3, "m_solver->m_stgRSTFactors", F0, AT_);
3816 m_stgRSTFactors[0] = 0.7;
3817 m_stgRSTFactors[1] = 0.4;
3818 m_stgRSTFactors[2] = 0.5;
3819
3835 if(Context::propertyExists("stgRSTFactors", m_solverId)) {
3836 for(MInt i = 0; i < 3; i++) {
3837 m_stgRSTFactors[i] =
3838 Context::getSolverProperty<MFloat>("stgRSTFactors", m_solverId, AT_, &m_stgRSTFactors[i], i);
3839 }
3840 }
3841
3842
3855 m_stgMaxNoEddies = 200;
3856 m_stgMaxNoEddies = Context::getSolverProperty<MInt>("stgMaxNoEddies", m_solverId, AT_, &m_stgMaxNoEddies);
3857
3870 m_stgExple = 0.5;
3871 m_stgExple = Context::getSolverProperty<MFloat>("stgExple", m_solverId, AT_, &m_stgExple);
3872
3886 m_stgEddieDistribution = 1.0;
3887 if(Context::propertyExists("stgEddieDistribution", m_solverId)) {
3888 m_stgEddieDistribution =
3889 Context::getSolverProperty<MFloat>("stgEddieDistribution", m_solverId, AT_, &m_stgEddieDistribution);
3890 }
3891
3905 m_stgCreateNewEddies = false;
3906 if(Context::propertyExists("stgCreateNewEddies", m_solverId)) {
3907 m_stgCreateNewEddies =
3908 Context::getSolverProperty<MBool>("stgCreateNewEddies", m_solverId, AT_, &m_stgCreateNewEddies);
3909 }
3910
3923 m_stgInitialStartup = false;
3924 m_stgInitialStartup = Context::getSolverProperty<MBool>("stgInitialStartup", m_solverId, AT_, &m_stgInitialStartup);
3925
3938 m_stgEddieLengthScales = false;
3939 if(Context::propertyExists("stgEddieLengthScales", m_solverId)) {
3940 m_stgEddieLengthScales =
3941 Context::getSolverProperty<MBool>("stgEddieLengthScales", m_solverId, AT_, &m_stgEddieLengthScales);
3942 }
3943
3956 m_stgShapeFunction = 4;
3957 if(Context::propertyExists("stgShapeFunction", m_solverId)) {
3958 m_stgShapeFunction = Context::getSolverProperty<MInt>("stgShapeFunction", m_solverId, AT_, &m_stgShapeFunction);
3959 }
3960
3961 if(m_stgInitialStartup) {
3962 // activate the nut FQ field
3963 FQ->neededFQVariables[FQ->NU_T] = 1;
3964 }
3965
3966 m_stgNoEddieProperties = 6;
3967 if(m_stgEddieLengthScales) {
3968 m_stgNoEddieProperties = 9;
3969 }
3970 mAlloc(m_stgEddies, m_stgMaxNoEddies, m_stgNoEddieProperties, "m_solver->m_stgEddies", -F1, AT_);
3971
3972 m_stgNoVariables = 20;
3973 MInt noSTGCells = m_nCells[0] * m_nCells[1] * 3;
3974 mAlloc(m_cells->stg_fq, m_stgNoVariables, noSTGCells, "m_cells->stg_fq", F0, AT_);
3975
3976 m_stgBoxSize[0] = 0;
3977 m_stgBoxSize[1] = 0;
3978 m_stgBoxSize[2] = 0;
3979
3980 m_log << "===========================================================" << endl
3981 << " STG PROPERTIES " << endl
3982 << "===========================================================" << endl
3983 << "Initial Start: " << m_stgInitialStartup << endl
3984 << "SubSup (Mixed subsonic/supersonic bc): " << m_stgSubSup << endl
3985 << "Supersonic BC: " << m_stgSupersonic << endl
3986 << "BLT 1,2,3: " << m_stgBLT1 << ", " << m_stgBLT2 << ", " << m_stgBLT3 << endl
3987 << "Delta0 inflow: " << m_stgDelta99Inflow << endl
3988 << "Length factors: " << m_stgLengthFactors[0] << ", " << m_stgLengthFactors[1] << ", "
3989 << m_stgLengthFactors[2] << endl
3990 << "Number of eddies: " << m_stgMaxNoEddies << endl
3991 << "Length scale exponent: " << m_stgExple << endl
3992 << "Eddie distribution: " << m_stgEddieDistribution << endl
3993 << "Create new eddies: " << m_stgCreateNewEddies << endl
3994 << "Eddie lengthscales: " << m_stgEddieLengthScales << endl
3995 << "Shape function: " << m_stgShapeFunction << endl
3996 << "Number of eddie properties: " << m_stgNoEddieProperties << endl
3997 << "Number of stg variables: " << m_stgNoVariables << endl
3998 << "===========================================================" << endl;
3999
4000 switch(m_stgFace) {
4001 case 0:
4002 case 1:
4003 m_stgBoxSize[0] = m_nCells[0];
4004 m_stgBoxSize[1] = m_nCells[1];
4005 m_stgBoxSize[2] = 3;
4006 break;
4007 default:
4008 mTerm(1, AT_, "STG Method is not prepared for faces different than 0 or 1!");
4009 }
4010 }
4011}
4012
4013template <MInt nDim>
4015 TRACE();
4016
4020
4021 m_bc2600IsActive = false;
4022 m_bc2600 = false;
4023 m_bc2600RootRank = -1;
4024 for(MInt i = 0; i < abs((MInt)m_windowInfo->globalStructuredBndryCndMaps.size()); ++i) {
4025 if(m_windowInfo->globalStructuredBndryCndMaps[i]->BC == 2600) {
4026 m_bc2600IsActive = true;
4027 break;
4028 }
4029 }
4030
4031 if(m_bc2600IsActive) {
4032 // now look if this domain contains parts of this bc
4033 MInt localRank = 9999999;
4034 for(MInt i = 0; i < abs((MInt)m_windowInfo->physicalBCMap.size()); ++i) {
4035 if(m_windowInfo->physicalBCMap[i]->BC == 2600) {
4036 m_bc2600 = true;
4037 m_bc2600Face = m_windowInfo->physicalBCMap[i]->face;
4038 localRank = domainId();
4039 break;
4040 }
4041 }
4042
4043 MPI_Allreduce(&localRank, &m_bc2600RootRank, 1, MPI_INT, MPI_MIN, m_StructuredComm, AT_, "localRank",
4044 "m_bc2600RootRank");
4045
4046 if(m_bc2600) {
4047 MPI_Comm_rank(m_commBC2600, &m_commBC2600MyRank);
4048 } else {
4049 m_commBC2600MyRank = -1;
4050 }
4051
4065 m_bc2600InitialStartup = false;
4066 m_bc2600InitialStartup =
4067 Context::getSolverProperty<MBool>("initialStartup2600", m_solverId, AT_, &m_bc2600InitialStartup);
4068
4069 mAlloc(m_bc2600noCells, nDim, "m_bc2600noCells", 0, AT_);
4070 mAlloc(m_bc2600noActiveCells, nDim, "m_bc2600noCells", 0, AT_);
4071 mAlloc(m_bc2600noOffsetCells, nDim, "m_bc2600noCells", 0, AT_);
4072 if(m_bc2600) {
4073 for(MInt dim = 0; dim < nDim; dim++) {
4074 m_bc2600noOffsetCells[dim] = m_nOffsetCells[dim];
4075 m_bc2600noCells[dim] = m_nCells[dim];
4076 m_bc2600noActiveCells[dim] = m_bc2600noCells[dim] - 2 * m_noGhostLayers;
4077 }
4078 m_bc2600noOffsetCells[nDim - 1] = 0;
4079 m_bc2600noCells[nDim - 1] = m_noGhostLayers;
4080 m_bc2600noActiveCells[nDim - 1] = m_noGhostLayers;
4081 MInt noCellsBC = 1;
4082 for(MInt dim = 0; dim < nDim; dim++) {
4083 noCellsBC *= m_bc2600noCells[dim];
4084 }
4085 mAlloc(m_bc2600Variables, m_maxNoVariables, noCellsBC, "m_bc2600Variables", -123.456, AT_);
4086 }
4087 }
4088
4092 m_bc2601IsActive = false;
4093 m_bc2601 = false;
4094 for(MInt i = 0; i < abs((MInt)m_windowInfo->globalStructuredBndryCndMaps.size()); ++i) {
4095 if(m_windowInfo->globalStructuredBndryCndMaps[i]->BC == 2601) {
4096 m_bc2601IsActive = true;
4097 }
4098 }
4099
4100 if(m_bc2601IsActive) {
4114 m_bc2601InitialStartup = false;
4115 m_bc2601InitialStartup =
4116 Context::getSolverProperty<MBool>("initialStartup2601", m_solverId, AT_, &m_bc2601InitialStartup);
4117
4126 m_bc2601GammaEpsilon = 0.12;
4127 m_bc2601GammaEpsilon =
4128 Context::getSolverProperty<MFloat>("gammaEpsilon2601", m_solverId, AT_, &m_bc2601GammaEpsilon);
4129
4130 mAlloc(m_bc2601noCells, nDim, "m_bc2601noCells", 0, AT_);
4131 mAlloc(m_bc2601noActiveCells, nDim, "m_bc2601noCells", 0, AT_);
4132 mAlloc(m_bc2601noOffsetCells, nDim, "m_bc2601noCells", 0, AT_);
4133 if(m_bc2601) {
4134 for(MInt dim = 0; dim < nDim; dim++) {
4135 m_bc2601noOffsetCells[dim] = m_nOffsetCells[dim];
4136 m_bc2601noCells[dim] = m_nCells[dim];
4137 m_bc2601noActiveCells[dim] = m_bc2601noCells[dim] - 2 * m_noGhostLayers;
4138 }
4139 m_bc2601noOffsetCells[nDim - 2] = 0;
4140 m_bc2601noCells[nDim - 2] = m_noGhostLayers;
4141 m_bc2601noActiveCells[nDim - 2] = m_noGhostLayers;
4142 MInt noCellsBC = 1;
4143 for(MInt dim = 0; dim < nDim; dim++) {
4144 noCellsBC *= m_bc2601noCells[dim];
4145 }
4146 mAlloc(m_bc2601Variables, CV->noVariables, noCellsBC, "m_bc2601Variables", -123.456, AT_);
4147 }
4148 }
4149}
4150
4151
4155template <MInt nDim>
4157 TRACE();
4158
4159 MBool fullRANS = false;
4160 m_zoneType = "LES";
4161 m_rans = false;
4162
4175 m_zonal = false;
4176 if(Context::propertyExists("zonal", m_solverId)) {
4177 m_zonal = Context::getSolverProperty<MBool>("zonal", m_solverId, AT_);
4178 }
4179
4192 if(Context::propertyExists("fullRANS", m_solverId)) {
4193 fullRANS = Context::getSolverProperty<MBool>("fullRANS", m_solverId, AT_, &fullRANS);
4194 }
4195
4196 if(m_zonal) {
4197 // activate the nut FQ field
4198 FQ->neededFQVariables[FQ->AVG_RHO] = 1;
4199 FQ->neededFQVariables[FQ->AVG_U] = 1;
4200 FQ->neededFQVariables[FQ->AVG_V] = 1;
4201 FQ->neededFQVariables[FQ->AVG_W] = 1;
4202 FQ->neededFQVariables[FQ->AVG_P] = 1;
4203
4204 m_zonalExchangeInterval = 5;
4205 m_zonalExchangeInterval =
4206 Context::getSolverProperty<MInt>("zonalExchangeInterval", m_solverId, AT_, &m_zonalExchangeInterval);
4207
4208 m_zonalAveragingFactor = 128.0;
4209 m_zonalAveragingFactor =
4210 Context::getSolverProperty<MFloat>("zonalAvgFactor", m_solverId, AT_, &m_zonalAveragingFactor);
4211
4212
4225 MInt noRansZones = 0;
4226 noRansZones = Context::getSolverProperty<MInt>("noRansZones", m_solverId, AT_, &noRansZones);
4227 MIntScratchSpace ransZones(noRansZones, AT_, "ransZones");
4228 ransZones.fill(0);
4229
4242 for(MInt RANS = 0; RANS < noRansZones; RANS++) {
4243 ransZones[RANS] = Context::getSolverProperty<MInt>("ransZone", m_solverId, AT_, &ransZones[RANS], RANS);
4244 }
4245
4246 // Find out if own partition is RANS
4247 for(MInt RANS = 0; RANS < noRansZones; RANS++) {
4248 MInt blockID = m_grid->getMyBlockId();
4249 if(blockID == ransZones[RANS]) {
4250 m_zoneType = "RANS";
4251 m_rans = true;
4252 }
4253 }
4254
4255 // Count the zones
4256 MInt NOZONES[2] = {0, 0};
4257 MInt NOZONESH[2] = {0, 0};
4258
4259 if(m_zoneType == "RANS") {
4260 NOZONES[0] = 1;
4261 NOZONES[1] = 0;
4262 } else {
4263 NOZONES[0] = 0;
4264 NOZONES[1] = 1;
4265 }
4266
4267 MPI_Allreduce(NOZONES, NOZONESH, 2, MPI_INT, MPI_SUM, m_StructuredComm, AT_, "NOZONES", "NOZONESH");
4268
4269 // Give overview over RANS/LES zones
4270 if(domainId() == 0) {
4271 cout << "////////////////////////////////////////////////////////////////////////" << endl;
4272 cout << "No of RANS partitions: " << NOZONESH[0] << " , No of LES partitions: " << NOZONESH[1] << endl;
4273 cout << "////////////////////////////////////////////////////////////////////////" << endl;
4274 }
4275 m_log << "No of RANS partitions: " << NOZONESH[0] << " , No of LES partitions: " << NOZONESH[1] << endl;
4276 }
4277
4278 if(fullRANS) {
4279 m_log << "Starting a full RANS computation" << endl;
4280 m_zoneType = "RANS";
4281 m_rans = true;
4282 }
4283
4284 if(m_zonal || m_rans) {
4285 m_ransMethod =
4286 static_cast<RansMethod>(string2enum(Context::getSolverProperty<MString>("ransMethod", m_solverId, AT_)));
4287
4288 if(noRansEquations(m_ransMethod) == 2) {
4289 if(!Context::propertyExists("rans2eq_mode", m_solverId))
4290 mTerm(1, "Usage of 2-eq. RANS model requires specification of rans2eq_mode: {init|production}");
4291 m_rans2eq_mode = Context::getSolverProperty<MString>("rans2eq_mode", m_solverId, AT_, &m_rans2eq_mode);
4292 if(m_rans2eq_mode != "init" && m_rans2eq_mode != "production") mTerm(1, "OMG! OMG!");
4293 }
4294
4295 if(m_porous && m_ransMethod != RANS_KEPSILON)
4296 mTerm(1, "Porous RANS computation is only supported by k-epsilon model!");
4297
4298 // Read properties required to compute inflow k & epsilon
4299 if(m_ransMethod == RANS_KEPSILON) {
4300 m_keps_nonDimType = true; // true=>non-dim with a_0^2
4301 m_keps_nonDimType = Context::getSolverProperty<MBool>("keps_nonDimType", m_solverId, AT_, &m_keps_nonDimType);
4302
4303 // TODO_SS labels:FV don't force specification of m_I and m_epsScale -> only for a few BCs and ICs mandatory
4304 if(!Context::propertyExists("turbulenceIntensity", m_solverId))
4305 mTerm(1, "Usage of k-epsilon model requires specification of inflow turbulenceIntensity");
4306 m_I = Context::getSolverProperty<MFloat>("turbulenceIntensity", m_solverId, AT_, &m_I);
4307
4308
4309 const MBool turbLengthScaleExists = Context::propertyExists("turbulentLengthScale", m_solverId);
4310 const MBool turbViscRatioExists = Context::propertyExists("turbulentViscosityRatio", m_solverId);
4311 const MBool turbEpsInfty = Context::propertyExists("turbEpsInfty", m_solverId);
4312 if(turbLengthScaleExists + turbViscRatioExists + turbEpsInfty != 1)
4313 mTerm(1, "Usage of k-epsilon model requires the specification of either a turbulentLengthScale or a "
4314 "turbulentViscosityRatio");
4315
4316 if(turbLengthScaleExists) {
4317 m_kepsICMethod = 1;
4318 m_epsScale = Context::getSolverProperty<MFloat>("turbulentLengthScale", m_solverId, AT_);
4319 } else if(turbViscRatioExists) {
4320 m_kepsICMethod = 2;
4321 // m_epsScale = muTurb / muLam
4322 m_epsScale = Context::getSolverProperty<MFloat>("turbulentViscosityRatio", m_solverId, AT_);
4323 } else {
4324 m_kepsICMethod = 3;
4325 m_epsScale = Context::getSolverProperty<MFloat>("turbEpsInfty", m_solverId, AT_);
4326 }
4327
4328 if(m_porous) {
4329 FQ->neededFQVariables[FQ->POROUS_INDICATOR] = 1;
4330 FQ->outputFQVariables[FQ->POROUS_INDICATOR] = false;
4331 }
4332 }
4333
4334 FQ->neededFQVariables[FQ->NU_T] = 1;
4335 FQ->outputFQVariables[FQ->NU_T] = true;
4336
4337 if(m_ransMethod == RANS_KEPSILON) {
4338 FQ->neededFQVariables[FQ->UTAU] = 1;
4339 FQ->outputFQVariables[FQ->UTAU] = false;
4340 if(m_porous) {
4341 FQ->neededFQVariables[FQ->UTAU2] = 1;
4342 FQ->outputFQVariables[FQ->UTAU2] = false;
4343 }
4344 }
4345
4346 if(m_ransMethod == RANS_SA_DV || m_ransMethod == RANS_KEPSILON) {
4347 FQ->neededFQVariables[FQ->WALLDISTANCE] = 1;
4348 FQ->outputFQVariables[FQ->WALLDISTANCE] = false;
4349 }
4350 }
4351
4352 if(m_rans) {
4353 m_ransTransPos = -1000000.0;
4354 if(Context::propertyExists("ransTransPos", m_solverId)) {
4355 m_ransTransPos = Context::getSolverProperty<MFloat>("ransTransPos", m_solverId, AT_, &m_ransTransPos);
4356 }
4357 }
4358}
4359
4360template <MInt nDim>
4362 // We will decide whether we will use RANS Variables or not depending on the solver
4363
4364 if(m_zoneType == "RANS") {
4365 // number of RANS equations
4366 m_noRansEquations = noRansEquations(m_ransMethod);
4367
4368 CV = make_unique<MConservativeVariables<nDim>>(m_noSpecies, m_noRansEquations);
4369 PV = make_unique<MPrimitiveVariables<nDim>>(m_noSpecies, m_noRansEquations);
4370 } else {
4371 // we only have LES solvers
4372 m_noRansEquations = 0;
4373 CV = make_unique<MConservativeVariables<nDim>>(m_noSpecies);
4374 PV = make_unique<MPrimitiveVariables<nDim>>(m_noSpecies);
4375 }
4376
4377 // LES zones have 5 but RANS zone have 6 variables,
4378 // we have to use maxNoVariables for allocations and
4379 // IO related procedures which use MPI
4380 m_maxNoVariables = -1;
4381 MPI_Allreduce(&PV->noVariables, &m_maxNoVariables, 1, MPI_INT, MPI_MAX, m_StructuredComm, AT_, "PV->noVariables",
4382 "m_maxNoVariables");
4383 m_log << "Max number of variables: " << m_maxNoVariables << endl;
4384}
4385
4386
4391template <MInt nDim>
4393 // as only 1D array is used the ghostcells will also need to have a right hand side variables
4394 // if storage need to be saved go over the inner loops and remove storge of ghost rhs
4395 const MInt noVars = CV->noVariables;
4396 for(MInt cellId = 0; cellId < m_noCells; cellId++) {
4397 for(MInt varId = 0; varId < noVars; varId++) {
4398 m_cells->rightHandSide[varId][cellId] = F0;
4399 }
4400 }
4401}
4402
4403
4404template <MInt nDim>
4406 // don't do this here, because it
4407 // will be executed before exchange() and
4408 // then wrong primitve values are in the GC
4409 // computePrimitiveVariables();
4410}
4411
4412
4413template <MInt nDim>
4414template <MFloat (FvStructuredSolver<nDim>::*totalEnergy_func)(MInt) const>
4416 m_log << "we got into the general formulation but should be in the other one" << endl;
4417 const MFloat FgammaMinusOne = F1 / (m_gamma - 1.0);
4418 MFloat** const RESTRICT cvars = m_cells->variables;
4419 MFloat** const RESTRICT pvars = m_cells->pvariables;
4420 MFloat rhoVelocity[3] = {0.0, 0.0, 0.0};
4421
4422 for(MInt cellId = 0; cellId < m_noCells; cellId++) {
4423 MFloat velPOW2 = F0;
4424 // copy the density
4425 const MFloat rho = pvars[PV->RHO][cellId];
4426 // compute the rho * velocity
4427 for(MInt i = 0; i < nDim; i++) {
4428 rhoVelocity[i] = pvars[PV->VV[i]][cellId] * rho;
4429 velPOW2 += POW2(pvars[PV->VV[i]][cellId]);
4430 }
4431
4432 // regular conservative variables
4433 cvars[CV->RHO][cellId] = rho;
4434 for(MInt i = 0; i < nDim; i++) {
4435 cvars[CV->RHO_VV[i]][cellId] = rhoVelocity[i];
4436 }
4437
4438 cvars[CV->RHO_E][cellId] =
4439 pvars[PV->P][cellId] * FgammaMinusOne + F1B2 * rho * velPOW2 + (this->*totalEnergy_func)(cellId);
4440
4441 // rans
4442 for(MInt ransVar = 0; ransVar < m_noRansEquations; ransVar++) {
4443 // pvars[PV->RANS_VAR[ransVar]][cellId] = mMax(pvars[PV->RANS_VAR[ransVar]][cellId], F0);
4444 // cvars[CV->RANS_VAR[ransVar]][cellId] = mMax(pvars[PV->RANS_VAR[ransVar]][cellId], F0)*rho;
4445 cvars[CV->RANS_VAR[ransVar]][cellId] = pvars[PV->RANS_VAR[ransVar]][cellId] * rho;
4446 }
4447
4448 // species
4449 for(MInt s = 0; s < m_noSpecies; s++) {
4450 cvars[CV->RHO_Y[s]][cellId] = pvars[PV->Y[s]][cellId] * rho;
4451 }
4452 }
4453}
4454
4455template <MInt nDim>
4457 if(noRansEquations(m_ransMethod) == 2) {
4458 if(m_rans2eq_mode == "production")
4459 computeConservativeVariables_<&FvStructuredSolver::totalEnergy_twoEqRans>();
4460 else
4461 computeConservativeVariables_();
4462 } else
4463 computeConservativeVariables_();
4464}
4465
4466
4467template <MInt nDim>
4469 m_cells->pvariables[varId][cellId] = var;
4470}
4471
4472
4473template <MInt nDim>
4475 TRACE();
4476
4477 switch(m_volumeForceMethod) {
4478 case 0:
4479 // default
4480 break;
4481 case 1:
4482 // To be used in combination with bc2402
4483 if(globalTimeStep % m_volumeForceUpdateInterval == 0 && m_RKStep == 0) {
4484 const MFloat relaxationFactor = 0.02;
4485 MPI_Allreduce(MPI_IN_PLACE, &m_inflowVelAvg, 1, MPI_DOUBLE, MPI_MAX, m_StructuredComm, AT_, "MPI_IN_PLACE",
4486 "inflowVelAvg");
4487 m_log << "GlobalTimeStep=" << globalTimeStep << setprecision(6)
4488 << ": inflowVelAvg(targetVelAvg)=" << m_inflowVelAvg << "(" << PV->UInfinity
4489 << "), volumeForce=" << m_volumeForce[0] << " -> ";
4490 const MFloat deltaVelAvg = PV->UInfinity - m_inflowVelAvg;
4491 m_volumeForce[0] += deltaVelAvg / (m_volumeForceUpdateInterval * m_timeStep) * relaxationFactor;
4492 m_volumeForce[0] = std::max(m_volumeForce[0], 0.0);
4493 m_log << setprecision(6) << m_volumeForce[0] << endl;
4494 m_inflowVelAvg = -1.0;
4495 }
4496 break;
4497 default:
4498 mTerm(1, "Unknown volume force method!");
4499 }
4500}
4501
4502
4503template <MInt nDim>
4505 TRACE();
4506
4507 for(MInt dim = 0; dim < nDim; dim++) {
4508 for(MInt cellId = 0; cellId < m_noCells; cellId++) {
4509 m_cells->rightHandSide[CV->RHO_VV[dim]][cellId] +=
4510 m_cells->variables[CV->RHO][cellId] * m_volumeForce[dim] * m_cells->cellJac[cellId];
4511 m_cells->rightHandSide[CV->RHO_E][cellId] +=
4512 m_cells->variables[CV->RHO_VV[dim]][cellId] * m_volumeForce[dim] * m_cells->cellJac[cellId];
4513 }
4514 }
4515}
4516
4517
4526template <>
4528 constexpr MInt nDim = 3;
4529 // create a file
4530 // a) all boxes for each time in one file
4531 // b) all boxes in one file and one file per output
4532 stringstream filename;
4533 filename << m_boxOutputDir << "boxOutput" << m_outputIterationNumber << m_outputFormat;
4534
4535 ParallelIoHdf5 pio(filename.str(), maia::parallel_io::PIO_REPLACE, m_StructuredComm);
4536
4537 writeHeaderAttributes(&pio, "boxes");
4538 writePropertiesAsAttributes(&pio, "");
4539 pio.setAttribute(m_boxNoBoxes, "noBoxes", "");
4540
4541 // create datasets
4542 ParallelIo::size_type localBoxSize[nDim]{0};
4543 ParallelIo::size_type localBoxOffset[nDim]{0};
4544 ParallelIo::size_type globalBoxSize[nDim]{0};
4545 ParallelIo::size_type localDomainBoxOffset[nDim]{0};
4546
4547 for(MInt i = 0; i < m_noBlocks; ++i) {
4548 for(MInt b = 0; b < m_boxNoBoxes; ++b) {
4549 if(m_boxBlock[b] == i) {
4550 // create a dataset for the solver
4551
4552 for(MInt dim = 0; dim < nDim; ++dim) {
4553 globalBoxSize[dim] = m_boxSize[b][dim];
4554 }
4555
4556 stringstream pathName;
4557 pathName << "/box" << b;
4558
4559 pio.setAttribute(m_boxOffset[b][2], "offseti", pathName.str());
4560 pio.setAttribute(m_boxOffset[b][1], "offsetj", pathName.str());
4561 pio.setAttribute(m_boxOffset[b][0], "offsetk", pathName.str());
4562
4563 pio.setAttribute(m_boxSize[b][2], "sizei", pathName.str());
4564 pio.setAttribute(m_boxSize[b][1], "sizej", pathName.str());
4565 pio.setAttribute(m_boxSize[b][0], "sizek", pathName.str());
4566
4567 pio.setAttribute(i, "blockId", pathName.str());
4568
4569 MInt hasCoordinates = 0;
4570
4571 for(MInt v = 0; v < m_maxNoVariables; v++) {
4572 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), m_pvariableNames[v], nDim, globalBoxSize);
4573 }
4574 // create datasets for fq-field
4575 for(MInt v = 0; v < FQ->noFQVariables; v++) {
4576 if(FQ->fqWriteOutputBoxes[v]) {
4577 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), FQ->fqNames[v], nDim, globalBoxSize);
4578 }
4579 }
4580 // create datasets for the variables
4581 if(m_boxWriteCoordinates) {
4582 hasCoordinates = 1;
4583 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), "x", nDim, globalBoxSize);
4584 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), "y", nDim, globalBoxSize);
4585 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), "z", nDim, globalBoxSize);
4586 }
4587 // write output to check if coordinates are contained within the variable list
4588 pio.setAttribute(hasCoordinates, "hasCoordinates", pathName.str());
4589 }
4590 }
4591 }
4592
4593 for(MInt b = 0; b < m_boxNoBoxes; ++b) {
4594 // check if the box is contained your inputsolverId
4595 if(m_boxBlock[b] == m_blockId
4596 && ((m_nOffsetCells[2] <= m_boxOffset[b][2] && m_boxOffset[b][2] < m_nOffsetCells[2] + m_nActiveCells[2])
4597 || (m_boxOffset[b][2] <= m_nOffsetCells[2] && m_nOffsetCells[2] < m_boxOffset[b][2] + m_boxSize[b][2]))
4598 && ((m_nOffsetCells[1] <= m_boxOffset[b][1] && m_boxOffset[b][1] < m_nOffsetCells[1] + m_nActiveCells[1])
4599 || (m_boxOffset[b][1] <= m_nOffsetCells[1] && m_nOffsetCells[1] < m_boxOffset[b][1] + m_boxSize[b][1]))
4600 && ((m_nOffsetCells[0] <= m_boxOffset[b][0] && m_boxOffset[b][0] < m_nOffsetCells[0] + m_nActiveCells[0])
4601 || (m_boxOffset[b][0] <= m_nOffsetCells[0]
4602 && m_nOffsetCells[0] < m_boxOffset[b][0] + m_boxSize[b][0]))) { // the box is contained
4603 // get the size of the box!!!
4604
4605 for(MInt dim = 0; dim < nDim; ++dim) {
4606 if(m_nOffsetCells[dim] <= m_boxOffset[b][dim]
4607 && m_boxOffset[b][dim] + m_boxSize[b][dim] < m_nOffsetCells[dim] + m_nActiveCells[dim]) {
4608 localBoxSize[dim] = m_boxSize[b][dim];
4609 localBoxOffset[dim] = 0;
4610 localDomainBoxOffset[dim] = m_boxOffset[b][dim] - m_nOffsetCells[dim];
4611 } else if(m_nOffsetCells[dim] <= m_boxOffset[b][dim]) {
4612 localBoxSize[dim] = (m_nOffsetCells[dim] + m_nActiveCells[dim]) - m_boxOffset[b][dim];
4613 localBoxOffset[dim] = 0;
4614 localDomainBoxOffset[dim] = m_boxOffset[b][dim] - m_nOffsetCells[dim];
4615 } else if(m_boxOffset[b][dim] <= m_nOffsetCells[dim]
4616 && m_nOffsetCells[dim] + m_nActiveCells[dim] < m_boxOffset[b][dim] + m_boxSize[b][dim]) {
4617 localBoxSize[dim] = m_nActiveCells[dim];
4618 localBoxOffset[dim] = m_nOffsetCells[dim] - m_boxOffset[b][dim];
4619 localDomainBoxOffset[dim] = 0;
4620 } else {
4621 localBoxSize[dim] = (m_boxOffset[b][dim] + m_boxSize[b][dim]) - m_nOffsetCells[dim];
4622 localBoxOffset[dim] = m_nOffsetCells[dim] - m_boxOffset[b][dim];
4623 localDomainBoxOffset[dim] = 0;
4624 }
4625 }
4626
4627 stringstream pathName;
4628 pathName << "/box" << b;
4629 MInt totalLocalSize = 1;
4630 for(MInt dim = 0; dim < nDim; ++dim) {
4631 totalLocalSize *= localBoxSize[dim];
4632 }
4633 MInt noFields = m_maxNoVariables;
4634 if(FQ->noFQBoxOutput > 0) noFields += FQ->noFQBoxOutput;
4635 if(m_boxWriteCoordinates) noFields += nDim;
4636
4637
4638 MFloatScratchSpace localBoxVar(noFields * totalLocalSize, AT_, "local Box Variables");
4639
4640 MInt cellId = 0;
4641 MInt localId = 0;
4642 MInt offset = 0;
4643
4644 MFloat noVars = m_maxNoVariables;
4645 for(MInt var = 0; var < noVars; ++var) {
4646 for(MInt k = m_noGhostLayers + localDomainBoxOffset[0];
4647 k < m_noGhostLayers + localDomainBoxOffset[0] + localBoxSize[0];
4648 ++k) {
4649 for(MInt j = m_noGhostLayers + localDomainBoxOffset[1];
4650 j < m_noGhostLayers + localDomainBoxOffset[1] + localBoxSize[1];
4651 ++j) {
4652 for(MInt i = m_noGhostLayers + localDomainBoxOffset[2];
4653 i < m_noGhostLayers + localDomainBoxOffset[2] + localBoxSize[2];
4654 ++i) {
4655 cellId = i + (j + k * m_nCells[1]) * m_nCells[2];
4656 MInt boxI = i - m_noGhostLayers - localDomainBoxOffset[2];
4657 MInt boxJ = j - m_noGhostLayers - localDomainBoxOffset[1];
4658 MInt boxK = k - m_noGhostLayers - localDomainBoxOffset[0];
4659 localId = var * totalLocalSize + (boxI + (boxJ + boxK * localBoxSize[1]) * localBoxSize[2]);
4660 localBoxVar[localId] = m_cells->pvariables[var][cellId];
4661 }
4662 }
4663 }
4664 }
4665 offset += m_maxNoVariables;
4666
4667 if(FQ->noFQBoxOutput > 0) {
4668 for(MInt v = 0; v < FQ->noFQVariables; ++v) {
4669 if(FQ->fqWriteOutputBoxes[v]) {
4670 for(MInt k = m_noGhostLayers + localDomainBoxOffset[0];
4671 k < m_noGhostLayers + localDomainBoxOffset[0] + localBoxSize[0];
4672 ++k) {
4673 for(MInt j = m_noGhostLayers + localDomainBoxOffset[1];
4674 j < m_noGhostLayers + localDomainBoxOffset[1] + localBoxSize[1];
4675 ++j) {
4676 for(MInt i = m_noGhostLayers + localDomainBoxOffset[2];
4677 i < m_noGhostLayers + localDomainBoxOffset[2] + localBoxSize[2];
4678 ++i) {
4679 cellId = i + (j + k * m_nCells[1]) * m_nCells[2];
4680 MInt boxI = i - m_noGhostLayers - localDomainBoxOffset[2];
4681 MInt boxJ = j - m_noGhostLayers - localDomainBoxOffset[1];
4682 MInt boxK = k - m_noGhostLayers - localDomainBoxOffset[0];
4683 localId = (offset)*totalLocalSize + (boxI + (boxJ + boxK * localBoxSize[1]) * localBoxSize[2]);
4684 localBoxVar[localId] = m_cells->fq[v][cellId];
4685 }
4686 }
4687 }
4688 ++offset;
4689 }
4690 }
4691 }
4692
4693 if(m_boxWriteCoordinates) {
4694 for(MInt dim = 0; dim < nDim; dim++) {
4695 for(MInt k = m_noGhostLayers + localDomainBoxOffset[0];
4696 k < m_noGhostLayers + localDomainBoxOffset[0] + localBoxSize[0];
4697 ++k) {
4698 for(MInt j = m_noGhostLayers + localDomainBoxOffset[1];
4699 j < m_noGhostLayers + localDomainBoxOffset[1] + localBoxSize[1];
4700 ++j) {
4701 for(MInt i = m_noGhostLayers + localDomainBoxOffset[2];
4702 i < m_noGhostLayers + localDomainBoxOffset[2] + localBoxSize[2];
4703 ++i) {
4704 cellId = i + (j + k * m_nCells[1]) * m_nCells[2];
4705 MInt boxI = i - m_noGhostLayers - localDomainBoxOffset[2];
4706 MInt boxJ = j - m_noGhostLayers - localDomainBoxOffset[1];
4707 MInt boxK = k - m_noGhostLayers - localDomainBoxOffset[0];
4708 localId = (offset + dim) * totalLocalSize + (boxI + (boxJ + boxK * localBoxSize[1]) * localBoxSize[2]);
4709 localBoxVar[localId] = m_cells->coordinates[dim][cellId];
4710 }
4711 }
4712 }
4713 }
4714 offset += nDim;
4715 }
4719 //--> /primitive/conservative variables
4720 for(MInt v = 0; v < m_maxNoVariables; v++) {
4721 pio.writeArray(&localBoxVar[v * totalLocalSize], pathName.str(), m_pvariableNames[v], nDim, localBoxOffset,
4722 localBoxSize);
4723 }
4724 offset = m_maxNoVariables;
4725 //--> fq field
4726 for(MInt v = 0; v < FQ->noFQVariables; ++v) {
4727 if(FQ->fqWriteOutputBoxes[v]) {
4728 pio.writeArray(&localBoxVar[(offset)*totalLocalSize], pathName.str(), FQ->fqNames[v], nDim, localBoxOffset,
4729 localBoxSize);
4730 offset++;
4731 }
4732 }
4733
4734 if(m_boxWriteCoordinates) {
4735 pio.writeArray(&localBoxVar[(offset + 0) * totalLocalSize], pathName.str(), "x", nDim, localBoxOffset,
4736 localBoxSize);
4737 pio.writeArray(&localBoxVar[(offset + 1) * totalLocalSize], pathName.str(), "y", nDim, localBoxOffset,
4738 localBoxSize);
4739 pio.writeArray(&localBoxVar[(offset + 2) * totalLocalSize], pathName.str(), "z", nDim, localBoxOffset,
4740 localBoxSize);
4741 offset += nDim;
4742 }
4743
4744 } else { // write out nothing as box is not contained
4745 stringstream pathName;
4746 pathName << "/box" << b;
4747 for(MInt dim = 0; dim < nDim; ++dim) {
4748 localBoxSize[dim] = 0;
4749 localBoxOffset[dim] = 0;
4750 }
4751 MFloat empty = 0;
4752 for(MInt v = 0; v < m_maxNoVariables; ++v) {
4753 pio.writeArray(&empty, pathName.str(), m_pvariableNames[v], nDim, localBoxOffset, localBoxSize);
4754 }
4755 for(MInt v = 0; v < FQ->noFQVariables; ++v) {
4756 if(FQ->fqWriteOutputBoxes[v]) {
4757 pio.writeArray(&empty, pathName.str(), FQ->fqNames[v], nDim, localBoxOffset, localBoxSize);
4758 }
4759 }
4760
4761 if(m_boxWriteCoordinates) {
4762 pio.writeArray(&empty, pathName.str(), "x", nDim, localBoxOffset, localBoxSize);
4763 pio.writeArray(&empty, pathName.str(), "y", nDim, localBoxOffset, localBoxSize);
4764 pio.writeArray(&empty, pathName.str(), "z", nDim, localBoxOffset, localBoxSize);
4765 }
4766 }
4767 }
4768}
4769
4778template <>
4780 constexpr MInt nDim = 2;
4781 // create a file
4782 // a) all boxes for each time in one file
4783 // b) all boxes in one file and one file per output
4784 stringstream filename;
4785 filename << m_boxOutputDir << "boxOutput" << m_outputIterationNumber << m_outputFormat;
4786
4787 ParallelIoHdf5 pio(filename.str(), maia::parallel_io::PIO_REPLACE, m_StructuredComm);
4788
4789 writeHeaderAttributes(&pio, "boxes");
4790 writePropertiesAsAttributes(&pio, "");
4791 pio.setAttribute(m_boxNoBoxes, "noBoxes", "");
4792
4793 // create datasets
4794 ParallelIo::size_type localBoxSize[nDim]{0};
4795 ParallelIo::size_type localBoxOffset[nDim]{0};
4796 ParallelIo::size_type globalBoxSize[nDim]{0};
4797 ParallelIo::size_type localDomainBoxOffset[nDim]{0};
4798
4799
4800 for(MInt i = 0; i < m_noBlocks; ++i) {
4801 for(MInt b = 0; b < m_boxNoBoxes; ++b) {
4802 if(m_boxBlock[b] == i) {
4803 // create a dataset for the solver
4804
4805 for(MInt dim = 0; dim < nDim; ++dim) {
4806 globalBoxSize[dim] = m_boxSize[b][dim];
4807 }
4808
4809 stringstream pathName;
4810 pathName << "/box" << b;
4811
4812 pio.setAttribute(m_boxOffset[b][2], "offseti", pathName.str());
4813 pio.setAttribute(m_boxOffset[b][1], "offsetj", pathName.str());
4814
4815 pio.setAttribute(m_boxSize[b][2], "sizei", pathName.str());
4816 pio.setAttribute(m_boxSize[b][1], "sizej", pathName.str());
4817
4818 pio.setAttribute(i, "blockId", pathName.str());
4819
4820 MInt hasCoordinates = 0;
4821
4822 for(MInt v = 0; v < m_maxNoVariables; v++) {
4823 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), m_pvariableNames[v], nDim, globalBoxSize);
4824 }
4825 // create datasets for fq-field
4826 for(MInt v = 0; v < FQ->noFQVariables; v++) {
4827 if(FQ->fqWriteOutputBoxes[v]) {
4828 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), FQ->fqNames[v], nDim, globalBoxSize);
4829 }
4830 }
4831 // create datasets for the variables
4832 if(m_boxWriteCoordinates) {
4833 hasCoordinates = 1;
4834 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), "x", nDim, globalBoxSize);
4835 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName.str(), "y", nDim, globalBoxSize);
4836 }
4837 // write output to check if coordinates are contained within the variable list
4838 pio.setAttribute(hasCoordinates, "hasCoordinates", pathName.str());
4839 }
4840 }
4841 }
4842
4843 for(MInt b = 0; b < m_boxNoBoxes; ++b) {
4844 // check if the box is contained your inputsolverId
4845 if(m_boxBlock[b] == m_blockId
4846 && ((m_nOffsetCells[1] <= m_boxOffset[b][1] && m_boxOffset[b][1] < m_nOffsetCells[1] + m_nActiveCells[1])
4847 || (m_boxOffset[b][1] <= m_nOffsetCells[1] && m_nOffsetCells[1] < m_boxOffset[b][1] + m_boxSize[b][1]))
4848 && ((m_nOffsetCells[0] <= m_boxOffset[b][0] && m_boxOffset[b][0] < m_nOffsetCells[0] + m_nActiveCells[0])
4849 || (m_boxOffset[b][0] <= m_nOffsetCells[0]
4850 && m_nOffsetCells[0] < m_boxOffset[b][0] + m_boxSize[b][0]))) { // the box is contained
4851 // get the size of the box!!!
4852
4853 for(MInt dim = 0; dim < nDim; ++dim) {
4854 if(m_nOffsetCells[dim] <= m_boxOffset[b][dim]
4855 && m_boxOffset[b][dim] + m_boxSize[b][dim] < m_nOffsetCells[dim] + m_nActiveCells[dim]) {
4856 localBoxSize[dim] = m_boxSize[b][dim];
4857 localBoxOffset[dim] = 0;
4858 localDomainBoxOffset[dim] = m_boxOffset[b][dim] - m_nOffsetCells[dim];
4859 } else if(m_nOffsetCells[dim] <= m_boxOffset[b][dim]) {
4860 localBoxSize[dim] = (m_nOffsetCells[dim] + m_nActiveCells[dim]) - m_boxOffset[b][dim];
4861 localBoxOffset[dim] = 0;
4862 localDomainBoxOffset[dim] = m_boxOffset[b][dim] - m_nOffsetCells[dim];
4863 } else if(m_boxOffset[b][dim] <= m_nOffsetCells[dim]
4864 && m_nOffsetCells[dim] + m_nActiveCells[dim] < m_boxOffset[b][dim] + m_boxSize[b][dim]) {
4865 localBoxSize[dim] = m_nActiveCells[dim];
4866 localBoxOffset[dim] = m_nOffsetCells[dim] - m_boxOffset[b][dim];
4867 localDomainBoxOffset[dim] = 0;
4868 } else {
4869 localBoxSize[dim] = (m_boxOffset[b][dim] + m_boxSize[b][dim]) - m_nOffsetCells[dim];
4870 localBoxOffset[dim] = m_nOffsetCells[dim] - m_boxOffset[b][dim];
4871 localDomainBoxOffset[dim] = 0;
4872 }
4873 }
4874
4875 stringstream pathName;
4876 pathName << "/box" << b;
4877 MInt totalLocalSize = 1;
4878 for(MInt dim = 0; dim < nDim; ++dim) {
4879 totalLocalSize *= localBoxSize[dim];
4880 }
4881 MInt noFields = m_maxNoVariables;
4882 if(FQ->noFQBoxOutput > 0) noFields += FQ->noFQBoxOutput;
4883 if(m_boxWriteCoordinates) noFields += nDim;
4884
4885
4886 MFloatScratchSpace localBoxVar(noFields * totalLocalSize, AT_, "local Box Variables");
4887
4888 MInt cellId = 0;
4889 MInt localId = 0;
4890 MInt offset = 0;
4891
4892 MFloat noVars = m_maxNoVariables;
4893 for(MInt var = 0; var < noVars; ++var) {
4894 for(MInt j = m_noGhostLayers + localDomainBoxOffset[0];
4895 j < m_noGhostLayers + localDomainBoxOffset[0] + localBoxSize[0];
4896 ++j) {
4897 for(MInt i = m_noGhostLayers + localDomainBoxOffset[1];
4898 i < m_noGhostLayers + localDomainBoxOffset[1] + localBoxSize[1];
4899 ++i) {
4900 cellId = i + j * m_nCells[1];
4901 MInt boxI = i - m_noGhostLayers - localDomainBoxOffset[1];
4902 MInt boxJ = j - m_noGhostLayers - localDomainBoxOffset[0];
4903 localId = var * totalLocalSize + (boxI + boxJ * localBoxSize[1]);
4904 localBoxVar[localId] = m_cells->pvariables[var][cellId];
4905 }
4906 }
4907 }
4908 offset += m_maxNoVariables;
4909
4910 if(FQ->noFQBoxOutput > 0) {
4911 for(MInt v = 0; v < FQ->noFQVariables; ++v) {
4912 if(FQ->fqWriteOutputBoxes[v]) {
4913 for(MInt j = m_noGhostLayers + localDomainBoxOffset[0];
4914 j < m_noGhostLayers + localDomainBoxOffset[0] + localBoxSize[0];
4915 ++j) {
4916 for(MInt i = m_noGhostLayers + localDomainBoxOffset[1];
4917 i < m_noGhostLayers + localDomainBoxOffset[1] + localBoxSize[1];
4918 ++i) {
4919 cellId = i + j * m_nCells[1];
4920 MInt boxI = i - m_noGhostLayers - localDomainBoxOffset[1];
4921 MInt boxJ = j - m_noGhostLayers - localDomainBoxOffset[0];
4922 localId = (offset)*totalLocalSize + (boxI + boxJ * localBoxSize[1]);
4923 localBoxVar[localId] = m_cells->fq[v][cellId];
4924 }
4925 }
4926 ++offset;
4927 }
4928 }
4929 }
4930
4931 if(m_boxWriteCoordinates) {
4932 for(MInt dim = 0; dim < nDim; dim++) {
4933 for(MInt j = m_noGhostLayers + localDomainBoxOffset[0];
4934 j < m_noGhostLayers + localDomainBoxOffset[0] + localBoxSize[0];
4935 ++j) {
4936 for(MInt i = m_noGhostLayers + localDomainBoxOffset[1];
4937 i < m_noGhostLayers + localDomainBoxOffset[1] + localBoxSize[1];
4938 ++i) {
4939 cellId = i + j * m_nCells[1];
4940 MInt boxI = i - m_noGhostLayers - localDomainBoxOffset[1];
4941 MInt boxJ = j - m_noGhostLayers - localDomainBoxOffset[0];
4942 localId = (offset + dim) * totalLocalSize + (boxI + boxJ * localBoxSize[1]);
4943 localBoxVar[localId] = m_cells->coordinates[dim][cellId];
4944 }
4945 }
4946 }
4947 offset += nDim;
4948 }
4952 //--> /primitive/conservative variables
4953 for(MInt v = 0; v < m_maxNoVariables; v++) {
4954 pio.writeArray(&localBoxVar[v * totalLocalSize], pathName.str(), m_pvariableNames[v], nDim, localBoxOffset,
4955 localBoxSize);
4956 }
4957 offset = m_maxNoVariables;
4958 //--> fq field
4959 for(MInt v = 0; v < FQ->noFQVariables; ++v) {
4960 if(FQ->fqWriteOutputBoxes[v]) {
4961 pio.writeArray(&localBoxVar[(offset)*totalLocalSize], pathName.str(), FQ->fqNames[v], nDim, localBoxOffset,
4962 localBoxSize);
4963 offset++;
4964 }
4965 }
4966
4967 if(m_boxWriteCoordinates) {
4968 pio.writeArray(&localBoxVar[(offset + 0) * totalLocalSize], pathName.str(), "x", nDim, localBoxOffset,
4969 localBoxSize);
4970 pio.writeArray(&localBoxVar[(offset + 1) * totalLocalSize], pathName.str(), "y", nDim, localBoxOffset,
4971 localBoxSize);
4972 offset += nDim;
4973 }
4974
4975 } else { // write out nothing as box is not contained
4976 stringstream pathName;
4977 pathName << "/box" << b;
4978 for(MInt dim = 0; dim < nDim; ++dim) {
4979 localBoxSize[dim] = 0;
4980 localBoxOffset[dim] = 0;
4981 }
4982 MFloat empty = 0;
4983 for(MInt v = 0; v < m_maxNoVariables; ++v) {
4984 pio.writeArray(&empty, pathName.str(), m_pvariableNames[v], nDim, localBoxOffset, localBoxSize);
4985 }
4986 for(MInt v = 0; v < FQ->noFQVariables; ++v) {
4987 if(FQ->fqWriteOutputBoxes[v]) {
4988 pio.writeArray(&empty, pathName.str(), FQ->fqNames[v], nDim, localBoxOffset, localBoxSize);
4989 }
4990 }
4991
4992 if(m_boxWriteCoordinates) {
4993 pio.writeArray(&empty, pathName.str(), "x", nDim, localBoxOffset, localBoxSize);
4994 pio.writeArray(&empty, pathName.str(), "y", nDim, localBoxOffset, localBoxSize);
4995 }
4996 }
4997 }
4998}
4999
5000
5006template <MInt nDim>
5008 stringstream gridFileName;
5009 MString gridNameStr = "";
5010 if(m_movingGrid && m_movingGridSaveGrid) {
5011 gridFileName << "grid" << globalTimeStep << m_outputFormat;
5012 gridNameStr = gridFileName.str();
5013 } else {
5014 gridNameStr = "../" + m_grid->m_gridInputFileName;
5015 }
5016
5017 pio->setAttribute(gridNameStr, "gridFile", "");
5018 pio->setAttribute(m_grid->m_uID, "UID", "");
5019 pio->setAttribute(fileType, "filetype", "");
5020
5021 const MInt zonal = (MInt)m_zonal;
5022 pio->setAttribute(zonal, "zonal", "");
5023 pio->setAttribute(m_noBlocks, "noBlocks", "");
5024}
5025
5026
5032template <MInt nDim>
5034 pio->setAttribute(m_Ma, "Ma", path);
5035 pio->setAttribute(m_Re, "Re", path);
5036 pio->setAttribute(m_Pr, "Pr", path);
5037 pio->setAttribute(m_timeStep, "timeStep", path);
5038 pio->setAttribute(m_time, "time", path);
5039 pio->setAttribute(m_physicalTimeStep, "physicalTimeStep", path);
5040 pio->setAttribute(m_physicalTime, "physicalTime", path);
5041 pio->setAttribute(globalTimeStep, "globalTimeStep", path);
5042 pio->setAttribute(m_firstMaxResidual, "firstMaxResidual", path);
5043 pio->setAttribute(m_firstAvrgResidual, "firstAvrgResidual", path);
5044
5045 // save the time(Step) at which the grid motion started
5046 // does only work safely for constant time step
5047 if(m_movingGrid) {
5048 pio->setAttribute(m_movingGridStepOffset, "movingGridStepOffset", path);
5049 pio->setAttribute(m_movingGridTimeOffset, "movingGridTimeOffset", path);
5050 // save whether or not the wave time step has been computed
5051 if(m_travelingWave || m_streamwiseTravelingWave) {
5052 pio->setAttribute(m_waveTimeStepComputed, "waveTimeStepComputed", path);
5053 pio->setAttribute(m_waveNoStepsPerCell, "waveNoStepsPerCell", path);
5054 }
5055 }
5056
5057 if(m_stgIsActive) {
5058 pio->setAttribute(m_stgMaxNoEddies, "stgNRAN", path);
5059 }
5060
5061 if(m_volumeForceMethod != 0) {
5062 pio->setAttribute(m_volumeForce[0], "volumeForce", path);
5063 }
5064}
5065
5066
5072template <MInt nDim>
5073void FvStructuredSolver<nDim>::saveSolverSolution(MBool forceOutput, const MBool finalTimeStep) {
5074 RECORD_TIMER_START(m_timers[Timers::Run]);
5075 RECORD_TIMER_START(m_timers[Timers::SaveOutput]);
5076
5077 // run postprocessing in-solve routines
5078 this->postprocessInSolve();
5079
5080 // Function to write the solution to file with iolibrary
5081 MBool writeSolution = false;
5082 MBool writeBox = false;
5083 MBool writeNodalBox = false;
5084 MBool writeIntpPoints = false;
5085 MBool writeAux = false;
5086 MBool computeForces = false;
5087 MBool writeForces = false;
5088 MBool computeAsciiCells = false;
5089 MBool writeAsciiCells = false;
5090
5091 // first find out which writeOut-mode we use (iteration or convective unit intervals)
5092 // then check which functions should write out in this timestep
5093 if(m_useConvectiveUnitWrite) {
5094 // in this mode we check the convective unit intervals
5095 // and write out files of each type if activated
5096 // activation is done by setting the interval
5097 // to a value greater than 0 (boxOutputInterval = 1)
5098 if(m_physicalTime - (MFloat)(m_noConvectiveOutputs)*m_convectiveUnitInterval >= m_convectiveUnitInterval) {
5099 // restart file output is still triggered by iteration counter
5100 writeSolution = isInInterval(m_solutionInterval);
5101 forceOutput = writeSolution;
5102
5103 // activate the desired outputs
5104 writeSolution = m_sampleSolutionFiles;
5105 writeBox = (m_boxOutputInterval > 0);
5106 writeNodalBox = (m_nodalBoxOutputInterval > 0);
5107 writeIntpPoints = (m_intpPointsOutputInterval > 0);
5108 writeAux = (m_forceOutputInterval > 0);
5109 computeForces = (m_forceAsciiComputeInterval > 0);
5110
5111 m_noConvectiveOutputs++;
5112 m_outputIterationNumber = m_noConvectiveOutputs;
5113 }
5114 } else {
5115 // in this mode we check the iteration intervals
5116 // for each writeOut-type (solution, box, line, aux)
5117 writeSolution = isInInterval(m_solutionInterval);
5118 writeBox = isInInterval(m_boxOutputInterval);
5119 writeNodalBox = isInInterval(m_nodalBoxOutputInterval);
5120 writeIntpPoints = isInInterval(m_intpPointsOutputInterval);
5121 writeAux = isInInterval(m_forceOutputInterval);
5122 computeForces = isInInterval(m_forceAsciiComputeInterval);
5123 computeAsciiCells = isInInterval(m_pointsToAsciiComputeInterval);
5124 if(writeSolution || finalTimeStep) {
5125 writeForces = true;
5126 writeAsciiCells = true;
5127 }
5128
5129
5130 m_outputIterationNumber = globalTimeStep;
5131 }
5132
5133 // compute vorticity if necessary
5134 if(m_vorticityOutput && (writeSolution || writeBox || forceOutput)) {
5135 computeVorticity();
5136 }
5137
5138 // compute velocity if wanted
5139 if(m_computeLambda2 && (writeSolution || writeBox || forceOutput)) {
5140 computeLambda2Criterion();
5141 }
5142
5143 // boxes, auxdata and lines
5144 // are only available for 3D checked by function pointer
5145
5146 RECORD_TIMER_START(m_timers[Timers::SaveBoxes]);
5147 if(writeBox) {
5148 saveBoxes();
5149 }
5150 if(writeNodalBox) {
5151 saveNodalBoxes();
5152 }
5153 RECORD_TIMER_STOP(m_timers[Timers::SaveBoxes]);
5154
5155 RECORD_TIMER_START(m_timers[Timers::SaveAuxdata]);
5156 if(writeAux) {
5157 saveAuxData();
5158 }
5159 RECORD_TIMER_STOP(m_timers[Timers::SaveAuxdata]);
5160 RECORD_TIMER_START(m_timers[Timers::SaveForces]);
5161 if(computeForces) {
5162 saveForcesToAsciiFile(writeForces);
5163 }
5164
5165 if(computeAsciiCells) {
5166 savePointsToAsciiFile(writeAsciiCells);
5167 }
5168
5169 RECORD_TIMER_STOP(m_timers[Timers::SaveForces]);
5170 IF_CONSTEXPR(nDim > 2) { // needs also to be implemented for 2d !!!!!!!!!!!!!!
5171 RECORD_TIMER_START(m_timers[Timers::SaveIntpPoints]);
5172 if(writeIntpPoints) {
5173 saveInterpolatedPoints();
5174 }
5175 RECORD_TIMER_STOP(m_timers[Timers::SaveIntpPoints]);
5176 }
5177
5178 if(writeSolution || forceOutput || finalTimeStep) {
5179 RECORD_TIMER_START(m_timers[Timers::SaveSolution]);
5180 // save out the partitions also if desired, i.e, for debugging purposses
5181 if(m_savePartitionOutput) {
5182 savePartitions();
5183 }
5184 // save postprocessing variables if activated
5185 saveAverageRestart();
5186 // save solution/restart file
5187 saveSolution(forceOutput);
5188 m_lastOutputTimeStep = globalTimeStep;
5189 RECORD_TIMER_STOP(m_timers[Timers::SaveSolution]);
5190 }
5191 RECORD_TIMER_STOP(m_timers[Timers::SaveOutput]);
5192 RECORD_TIMER_STOP(m_timers[Timers::Run]);
5193}
5194
5195template <MInt nDim>
5197 if(interval > 0) {
5198 if((globalTimeStep - m_outputOffset) % interval == 0 && globalTimeStep - m_outputOffset >= 0) {
5199 return true;
5200 }
5201 }
5202 return false;
5203}
5204
5210template <MInt nDim>
5212 stringstream fileName;
5213 fileName << m_solutionOutput << m_outputIterationNumber << m_outputFormat;
5214
5215 if(m_movingGrid) {
5216 if(m_movingGridSaveGrid) {
5217 m_grid->writeGrid(m_solutionOutput, m_outputFormat);
5218 }
5219 }
5220
5221 m_log << "writing Solution file " << fileName.str() << " ... forceOutput: " << forceOutput << endl;
5222
5223 // Check if file exists
5224 MInt fileMode = -1;
5225 // if (FILE *file = fopen((fileName.str()).c_str(), "r")) { // file does exist
5226 // fclose(file);
5227 // fileMode = maia::parallel_io::PIO_APPEND;
5228 // } else { // file does not exist
5230 //}
5231
5232 ParallelIoHdf5 pio(fileName.str(), fileMode, m_StructuredComm);
5233
5234 writeHeaderAttributes(&pio, "solution");
5235 writePropertiesAsAttributes(&pio, "");
5236
5237 ParallelIo::size_type allCells[3] = {0, 0, 0};
5238 ParallelIo::size_type stgNoEddieFields = 1200;
5239 MString stgGlobalPathStr = "stgGlobal";
5240
5241 for(MInt i = 0; i < m_noBlocks; i++) {
5242 for(MInt j = 0; j < nDim; j++) {
5243 allCells[j] = m_grid->getBlockNoCells(i, j);
5244 }
5245 // create datasets for the io library
5246 stringstream path;
5247 path << i;
5248 MString blockPathStr = "block";
5249 blockPathStr += path.str();
5250 const char* blockPath = blockPathStr.c_str();
5251
5255 m_log << "writing primitive Output" << endl;
5256 for(MInt v = 0; v < m_maxNoVariables; v++) {
5257 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, m_pvariableNames[v], nDim, allCells);
5258 }
5259
5263 if(FQ->noFQVariables > 0) {
5264 for(MInt v = 0; v < FQ->noFQVariables; ++v) {
5265 if(FQ->fqWriteOutput[v]) {
5266 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, FQ->fqNames[v], nDim, allCells);
5267 }
5268 }
5269 }
5270
5274 if(m_bc2600IsActive) {
5275 ParallelIo::size_type allCells2600[3] = {allCells[0], allCells[1], allCells[2]};
5276 allCells2600[nDim - 1] = m_noGhostLayers;
5277 stringstream path2600Str;
5278 path2600Str << blockPath << "/bc2600";
5279 std::string path2600 = path2600Str.str();
5280
5281 for(MInt var = 0; var < m_maxNoVariables; var++) {
5282 pio.defineArray(maia::parallel_io::PIO_FLOAT, path2600, m_pvariableNames[var], nDim, allCells2600);
5283 }
5284 }
5285
5286 // ////////////////////////////////////////////////
5287 // ///////// Create BC2601 Information ////////////
5288 // ////////////////////////////////////////////////
5289 if(m_bc2601IsActive) {
5290 ParallelIo::size_type allCells2601[3] = {allCells[0], allCells[1], allCells[2]};
5291 allCells2601[nDim - 2] = m_noGhostLayers;
5292 stringstream path2601Str;
5293 path2601Str << blockPath << "/bc2601";
5294 std::string path2601 = path2601Str.str();
5295
5296 for(MInt var = 0; var < m_maxNoVariables; var++) {
5297 pio.defineArray(maia::parallel_io::PIO_FLOAT, path2601, m_pvariableNames[var], nDim, allCells2601);
5298 }
5299 }
5300
5304 if(m_stgIsActive) {
5305 ParallelIo::size_type allCells7909[3];
5306 allCells7909[0] = allCells[0];
5307 allCells7909[1] = allCells[1];
5308 allCells7909[2] = 3;
5309 for(MInt var = 0; var < m_stgNoVariables; var++) {
5310 stringstream stgPath;
5311 stgPath << blockPathStr << "/stg";
5312 stringstream fieldName;
5313 fieldName << "stgFQ" << var;
5314 pio.defineArray(maia::parallel_io::PIO_FLOAT, stgPath.str(), fieldName.str(), nDim, allCells7909);
5315 }
5316 }
5317 }
5318
5322 if(m_useSandpaperTrip) {
5323 stringstream tripPath;
5324 tripPath << "/trip";
5325 ParallelIo::size_type dataSize = m_tripNoTrips * 2 * m_tripNoModes;
5326
5327 pio.defineArray(maia::parallel_io::PIO_FLOAT, tripPath.str(), "tripModesG", 1, &dataSize);
5328 pio.defineArray(maia::parallel_io::PIO_FLOAT, tripPath.str(), "tripModesH1", 1, &dataSize);
5329 pio.defineArray(maia::parallel_io::PIO_FLOAT, tripPath.str(), "tripModesH2", 1, &dataSize);
5330 }
5331
5332 if(m_stgIsActive) {
5333 stgNoEddieFields = MInt(m_stgNoEddieProperties * m_stgMaxNoEddies);
5334 pio.defineArray(maia::parallel_io::PIO_FLOAT, stgGlobalPathStr, "FQeddies", 1, &stgNoEddieFields);
5335 }
5336
5340 stringstream path;
5341 path << m_blockId;
5342 MString blockPathStr = "block";
5343 blockPathStr += path.str();
5344 // write out the data
5345 ParallelIo::size_type ioOffset[3] = {0, 0, 0};
5346 ParallelIo::size_type ioSize[3] = {0, 0, 0};
5347 ParallelIo::size_type ioGhost[3] = {m_noGhostLayers, m_noGhostLayers, m_noGhostLayers};
5348 for(MInt dim = 0; dim < nDim; ++dim) {
5349 ioOffset[dim] = m_nOffsetCells[dim];
5350 ioSize[dim] = m_nActiveCells[dim];
5351 }
5352
5353 for(MInt v = 0; v < m_maxNoVariables; ++v) {
5354 pio.writeArray(&(m_cells->pvariables[v][0]), blockPathStr, m_pvariableNames[v], nDim, ioOffset, ioSize, ioGhost);
5355 }
5356
5360 if(FQ->noFQVariables > 0) {
5361 for(MInt v = 0; v < FQ->noFQVariables; ++v) {
5362 if(FQ->fqWriteOutput[v]) {
5363 pio.writeArray(&m_cells->fq[v][0], blockPathStr, FQ->fqNames[v], nDim, ioOffset, ioSize, ioGhost);
5364 }
5365 }
5366 }
5367
5368
5372 if(m_bc2600IsActive) {
5373 stringstream path2600Str;
5374 path2600Str << blockPathStr << "/bc2600";
5375 std::string path2600 = path2600Str.str();
5376
5377 ParallelIo::size_type ioSize2600[3] = {0, 0, 0};
5378 ParallelIo::size_type ioOffset2600[3] = {0, 0, 0};
5379 ParallelIo::size_type ioGhost2600[3] = {m_noGhostLayers, m_noGhostLayers, m_noGhostLayers};
5380 for(MInt dim = 0; dim < nDim; ++dim) {
5381 ioSize2600[dim] = m_bc2600noActiveCells[dim];
5382 ioOffset2600[dim] = m_bc2600noOffsetCells[dim];
5383 }
5384
5385 ioGhost2600[nDim - 1] = 0;
5386 if(m_bc2600) {
5387 for(MInt var = 0; var < m_maxNoVariables; var++) {
5388 pio.writeArray(&m_bc2600Variables[var][0], path2600, m_pvariableNames[var], nDim, ioOffset2600, ioSize2600,
5389 ioGhost2600);
5390 }
5391 } else {
5392 MFloat empty = 0;
5393 for(MInt var = 0; var < m_maxNoVariables; var++) {
5394 pio.writeArray(&empty, path2600, m_pvariableNames[var], nDim, ioOffset2600, ioSize2600, ioGhost2600);
5395 }
5396 }
5397 }
5398
5402 if(m_bc2601IsActive) {
5403 stringstream path2601Str;
5404 path2601Str << blockPathStr << "/bc2601";
5405 std::string path2601 = path2601Str.str();
5406
5407 ParallelIo::size_type ioSize2601[3] = {0, 0, 0};
5408 ParallelIo::size_type ioOffset2601[3] = {0, 0, 0};
5409 ParallelIo::size_type ioGhost2601[3] = {m_noGhostLayers, m_noGhostLayers, m_noGhostLayers};
5410 for(MInt dim = 0; dim < nDim; ++dim) {
5411 ioSize2601[dim] = m_bc2601noActiveCells[dim];
5412 ioOffset2601[dim] = m_bc2601noOffsetCells[dim];
5413 }
5414
5415 ioGhost2601[nDim - 2] = 0;
5416 if(m_bc2601) {
5417 for(MInt var = 0; var < m_maxNoVariables; var++) {
5418 pio.writeArray(&m_bc2601Variables[var][0], path2601, m_pvariableNames[var], nDim, ioOffset2601, ioSize2601,
5419 ioGhost2601);
5420 }
5421 } else {
5422 MFloat empty = 0;
5423 for(MInt var = 0; var < m_maxNoVariables; var++) {
5424 pio.writeArray(&empty, path2601, m_pvariableNames[var], nDim, ioOffset2601, ioSize2601, ioGhost2601);
5425 }
5426 }
5427 }
5428
5432 if(m_stgIsActive) {
5433 ParallelIo::size_type VBOffset = 0;
5434 if(m_stgRootRank) {
5435 pio.writeArray(&m_stgEddies[0][0], stgGlobalPathStr, "FQeddies", 1, &VBOffset, &stgNoEddieFields);
5436 } else {
5437 stgNoEddieFields = 0;
5438 MFloat empty = 0;
5439 pio.writeArray(&empty, stgGlobalPathStr, "FQeddies", 1, &VBOffset, &stgNoEddieFields);
5440 }
5441
5442 // if this domain has part of the STG bc write value, otherwise only write nullptr
5443 if(m_stgLocal) {
5444 MInt noActiveStgCells = (m_stgBoxSize[0] - 2 * m_noGhostLayers) * (m_stgBoxSize[1] - 2 * m_noGhostLayers) * 3;
5445 MFloatScratchSpace stgFqDummy(m_stgNoVariables, noActiveStgCells, AT_, "stgFqDummy");
5446
5447 for(MInt var = 0; var < m_stgNoVariables; var++) {
5448 for(MInt k = m_noGhostLayers; k < m_stgBoxSize[0] - m_noGhostLayers; k++) {
5449 for(MInt j = m_noGhostLayers; j < m_stgBoxSize[1] - m_noGhostLayers; j++) {
5450 for(MInt i = 0; i < m_stgBoxSize[2]; i++) {
5451 MInt cellIdBC = i + (j + k * m_stgBoxSize[1]) * 3;
5452 MInt cellIdDummy =
5453 i + ((j - m_noGhostLayers) + (k - m_noGhostLayers) * (m_stgBoxSize[1] - 2 * m_noGhostLayers)) * 3;
5454 stgFqDummy(var, cellIdDummy) = m_cells->stg_fq[var][cellIdBC];
5455 }
5456 }
5457 }
5458 }
5459
5460 ParallelIo::size_type bcOffset[3] = {m_nOffsetCells[0], m_nOffsetCells[1], 0};
5461 ParallelIo::size_type bcCells[3] = {m_stgBoxSize[0] - 2 * m_noGhostLayers, m_stgBoxSize[1] - 2 * m_noGhostLayers,
5462 m_stgBoxSize[2]};
5463
5464 for(MInt var = 0; var < m_stgNoVariables; var++) {
5465 stringstream fieldName;
5466 stringstream stgPath;
5467 stgPath << blockPathStr << "/stg";
5468 fieldName << "stgFQ" << var;
5469 pio.writeArray(&stgFqDummy(var, 0), stgPath.str(), fieldName.str(), nDim, bcOffset, bcCells);
5470 }
5471 } else {
5472 ParallelIo::size_type bcOffset[3] = {0, 0, 0};
5473 ParallelIo::size_type bcCells[3] = {0, 0, 0};
5474 MFloat empty = 0;
5475
5476 for(MInt var = 0; var < m_stgNoVariables; var++) {
5477 stringstream fieldName;
5478 stringstream stgPath;
5479 stgPath << blockPathStr << "/stg";
5480 fieldName << "stgFQ" << var;
5481 pio.writeArray(&empty, stgPath.str(), fieldName.str(), nDim, bcOffset, bcCells);
5482 }
5483 }
5484 }
5485
5489 if(m_useSandpaperTrip) {
5490 stringstream tripPath;
5491 tripPath << "trip";
5492
5493 if(domainId() == 0) {
5494 ParallelIo::size_type offset = 0;
5495 ParallelIo::size_type dataSize = m_tripNoTrips * m_tripNoModes * 2;
5496
5497 pio.writeArray(m_tripModesG, tripPath.str(), "tripModesG", 1, &offset, &dataSize);
5498 pio.writeArray(m_tripModesH1, tripPath.str(), "tripModesH1", 1, &offset, &dataSize);
5499 pio.writeArray(m_tripModesH2, tripPath.str(), "tripModesH2", 1, &offset, &dataSize);
5500 } else {
5501 ParallelIo::size_type offset = 0;
5502 ParallelIo::size_type dataSize = 0;
5503 MFloat empty = 0;
5504 pio.writeArray(&empty, tripPath.str(), "tripModesG", 1, &offset, &dataSize);
5505 pio.writeArray(&empty, tripPath.str(), "tripModesH1", 1, &offset, &dataSize);
5506 pio.writeArray(&empty, tripPath.str(), "tripModesH2", 1, &offset, &dataSize);
5507 }
5508 }
5509
5510 m_log << "...-> OK " << endl;
5511}
5512
5513
5520template <MInt nDim>
5522 // Function to write the solution to file with iolibrary
5523 stringstream fileName;
5524 ParallelIo::size_type noCells[3] = {0, 0, 0};
5525
5526 fileName << m_solutionOutput << "partitioned" << globalTimeStep << m_outputFormat;
5527 ParallelIoHdf5 pio(fileName.str(), maia::parallel_io::PIO_REPLACE, m_StructuredComm);
5528 writeHeaderAttributes(&pio, "solution");
5529 writePropertiesAsAttributes(&pio, "");
5530
5531 // save with ghostcells ==> multiple solvers;
5532 for(MInt i = 0; i < noDomains(); i++) {
5533 // create datasets for the io library
5534 for(MInt j = 0; j < nDim; j++) {
5535 noCells[j] = m_grid->getActivePoints(i, j) - 1 + 2 * m_noGhostLayers;
5536 }
5537 stringstream path;
5538 path << i;
5539 MString partitionPathStr = "block";
5540 partitionPathStr += path.str();
5541 const char* partitionPath = partitionPathStr.c_str();
5542 // create dataset for primitive/conservative variables
5543 for(MInt v = 0; v < m_maxNoVariables; v++) {
5544 pio.defineArray(maia::parallel_io::PIO_FLOAT, partitionPath, m_pvariableNames[v], nDim, noCells);
5545 }
5546 // create dataset for fq field variables
5547 for(MInt v = 0; v < FQ->noFQVariables; v++) {
5548 pio.defineArray(maia::parallel_io::PIO_FLOAT, partitionPath, FQ->fqNames[v], nDim, noCells);
5549 }
5550
5551 if(m_stgIsActive) {
5552 ParallelIo::size_type allCells7909[3];
5553 allCells7909[0] = m_grid->getActivePoints(i, 0) - 1 + 2 * m_noGhostLayers;
5554 allCells7909[1] = m_grid->getActivePoints(i, 1) - 1 + 2 * m_noGhostLayers;
5555 allCells7909[2] = 3;
5556
5557 for(MInt var = 0; var < m_stgNoVariables; var++) {
5558 stringstream fieldName;
5559 stringstream stgPath;
5560 stgPath << partitionPathStr << "/stg";
5561 fieldName << "stgFQ" << var;
5562 pio.defineArray(maia::parallel_io::PIO_FLOAT, stgPath.str(), fieldName.str(), nDim, allCells7909);
5563 }
5564 }
5565 }
5566
5567 // write the values into the array so that we can visualize it
5568 ParallelIo::size_type ioOffset[3] = {0, 0, 0};
5569 ParallelIo::size_type ioSize[3] = {m_nCells[0], m_nCells[1], m_nCells[2]};
5570 stringstream path;
5571 path << domainId();
5572 MString partitionPathStr = "block";
5573 partitionPathStr += path.str();
5574
5575 // write primitive variables
5576 for(MInt v = 0; v < m_maxNoVariables; ++v) {
5577 pio.writeArray(&m_cells->pvariables[v][0], partitionPathStr, m_pvariableNames[v], nDim, ioOffset, ioSize);
5578 }
5579
5580 for(MInt v = 0; v < FQ->noFQVariables; v++) {
5581 pio.writeArray(&m_cells->fq[v][0], partitionPathStr, FQ->fqNames[v], nDim, ioOffset, ioSize);
5582 }
5583
5587 if(m_stgIsActive) {
5588 ParallelIo::size_type bcOffset[3] = {0, 0, 0};
5589 ParallelIo::size_type bcCells[3] = {m_nCells[0], m_nCells[1], 3};
5590
5591 for(MInt var = 0; var < m_stgNoVariables; var++) {
5592 stringstream fieldName;
5593 stringstream stgPath;
5594 stgPath << partitionPathStr << "/stg";
5595 fieldName << "stgFQ" << var;
5596 pio.writeArray(&m_cells->stg_fq[var][0], stgPath.str(), fieldName.str(), nDim, bcOffset, bcCells);
5597 }
5598 }
5599}
5600
5605template <MInt nDim>
5607 TRACE();
5608
5609 if(!m_useNonSpecifiedRestartFile) {
5610 TERMM(1, "determineRestartTimeStep should only be used with useNonSpecifiedRestartFile enabled!");
5611 }
5612
5613 MString restartFile = Context::getSolverProperty<MString>("restartVariablesFileName", m_solverId, AT_);
5614 std::stringstream restartFileName;
5615 restartFileName << outputDir() << restartFile;
5616 ParallelIoHdf5 pio(restartFileName.str(), maia::parallel_io::PIO_READ, MPI_COMM_SELF);
5617 MInt timeStep = -1;
5618 pio.getAttribute(&timeStep, "globalTimeStep", "");
5619
5620 return timeStep;
5621}
5622
5629template <MInt nDim>
5631 TRACE();
5632 RECORD_TIMER_START(m_timers[Timers::LoadRestart]);
5633 m_log << "loading Restart file ... " << endl;
5634 stringstream restartFileName;
5635
5636 if(m_useNonSpecifiedRestartFile) {
5637 MString restartFile = "restart.hdf5";
5650 restartFile =
5651 Context::getSolverProperty<MString>("restartVariablesFileName", m_solverId, AT_); // this should be removed
5652 restartFileName << outputDir() << restartFile;
5653 } else {
5654 MString restartFile = "restart";
5668 MInt restartTimeStep = Context::getSolverProperty<MInt>("restartTimeStep", m_solverId, AT_);
5669
5670 restartFileName << outputDir() << restartFile << restartTimeStep << ".hdf5";
5671 }
5672
5673 MBool restartFromSA = false;
5674 restartFromSA = Context::getSolverProperty<MBool>("restartFromSA", m_solverId, AT_, &restartFromSA);
5675 if(restartFromSA && m_ransMethod != RANS_KEPSILON) mTerm(1, "Are you sick!");
5676
5677 ParallelIoHdf5 pio(restartFileName.str(), maia::parallel_io::PIO_READ, m_StructuredComm);
5678
5679 // check if restart and grid do fit together through UID
5680 if(!m_ignoreUID) {
5681 MString aUID = "";
5682 pio.getAttribute(&aUID, "UID", "");
5683
5684 if(aUID.compare(m_grid->m_uID) != 0) {
5685 mTerm(1, AT_, "FATAL: the files do not match each other according to the attribute UID");
5686 }
5687 }
5688 // check general attributes
5689 pio.getAttribute(&m_time, "time", "");
5690 pio.getAttribute(&m_physicalTime, "physicalTime", "");
5691 pio.getAttribute(&m_physicalTimeStep, "physicalTimeStep", "");
5692 pio.getAttribute(&m_firstMaxResidual, "firstMaxResidual", "");
5693 pio.getAttribute(&m_firstAvrgResidual, "firstAvrgResidual", "");
5694 pio.getAttribute(&m_timeStep, "timeStep", "");
5695 // check if primitive or conservative output is given
5696 MInt isPrimitiveOutput = 1;
5697 if(pio.hasAttribute("primitiveOutput", "")) {
5698 pio.getAttribute(&isPrimitiveOutput, "primitiveOutput", "");
5699 }
5700 // if moving Grid is actived read the moving grid time offset (if it exists)
5701 // otherwise assume this is an initial start and set the current restart time
5702 // as the moving grid time offset
5703 if(m_movingGrid || m_bodyForce) {
5704 if(pio.hasAttribute("movingGridStepOffset", "")) {
5705 pio.getAttribute(&m_movingGridTimeOffset, "movingGridTimeOffset", "");
5706 pio.getAttribute(&m_movingGridStepOffset, "movingGridStepOffset", "");
5707 m_movingGridInitialStart = false;
5708 } else {
5709 m_movingGridTimeOffset = m_time;
5710 m_movingGridStepOffset = globalTimeStep;
5711 m_movingGridInitialStart = true;
5712 }
5713 // check if the wave time step has already been computed
5714 if(pio.hasAttribute("waveTimeStepComputed", "")) {
5715 pio.getAttribute(&m_waveTimeStepComputed, "waveTimeStepComputed", "");
5716 } else {
5717 m_waveTimeStepComputed = false;
5718 }
5719
5720 if(pio.hasAttribute("waveNoStepsPerCell", "")) {
5721 pio.getAttribute(&m_waveNoStepsPerCell, "waveNoStepsPerCell", "");
5722 } else {
5723 m_waveNoStepsPerCell = 1;
5724 }
5725 }
5726
5727 // check for convective unit output
5728 if(m_useConvectiveUnitWrite) {
5729 m_noConvectiveOutputs = (MInt)(m_physicalTime / m_convectiveUnitInterval);
5730 m_log << "Convective unit output iteration counter: " << m_noConvectiveOutputs << endl;
5731 }
5732 // check for moving grid initial start
5733 if(m_movingGridInitialStart) {
5734 m_movingGridTimeOffset = m_time;
5735 }
5736 if(domainId() == 0) {
5737 cout << "Restarting at GlobalTimeStep " << globalTimeStep << endl;
5738 }
5739 m_restartTimeStep = globalTimeStep;
5740 // now read in the data!
5741 m_log << "-> reading in the data ... " << endl;
5742 m_log << "Loading restart variables..." << endl;
5743 if(domainId() == 0) {
5744 cout << "Loading restart variables..." << endl;
5745 }
5746 stringstream blockNumber;
5747 blockNumber << m_blockId;
5748 MString blockPathStr = "/block";
5749 blockPathStr += blockNumber.str();
5750 const char* blockPath = blockPathStr.c_str();
5751
5752 // Check if restart file has correct data for restart from SA
5753 if(restartFromSA) {
5754 vector<MString> variableNames = pio.getDatasetNames(blockPath);
5755
5756 MBool rans0 = false;
5757 for(MUint i = 0; i < variableNames.size(); ++i) {
5758 if(variableNames[i].find("rans1") != std::string::npos) {
5759 cout << variableNames[i] << endl;
5760 mTerm(1, "Restart file contains the variable rans1, but restartFromSA was set!!!");
5761 }
5762 if(variableNames[i].find("rans0") != std::string::npos) rans0 = true;
5763 }
5764 if(!rans0) mTerm(1, "Restart file does not contain variable 'rans0'!");
5765 }
5766
5767 // record tim to load restart file members
5768 RECORD_TIMER_START(m_timers[Timers::LoadVariables]);
5769 // check for primitive input or conservative input
5770 ParallelIo::size_type ioOffset[3] = {0, 0, 0};
5771 ParallelIo::size_type ioSize[3] = {0, 0, 0};
5772 for(MInt dim = 0; dim < nDim; ++dim) {
5773 ioOffset[dim] = m_nOffsetCells[dim];
5774 ioSize[dim] = m_nActiveCells[dim];
5775 }
5776
5777 if(isPrimitiveOutput) {
5778 for(MInt var = 0; var < m_maxNoVariables - restartFromSA; var++) {
5779 m_cells->pvariables[var][0] = -1.0;
5780 pio.readArray(m_cells->pvariables[var], blockPath, m_pvariableNames[var], nDim, ioOffset, ioSize);
5781 m_log << "Reading " << m_pvariableNames[var] << endl;
5782 }
5783 } else {
5784 for(MInt var = 0; var < CV->noVariables - restartFromSA; var++) {
5785 pio.readArray(m_cells->variables[var], blockPath, m_variableNames[var], nDim, ioOffset, ioSize);
5786 }
5787 }
5788 if(m_zonal) {
5789 pio.readArray(m_cells->fq[FQ->AVG_U], blockPath, FQ->fqNames[FQ->AVG_U], nDim, ioOffset, ioSize);
5790 pio.readArray(m_cells->fq[FQ->AVG_V], blockPath, FQ->fqNames[FQ->AVG_V], nDim, ioOffset, ioSize);
5791 pio.readArray(m_cells->fq[FQ->AVG_W], blockPath, FQ->fqNames[FQ->AVG_W], nDim, ioOffset, ioSize);
5792 pio.readArray(m_cells->fq[FQ->AVG_RHO], blockPath, FQ->fqNames[FQ->AVG_RHO], nDim, ioOffset, ioSize);
5793 pio.readArray(m_cells->fq[FQ->AVG_P], blockPath, FQ->fqNames[FQ->AVG_P], nDim, ioOffset, ioSize);
5794 pio.readArray(m_cells->fq[FQ->NU_T], blockPath, FQ->fqNames[FQ->NU_T], nDim, ioOffset, ioSize);
5795
5796 FQ->loadedFromRestartFile[FQ->AVG_U] = true;
5797 FQ->loadedFromRestartFile[FQ->AVG_V] = true;
5798 FQ->loadedFromRestartFile[FQ->AVG_W] = true;
5799 FQ->loadedFromRestartFile[FQ->AVG_RHO] = true;
5800 FQ->loadedFromRestartFile[FQ->AVG_P] = true;
5801 FQ->loadedFromRestartFile[FQ->NU_T] = true;
5802 }
5803
5804 RECORD_TIMER_STOP(m_timers[Timers::LoadVariables]);
5805 m_log << "Loading restart variables... SUCCESSFUL!" << endl;
5806 if(domainId() == 0) {
5807 cout << "Loading restart variables... SUCCESSFUL!" << endl;
5808 }
5809 m_log << "-> reading in auxilliary data for restart ..." << endl;
5810 m_log << "--> ... sponge ..." << endl;
5814
5815 RECORD_TIMER_START(m_timers[Timers::LoadSponge]);
5816 if(m_useSponge) {
5817 m_log << "--> ... sponge ..." << endl;
5818 if(domainId() == 0) {
5819 cout << "Loading sponge data..." << endl;
5820 }
5821 if(m_computeSpongeFactor == false) {
5822 pio.readArray(m_cells->fq[FQ->SPONGE_FACTOR], blockPath, FQ->fqNames[FQ->SPONGE_FACTOR], nDim, ioOffset, ioSize);
5823 FQ->loadedFromRestartFile[FQ->SPONGE_FACTOR] = true;
5824 }
5825 if(m_spongeLayerType == 2) {
5826 pio.readArray(m_cells->fq[FQ->SPONGE_RHO], blockPath, FQ->fqNames[FQ->SPONGE_RHO], nDim, ioOffset, ioSize);
5827 FQ->loadedFromRestartFile[FQ->SPONGE_RHO] = true;
5828 pio.readArray(m_cells->fq[FQ->SPONGE_RHO_E], blockPath, FQ->fqNames[FQ->SPONGE_RHO_E], nDim, ioOffset, ioSize);
5829 FQ->loadedFromRestartFile[FQ->SPONGE_RHO_E] = true;
5830 }
5831 if(m_spongeLayerType == 4) {
5832 pio.readArray(m_cells->fq[FQ->SPONGE_RHO], blockPath, FQ->fqNames[FQ->SPONGE_RHO], nDim, ioOffset, ioSize);
5833 FQ->loadedFromRestartFile[FQ->SPONGE_RHO] = true;
5834 }
5835 if(domainId() == 0) {
5836 cout << "Loading sponge data... SUCCESSFUL!" << endl;
5837 }
5838 m_log << "--> ... sponge ... SUCCESSFUL" << endl;
5839 }
5840 RECORD_TIMER_STOP(m_timers[Timers::LoadSponge]);
5841
5845 if(isPrimitiveOutput) {
5846 this->shiftCellValuesRestart(true);
5847 computeConservativeVariables();
5848 } else {
5849 this->shiftCellValuesRestart(false);
5850 computePrimitiveVariables();
5851 }
5852
5853 // fill the ghost-cells for the
5854 // averaged cells with exchange or
5855 // simple extrapolation
5856 if(m_zonal) {
5857 vector<MFloat*> zonalVars;
5858 zonalVars.push_back(m_cells->fq[FQ->AVG_U]);
5859 zonalVars.push_back(m_cells->fq[FQ->AVG_V]);
5860 zonalVars.push_back(m_cells->fq[FQ->AVG_W]);
5861 zonalVars.push_back(m_cells->fq[FQ->AVG_P]);
5862 zonalVars.push_back(m_cells->fq[FQ->AVG_RHO]);
5863 zonalVars.push_back(m_cells->fq[FQ->NU_T]);
5864 gcFillGhostCells(zonalVars);
5865 }
5866
5867 // load special variables
5868
5869 IF_CONSTEXPR(nDim == 3) { // only implemented for 3d or does not work in 2d.
5870 loadRestartBC2601();
5871 if(m_stgIsActive) {
5872 RECORD_TIMER_START(m_timers[Timers::LoadSTG]);
5873 loadRestartSTG(isPrimitiveOutput);
5874 RECORD_TIMER_STOP(m_timers[Timers::LoadSTG]);
5875 }
5876 }
5877
5881 if(m_changeMa) {
5882 MFloat oldMa = F0;
5883 pio.getAttribute(&oldMa, "Ma", "");
5884 convertRestartVariables(oldMa);
5885 // if we use the STG also convert the vars in the STG fields
5886 if(m_stgIsActive) {
5887 convertRestartVariablesSTG(oldMa);
5888 }
5889 }
5890
5894 if(m_volumeForceMethod != 0) {
5895 // if(pio.hasAttribute("volumeForce", "")) {
5896 pio.getAttribute(&m_volumeForce[0], "volumeForce", "");
5897 // }
5898 }
5899
5900 m_log << "-> reading in auxilliary data for restart ...SUCCESSFUL" << endl;
5901 m_log << "loading Restart file ... SUCCESSFUL " << endl;
5902
5903 loadRestartBC2600();
5904
5905 RECORD_TIMER_STOP(m_timers[Timers::LoadRestart]);
5906}
5907
5914template <>
5916 TRACE();
5917 for(MInt j = (m_nActiveCells[0] - 1); j >= 0; j--) {
5918 for(MInt i = (m_nActiveCells[1] - 1); i >= 0; i--) {
5919 const MInt cellId_org = i + j * m_nActiveCells[1];
5920 const MInt i_new = i + m_noGhostLayers;
5921 const MInt j_new = j + m_noGhostLayers;
5922 const MInt cellId = i_new + j_new * m_nCells[1];
5923 if(!isPrimitive) {
5924 for(MInt var = 0; var < CV->noVariables; var++) {
5925 m_cells->variables[var][cellId] = m_cells->variables[var][cellId_org];
5926 m_cells->variables[var][cellId_org] = F0;
5927 }
5928 } else {
5929 for(MInt var = 0; var < m_maxNoVariables; var++) {
5930 m_cells->pvariables[var][cellId] = m_cells->pvariables[var][cellId_org];
5931 m_cells->pvariables[var][cellId_org] = F0;
5932 }
5933 }
5934 // also shift values in the FQ field
5935 if(FQ->noFQVariables > 0) {
5936 for(MInt var = 0; var < FQ->noFQVariables; var++) {
5937 if(FQ->loadedFromRestartFile[var]) {
5938 m_cells->fq[var][cellId] = m_cells->fq[var][cellId_org];
5939 m_cells->fq[var][cellId_org] = F0;
5940 }
5941 }
5942 }
5943 }
5944 }
5945}
5946
5947template <>
5949 TRACE();
5950 // accounting for the ghost layers and shift the values to the right place
5951 for(MInt k = (m_nActiveCells[0] - 1); k >= 0; k--) {
5952 for(MInt j = (m_nActiveCells[1] - 1); j >= 0; j--) {
5953 for(MInt i = (m_nActiveCells[2] - 1); i >= 0; i--) {
5954 const MInt cellId_org = i + (j + k * m_nActiveCells[1]) * m_nActiveCells[2];
5955 const MInt i_new = i + m_noGhostLayers;
5956 const MInt j_new = j + m_noGhostLayers;
5957 const MInt k_new = k + m_noGhostLayers;
5958 const MInt cellId = i_new + (j_new + k_new * m_nCells[1]) * m_nCells[2];
5959 if(!isPrimitive) {
5960 for(MInt var = 0; var < CV->noVariables; var++) {
5961 m_cells->variables[var][cellId] = m_cells->variables[var][cellId_org];
5962 m_cells->variables[var][cellId_org] = F0;
5963 }
5964 } else {
5965 for(MInt var = 0; var < m_maxNoVariables; var++) {
5966 m_cells->pvariables[var][cellId] = m_cells->pvariables[var][cellId_org];
5967 m_cells->pvariables[var][cellId_org] = F0;
5968 }
5969 }
5970 // also shift values in the FQ field
5971 if(FQ->noFQVariables > 0) {
5972 for(MInt var = 0; var < FQ->noFQVariables; var++) {
5973 if(FQ->loadedFromRestartFile[var]) {
5974 m_cells->fq[var][cellId] = m_cells->fq[var][cellId_org];
5975 m_cells->fq[var][cellId_org] = F0;
5976 }
5977 }
5978 }
5979 }
5980 }
5981 }
5982}
5983
5991template <MInt nDim>
5992MBool FvStructuredSolver<nDim>::loadBoxFile(MString fileDir, MString filePrefix, MInt currentStep, MInt boxNr) {
5993 TRACE();
5994
5995 stringstream fileName;
5996 fileName << fileDir << "/" << filePrefix << currentStep << ".hdf5";
5997 if(FILE* file = fopen((fileName.str()).c_str(), "r")) {
5998 fclose(file);
5999 if(domainId() == 0) {
6000 cout << "Loading box file " << fileName.str() << endl;
6001 }
6002 } else {
6003 if(domainId() == 0) {
6004 cout << "Box file " << fileName.str() << " does not exist" << endl;
6005 }
6006 return false;
6007 }
6008
6009
6010 ParallelIoHdf5 pio(fileName.str(), maia::parallel_io::PIO_READ, m_StructuredComm);
6011 stringstream boxPath;
6012 boxPath << "t" << currentStep << "/box" << boxNr;
6013
6014 MInt boxOffset[3] = {0, 0, 0};
6015 pio.getAttribute(&boxOffset[0], "offsetk", boxPath.str());
6016 pio.getAttribute(&boxOffset[1], "offsetj", boxPath.str());
6017 pio.getAttribute(&boxOffset[2], "offseti", boxPath.str());
6018 MInt boxSize[3] = {0, 0, 0};
6019 pio.getAttribute(&boxSize[0], "sizek", boxPath.str());
6020 pio.getAttribute(&boxSize[1], "sizej", boxPath.str());
6021 pio.getAttribute(&boxSize[2], "sizei", boxPath.str());
6022
6023 ParallelIo::size_type localBoxSize[3] = {0, 0, 0};
6024 ParallelIo::size_type localBoxOffset[3] = {0, 0, 0};
6025 ParallelIo::size_type localDomainBoxOffset[3] = {0, 0, 0};
6026
6027 if(((m_nOffsetCells[2] <= boxOffset[2] && boxOffset[2] < m_nOffsetCells[2] + m_nActiveCells[2])
6028 || (boxOffset[2] <= m_nOffsetCells[2] && m_nOffsetCells[2] < boxOffset[2] + boxSize[2]))
6029 && ((m_nOffsetCells[1] <= boxOffset[1] && boxOffset[1] < m_nOffsetCells[1] + m_nActiveCells[1])
6030 || (boxOffset[1] <= m_nOffsetCells[1] && m_nOffsetCells[1] < boxOffset[1] + boxSize[1]))
6031 && ((m_nOffsetCells[0] <= boxOffset[0] && boxOffset[0] < m_nOffsetCells[0] + m_nActiveCells[0])
6032 || (boxOffset[0] <= m_nOffsetCells[0]
6033 && m_nOffsetCells[0] < boxOffset[0] + boxSize[0]))) { // the box is contained
6034
6035 // get the size of the box
6036 for(MInt dim = 0; dim < nDim; ++dim) {
6037 if(m_nOffsetCells[dim] <= boxOffset[dim]
6038 && boxOffset[dim] + boxSize[dim] < m_nOffsetCells[dim] + m_nActiveCells[dim]) {
6039 localBoxSize[dim] = boxSize[dim];
6040 localBoxOffset[dim] = 0;
6041 localDomainBoxOffset[dim] = boxOffset[dim] - m_nOffsetCells[dim];
6042 } else if(m_nOffsetCells[dim] <= boxOffset[dim]) {
6043 localBoxSize[dim] = (m_nOffsetCells[dim] + m_nActiveCells[dim]) - boxOffset[dim];
6044 localBoxOffset[dim] = 0;
6045 localDomainBoxOffset[dim] = boxOffset[dim] - m_nOffsetCells[dim];
6046 } else if(boxOffset[dim] <= m_nOffsetCells[dim]
6047 && m_nOffsetCells[dim] + m_nActiveCells[dim] < boxOffset[dim] + boxSize[dim]) {
6048 localBoxSize[dim] = m_nActiveCells[dim];
6049 localBoxOffset[dim] = m_nOffsetCells[dim] - boxOffset[dim];
6050 localDomainBoxOffset[dim] = 0;
6051 } else {
6052 localBoxSize[dim] = (boxOffset[dim] + boxSize[dim]) - m_nOffsetCells[dim];
6053 localBoxOffset[dim] = m_nOffsetCells[dim] - boxOffset[dim];
6054 localDomainBoxOffset[dim] = 0;
6055 }
6056 }
6057
6058 MInt totalLocalSize = 1;
6059 for(MInt dim = 0; dim < nDim; ++dim) {
6060 totalLocalSize *= localBoxSize[dim];
6061 }
6062
6063 MFloatScratchSpace localBoxVar(totalLocalSize, AT_, "local Box Variables");
6064 for(MInt var = 0; var < PV->noVariables; var++) {
6065 pio.readArray(&localBoxVar[0], boxPath.str(), m_pvariableNames[var], nDim, localBoxOffset, localBoxSize);
6066
6067 for(MInt k = m_noGhostLayers + localDomainBoxOffset[0];
6068 k < m_noGhostLayers + localDomainBoxOffset[0] + localBoxSize[0];
6069 ++k) {
6070 for(MInt j = m_noGhostLayers + localDomainBoxOffset[1];
6071 j < m_noGhostLayers + localDomainBoxOffset[1] + localBoxSize[1];
6072 ++j) {
6073 for(MInt i = m_noGhostLayers + localDomainBoxOffset[2];
6074 i < m_noGhostLayers + localDomainBoxOffset[2] + localBoxSize[2];
6075 ++i) {
6076 const MInt cellId = i + (j + k * m_nCells[1]) * m_nCells[2];
6077 const MInt boxI = i - m_noGhostLayers - localDomainBoxOffset[2];
6078 const MInt boxJ = j - m_noGhostLayers - localDomainBoxOffset[1];
6079 const MInt boxK = k - m_noGhostLayers - localDomainBoxOffset[0];
6080 const MInt localId = boxI + (boxJ + boxK * localBoxSize[1]) * localBoxSize[2];
6081 m_cells->pvariables[var][cellId] = localBoxVar[localId];
6082 }
6083 }
6084 }
6085 }
6086 } else {
6087 for(MInt var = 0; var < PV->noVariables; var++) {
6088 ParallelIo::size_type offset[3] = {0, 0, 0};
6089 ParallelIo::size_type size[3] = {0, 0, 0};
6090 MFloat empty = 0;
6091 pio.readArray(&empty, boxPath.str(), m_pvariableNames[var], nDim, offset, size);
6092 }
6093 }
6094
6095
6096 if(domainId() == 0) {
6097 cout << "Done loading box file " << currentStep << endl;
6098 }
6099
6100 return true;
6101}
6102
6103
6104template <MInt nDim>
6106 computeAuxData();
6107 stringstream fileName;
6108 MChar gridFile[25];
6109 MString tempG;
6110
6111 fileName << m_auxOutputDir << "auxData" << m_outputIterationNumber << m_outputFormat;
6112
6113 strcpy(gridFile, tempG.c_str());
6114 ParallelIoHdf5 pio(fileName.str(), maia::parallel_io::PIO_REPLACE, m_StructuredComm);
6115 writeHeaderAttributes(&pio, "auxdata");
6116 writePropertiesAsAttributes(&pio, "");
6117 const MString powerNamesVisc[3] = {"Pxv", "Pyv", "Pzv"};
6118 const MString powerNamesPres[3] = {"Pxp", "Pyp", "Pzp"};
6119
6120 const MString dataNames3D[] = {"cfx", "cfy", "cfz", "ax", "ay", "az", "x", "y", "z"};
6121 MString dataNames[3 * nDim];
6122 MInt cnt = 0;
6123 for(MInt i = 0; i < 3; ++i) {
6124 for(MInt dim = 0; dim < nDim; ++dim)
6125 dataNames[cnt++] = dataNames3D[i * 3 + dim];
6126 }
6127 MInt noFields = nDim;
6128 if(m_detailAuxData) {
6129 noFields = 3 * nDim;
6130 }
6131
6132 for(auto it = m_windowInfo->m_auxDataWindowIds.cbegin(); it != m_windowInfo->m_auxDataWindowIds.cend(); ++it) {
6133 const MInt i = it->first;
6134 ParallelIo::size_type datasetSize[nDim - 1];
6135 MInt dim1 = nDim - 2;
6136 for(MInt dim = 0; dim < nDim; ++dim) {
6137 if(m_windowInfo->globalStructuredBndryCndMaps[i]->end2[dim]
6138 == m_windowInfo->globalStructuredBndryCndMaps[i]->start2[dim]) {
6139 continue;
6140 }
6141 datasetSize[dim1--] = m_windowInfo->globalStructuredBndryCndMaps[i]->end2[dim]
6142 - m_windowInfo->globalStructuredBndryCndMaps[i]->start2[dim];
6143 }
6144
6145 if(m_bForce) {
6146 stringstream datasetId;
6147 datasetId << it->second; //==m_windowInfo->globalStructuredBndryCndMaps[i]->Id2;
6148 MString pathName = "window";
6149 pathName += datasetId.str();
6150 MString dataNamesCp = "cp";
6151 for(MInt j = 0; j < noFields; j++) {
6152 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName, dataNames[j], nDim - 1, datasetSize);
6153 }
6154 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName, dataNamesCp, nDim - 1, datasetSize);
6155 }
6156
6157 if(m_bPower) {
6158 stringstream datasetId;
6159 datasetId << it->second; //==m_windowInfo->globalStructuredBndryCndMaps[i]->Id2;
6160 MString pathName = "window";
6161 pathName += datasetId.str();
6162 for(MInt j = 0; j < nDim; j++) {
6163 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName, powerNamesVisc[j], nDim - 1, datasetSize);
6164 pio.defineArray(maia::parallel_io::PIO_FLOAT, pathName, powerNamesPres[j], nDim - 1, datasetSize);
6165 }
6166 }
6167 }
6168
6169 for(auto it = m_windowInfo->m_auxDataWindowIds.cbegin(); it != m_windowInfo->m_auxDataWindowIds.cend(); ++it) {
6170 stringstream datasetname;
6171 datasetname << it->second; //==m_windowInfo->globalStructuredBndryCndMaps[i]->Id2;
6172
6173 MBool isLocalAuxMap = false;
6174 MInt localAuxMapId = 0;
6175 const MUint noAuxDataMaps = m_windowInfo->physicalAuxDataMap.size();
6176
6177 // loop through all local auxDataMaps
6178 // to find if this partition shares a part of it
6179 // and then save the local id
6180 for(MUint j = 0; j < noAuxDataMaps; ++j) {
6181 stringstream datasetId;
6182 datasetId << m_windowInfo->physicalAuxDataMap[j]->Id2;
6183 if(datasetId.str() == datasetname.str()) {
6184 isLocalAuxMap = true;
6185 localAuxMapId = j;
6186 break;
6187 }
6188 }
6189
6190 if(isLocalAuxMap) {
6191 stringstream datasetId;
6192 datasetId << m_windowInfo->physicalAuxDataMap[localAuxMapId]->Id2;
6193
6194 ParallelIo::size_type offset[nDim - 1] = {};
6195 ParallelIo::size_type dataSize[nDim - 1] = {};
6196 MInt dataSetSize = 1;
6197 MInt dim1 = nDim - 2;
6198 for(MInt j = 0; j < nDim; ++j) {
6199 if(m_windowInfo->physicalAuxDataMap[localAuxMapId]->start2[j]
6200 == m_windowInfo->physicalAuxDataMap[localAuxMapId]->end2[j])
6201 continue;
6202 dataSize[dim1] = m_windowInfo->physicalAuxDataMap[localAuxMapId]->end2[j]
6203 - m_windowInfo->physicalAuxDataMap[localAuxMapId]->start2[j];
6204 offset[dim1] = m_windowInfo->physicalAuxDataMap[localAuxMapId]->start2[j];
6205 dataSetSize *= dataSize[dim1];
6206 dim1--;
6207 }
6208
6209 if(m_bForce) {
6210 const MInt mapOffset = m_cells->cfOffsets[localAuxMapId];
6211 MString pathName = "window" + datasetId.str();
6212 for(MInt j = 0; j < noFields; j++) {
6213 pio.writeArray(&m_cells->cf[mapOffset + dataSetSize * j], pathName, dataNames[j], nDim - 1, offset, dataSize);
6214 }
6215 const MInt mapOffsetCp = m_cells->cpOffsets[localAuxMapId];
6216 MString dataname = "cp";
6217 pio.writeArray(&m_cells->cp[mapOffsetCp], pathName, dataname, nDim - 1, offset, dataSize);
6218 }
6219
6220 if(m_bPower) {
6221 const MInt mapOffset = m_cells->powerOffsets[localAuxMapId];
6222 MString pathName = "window" + datasetId.str();
6223 for(MInt j = 0; j < nDim; j++) {
6224 pio.writeArray(&m_cells->powerVisc[mapOffset + dataSetSize * j], pathName, powerNamesVisc[j], nDim - 1,
6225 offset, dataSize);
6226 pio.writeArray(&m_cells->powerPres[mapOffset + dataSetSize * j], pathName, powerNamesPres[j], nDim - 1,
6227 offset, dataSize);
6228 }
6229 }
6230 } else {
6231 ParallelIo::size_type offset[nDim] = {};
6232 ParallelIo::size_type dataSize[nDim] = {};
6233 for(MInt j = 0; j < nDim - 1; ++j) {
6234 offset[j] = 0;
6235 dataSize[j] = 0;
6236 }
6237 // skin-friction and pressure coefficient
6238 if(m_bForce) {
6239 MString pathName = "window" + datasetname.str();
6240 MFloat empty = 0;
6241 for(MInt j = 0; j < noFields; j++) {
6242 pio.writeArray(&empty, pathName, dataNames[j], nDim - 1, offset, dataSize);
6243 }
6244 MString dataname = "cp";
6245 pio.writeArray(&empty, pathName, dataname, nDim - 1, offset, dataSize);
6246 }
6247 // power
6248 if(m_bPower) {
6249 MString pathName = "window" + datasetname.str();
6250 MFloat empty = 0;
6251 for(MInt j = 0; j < nDim; j++) {
6252 pio.writeArray(&empty, pathName, powerNamesVisc[j], nDim - 1, offset, dataSize);
6253 pio.writeArray(&empty, pathName, powerNamesPres[j], nDim - 1, offset, dataSize);
6254 }
6255 }
6256 }
6257 }
6258
6259 if(m_bForce) {
6260 saveForceCoefficient(&pio);
6261 }
6262}
6263
6264
6272template <MInt nDim>
6274 TRACE();
6275
6276 MInt noWalls = m_windowInfo->m_auxDataWindowIds.size();
6277 MFloatScratchSpace force(noWalls, nDim, AT_, "force");
6278 MFloatScratchSpace forceP(noWalls, nDim, AT_, "forceP");
6279 MFloatScratchSpace forceC(noWalls, nDim, AT_, "forceC");
6280 MFloatScratchSpace forceV(noWalls, nDim, AT_, "forceV");
6281 MFloatScratchSpace area(noWalls, nDim, AT_, "area");
6282 MFloatScratchSpace power(noWalls, nDim, AT_, "Ptot");
6283 MFloatScratchSpace powerV(noWalls, nDim, AT_, "Pvisc");
6284 MFloatScratchSpace powerP(noWalls, nDim, AT_, "Ppres");
6285
6286 for(MInt i = 0; i < noWalls; ++i) {
6287 for(MInt dim = 0; dim < nDim; dim++) {
6288 forceV(i, dim) = m_forceCoef[i * m_noForceDataFields + dim];
6289 forceC(i, dim) = m_forceCoef[i * m_noForceDataFields + nDim + dim];
6290 forceP(i, dim) = m_forceCoef[i * m_noForceDataFields + 2 * nDim + dim];
6291 force(i, dim) = forceV(i, dim) + forceC(i, dim) + forceP(i, dim);
6292 powerV(i, dim) = m_forceCoef[i * m_noForceDataFields + 3 * nDim + 1 + dim];
6293 powerP(i, dim) = m_forceCoef[i * m_noForceDataFields + 4 * nDim + 1 + dim];
6294 power(i, dim) = powerV(i, dim) + powerP(i, dim);
6295 }
6296 area[i] = m_forceCoef[i * m_noForceDataFields + 3 * nDim];
6297 }
6298
6299 MInt count = 0;
6300 for(auto it = m_windowInfo->m_auxDataWindowIds.cbegin(); it != m_windowInfo->m_auxDataWindowIds.cend(); ++it) {
6301 stringstream datasetname;
6302 datasetname << it->second; //==m_windowInfo->globalStructuredBndryCndMaps[it->first]->Id2;
6303 MString pathName = "window" + datasetname.str();
6304
6305 pio->setAttribute(force(count, 0), "forceX", pathName);
6306 pio->setAttribute(forceV(count, 0), "forceVX", pathName);
6307 pio->setAttribute(forceP(count, 0), "forcePX", pathName);
6308 pio->setAttribute(forceC(count, 0), "forceCX", pathName);
6309
6310 pio->setAttribute(force(count, 1), "forceY", pathName);
6311 pio->setAttribute(forceV(count, 1), "forceVY", pathName);
6312 pio->setAttribute(forceP(count, 1), "forcePY", pathName);
6313 pio->setAttribute(forceC(count, 1), "forceCY", pathName);
6314
6315 IF_CONSTEXPR(nDim == 3) {
6316 pio->setAttribute(force(count, 2), "forceZ", pathName);
6317 pio->setAttribute(forceV(count, 2), "forceVZ", pathName);
6318 pio->setAttribute(forceP(count, 2), "forcePZ", pathName);
6319 pio->setAttribute(forceC(count, 2), "forceCZ", pathName);
6320 }
6321
6322 pio->setAttribute(area[count], "area", pathName);
6323
6324 if(m_bPower) {
6325 pio->setAttribute(power(count, 0), "powerX", pathName);
6326 pio->setAttribute(power(count, 1), "powerY", pathName);
6327 pio->setAttribute(power(count, 2), "powerZ", pathName);
6328
6329 pio->setAttribute(powerP(count, 0), "powerPX", pathName);
6330 pio->setAttribute(powerP(count, 1), "powerPY", pathName);
6331 pio->setAttribute(powerP(count, 2), "powerPZ", pathName);
6332
6333 pio->setAttribute(powerV(count, 0), "powerVX", pathName);
6334 pio->setAttribute(powerV(count, 1), "powerVY", pathName);
6335 pio->setAttribute(powerV(count, 2), "powerVZ", pathName);
6336 }
6337
6338 count++;
6339 }
6340}
6341
6342
6349template <MInt nDim>
6351 TRACE();
6352 // compute the data
6353 if(m_bForce) {
6354 computeAuxDataRoot();
6355
6356 // write all the data to files if domainId()==0
6357 if(domainId() == 0) {
6358 MInt noWalls = m_windowInfo->m_auxDataWindowIds.size();
6359
6360 MFloatScratchSpace cForce(noWalls, nDim, AT_, "cForce");
6361 MFloatScratchSpace cForceP(noWalls, nDim, AT_, "cForceP");
6362 MFloatScratchSpace cForceC(noWalls, nDim, AT_, "cForceC");
6363 MFloatScratchSpace cForceV(noWalls, nDim, AT_, "cForceV");
6364 MFloatScratchSpace area(noWalls, AT_, "area");
6365 // power consumption
6366 MFloatScratchSpace cPower(noWalls, nDim, AT_, "cPower");
6367 MFloatScratchSpace cPowerV(noWalls, nDim, AT_, "cPower");
6368 MFloatScratchSpace cPowerP(noWalls, nDim, AT_, "cPower");
6369
6370 for(MInt i = 0; i < noWalls; ++i) {
6371 for(MInt dim = 0; dim < nDim; dim++) {
6372 cForceV(i, dim) = m_forceCoef[i * m_noForceDataFields + dim];
6373 cForceC(i, dim) = m_forceCoef[i * m_noForceDataFields + nDim + dim];
6374 cForceP(i, dim) = m_forceCoef[i * m_noForceDataFields + 2 * nDim + dim];
6375 cForce(i, dim) = cForceV(i, dim) + cForceP(i, dim) + cForceC(i, dim);
6376 cPowerV(i, dim) = m_forceCoef[i * m_noForceDataFields + 3 * nDim + 1 + dim];
6377 cPowerP(i, dim) = m_forceCoef[i * m_noForceDataFields + 4 * nDim + 1 + dim];
6378 cPower(i, dim) = cPowerV(i, dim) + cPowerP(i, dim);
6379 }
6380 area[i] = m_forceCoef[i * m_noForceDataFields + 3 * nDim];
6381 }
6382
6383 if(m_lastForceComputationTimeStep != globalTimeStep) {
6384 for(MInt i = 0; i < noWalls; ++i) {
6385 MInt cnt = 0;
6386 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = globalTimeStep;
6387 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = m_time;
6388 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = m_physicalTime;
6389 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForce(i, 0);
6390 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceV(i, 0);
6391 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceP(i, 0);
6392 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceC(i, 0);
6393 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForce(i, 1);
6394 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceV(i, 1);
6395 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceP(i, 1);
6396 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceC(i, 1);
6397 IF_CONSTEXPR(nDim == 3) {
6398 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForce(i, 2);
6399 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceV(i, 2);
6400 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceP(i, 2);
6401 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cForceC(i, 2);
6402 }
6403 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = area[i];
6404
6405 if(m_bPower) {
6406 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPower(i, 0);
6407 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPowerV(i, 0);
6408 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPowerP(i, 0);
6409 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPower(i, 1);
6410 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPowerV(i, 1);
6411 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPowerP(i, 1);
6412 IF_CONSTEXPR(nDim == 3) {
6413 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPower(i, 2);
6414 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPowerV(i, 2);
6415 m_forceData[m_forceCounter][i * m_noForceDataFields + cnt++] = cPowerP(i, 2);
6416 }
6417 }
6418 }
6419 m_forceCounter++;
6420 m_lastForceComputationTimeStep = globalTimeStep;
6421 }
6422
6423 if((m_forceCounter >= m_forceAsciiOutputInterval || forceWrite) && m_lastForceOutputTimeStep != globalTimeStep) {
6424 cout << "globalTimeStep: " << globalTimeStep << " writing out to ascii file" << endl;
6425 // TODO_SS labels:FV why not looping over the elements of m_windowInfo->m_auxDataWindowIds and choosing windowId
6426 // for iWall
6427 for(MInt i = 0; i < noWalls; ++i) {
6428 stringstream iWall;
6429 iWall << i;
6430 MString filename = "./forces." + iWall.str() + ".dat";
6431
6432 FILE* f_forces;
6433 f_forces = fopen(filename.c_str(), "a+");
6434
6435 for(MInt j = 0; j < m_forceCounter; j++) {
6436 fprintf(f_forces, "%d ", (MInt)m_forceData[j][i * m_noForceDataFields + 0]);
6437 for(MInt k = 1; k < m_noForceDataFields; k++) {
6438 fprintf(f_forces, " %.8f ", m_forceData[j][i * m_noForceDataFields + k]);
6439 }
6440 fprintf(f_forces, "\n");
6441 }
6442 fclose(f_forces);
6443 }
6444
6445 m_forceCounter = 0;
6446 m_lastForceOutputTimeStep = globalTimeStep;
6447 }
6448 }
6449 }
6450}
6451
6452
6459template <MInt nDim>
6461 // Function to write the solution to file with iolibrary
6462 stringstream fileName;
6463
6464 m_log << "writing Averaged Variables to file " << name << m_outputFormat << " ... " << endl;
6465 fileName << name << m_outputFormat;
6466
6467 ParallelIoHdf5 pio(fileName.str(), maia::parallel_io::PIO_REPLACE, m_StructuredComm);
6468
6469 writeHeaderAttributes(&pio, "solution");
6470 writePropertiesAsAttributes(&pio, "");
6471
6472 pio.setAttribute(m_averageStartTimestep, "averageStartTimeStep", "");
6473 pio.setAttribute(m_averageInterval, "averageSampleInterval", "");
6474 pio.setAttribute(m_noSamples, "noSamples", "");
6475
6476 for(MInt i = 0; i < m_noBlocks; i++) {
6477 ParallelIo::size_type noCells[nDim] = {};
6478 for(MInt j = 0; j < nDim; j++) {
6479 noCells[j] = m_grid->getBlockNoCells(i, j);
6480 }
6481 // create datasets for the io library
6482 stringstream path;
6483 path << i;
6484 MString blockPathStr = "block";
6485 blockPathStr += path.str();
6486
6487 // create dataset and write
6488 for(MInt var = 0; var < noVars; var++) {
6489 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, m_avgVariableNames[var], nDim, noCells);
6490 }
6491
6492 if(m_averagingFavre) {
6493 for(MInt var = 0; var < PV->noVariables; var++) {
6494 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, m_avgFavreNames[var], nDim, noCells);
6495 }
6496 }
6497 }
6498
6499 ParallelIo::size_type ioOffset[3] = {0, 0, 0};
6500 ParallelIo::size_type ioSize[3] = {0, 0, 0};
6501 ParallelIo::size_type ioGhost[3] = {m_noGhostLayers, m_noGhostLayers, m_noGhostLayers};
6502 for(MInt dim = 0; dim < nDim; ++dim) {
6503 ioOffset[dim] = m_nOffsetCells[dim];
6504 ioSize[dim] = m_nActiveCells[dim];
6505 }
6506
6507 stringstream path;
6508 path << m_blockId;
6509 MString blockPathStr = "block";
6510 blockPathStr += path.str();
6511 for(MInt var = 0; var < noVars; var++) {
6512 pio.writeArray(&summedVars[var][0], blockPathStr, m_avgVariableNames[var], nDim, ioOffset, ioSize, ioGhost);
6513 }
6514
6515 if(m_averagingFavre) {
6516 for(MInt var = 0; var < PV->noVariables; var++) {
6517 pio.writeArray(&m_favre[var][0], blockPathStr, m_avgFavreNames[var], nDim, ioOffset, ioSize, ioGhost);
6518 }
6519 }
6520}
6521
6527template <MInt nDim>
6529 MFloat** cube, MFloat** fourth) {
6530 (void)noVars;
6531
6532 // Function to write the solution to file with iolibrary
6533 stringstream fileName;
6534
6535 m_log << "writing Averaged Restart Variables to file " << name << m_outputFormat << " ... " << endl;
6536 fileName << name << m_outputFormat;
6537
6538 ParallelIoHdf5 pio(fileName.str(), maia::parallel_io::PIO_REPLACE, m_StructuredComm);
6539
6540 writeHeaderAttributes(&pio, "solution");
6541 writePropertiesAsAttributes(&pio, "");
6542
6543 pio.setAttribute(m_averageStartTimestep, "averageStartTimeStep", "");
6544 pio.setAttribute(m_averageInterval, "averageSampleInterval", "");
6545 pio.setAttribute(m_noSamples, "noSamples", "");
6546
6547 ParallelIo::size_type allCells[3]; // not nDim because of compiler warning0
6548 for(MInt i = 0; i < m_noBlocks; i++) {
6549 for(MInt j = 0; j < nDim; j++) {
6550 allCells[j] = m_grid->getBlockNoCells(i, j);
6551 }
6552 // create datasets for the io library
6553 stringstream path;
6554 path << i; // m_blockId;
6555 MString blockPathStr = "block";
6556 blockPathStr += path.str();
6557
6558 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "u", 3, allCells);
6559 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "v", 3, allCells);
6560 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "w", 3, allCells);
6561 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "rho", 3, allCells);
6562 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "p", 3, allCells);
6563
6564 if(m_averagingFavre) {
6565 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "um_favre", 3, allCells);
6566 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vm_favre", 3, allCells);
6567 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "wm_favre", 3, allCells);
6568 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "rhom_favre", 3, allCells);
6569 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "pm_favre", 3, allCells);
6570 }
6571
6572 if(m_averageVorticity) {
6573 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vortx", 3, allCells);
6574 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vorty", 3, allCells);
6575 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vortz", 3, allCells);
6576 }
6577
6578 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "uu", 3, allCells);
6579 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vv", 3, allCells);
6580 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "ww", 3, allCells);
6581 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "uv", 3, allCells);
6582 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vw", 3, allCells);
6583 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "uw", 3, allCells);
6584 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "pp", 3, allCells);
6585
6586 if(m_averageVorticity) {
6587 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vortxvortx", 3, allCells);
6588 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vortyvorty", 3, allCells);
6589 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vortzvortz", 3, allCells);
6590 }
6591
6592 if(m_kurtosis || m_skewness) {
6593 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "uuu", 3, allCells);
6594 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vvv", 3, allCells);
6595 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "www", 3, allCells);
6596 }
6597
6598 if(m_kurtosis) {
6599 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "uuuu", 3, allCells);
6600 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "vvvv", 3, allCells);
6601 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "wwww", 3, allCells);
6602 }
6603 }
6604
6608 ParallelIo::size_type ioOffset[3] = {0, 0, 0};
6609 ParallelIo::size_type ioSize[3] = {0, 0, 0};
6610 ParallelIo::size_type ioGhost[3] = {m_noGhostLayers, m_noGhostLayers, m_noGhostLayers};
6611 for(MInt dim = 0; dim < nDim; ++dim) {
6612 ioOffset[dim] = m_nOffsetCells[dim];
6613 ioSize[dim] = m_nActiveCells[dim];
6614 }
6615
6616 stringstream path;
6617 path << m_blockId;
6618 MString blockPathStr = "block";
6619 blockPathStr += path.str();
6620 MInt offset = 0;
6621 pio.writeArray(&summedVars[0][0], blockPathStr, "u", nDim, ioOffset, ioSize, ioGhost);
6622 pio.writeArray(&summedVars[1][0], blockPathStr, "v", nDim, ioOffset, ioSize, ioGhost);
6623 pio.writeArray(&summedVars[2][0], blockPathStr, "w", nDim, ioOffset, ioSize, ioGhost);
6624 pio.writeArray(&summedVars[3][0], blockPathStr, "rho", nDim, ioOffset, ioSize, ioGhost);
6625 pio.writeArray(&summedVars[4][0], blockPathStr, "p", nDim, ioOffset, ioSize, ioGhost);
6626 offset = noVariables();
6627
6628 if(m_averagingFavre) {
6629 pio.writeArray(&m_favre[0][0], blockPathStr, "um_favre", nDim, ioOffset, ioSize, ioGhost);
6630 pio.writeArray(&m_favre[1][0], blockPathStr, "vm_favre", nDim, ioOffset, ioSize, ioGhost);
6631 pio.writeArray(&m_favre[2][0], blockPathStr, "wm_favre", nDim, ioOffset, ioSize, ioGhost);
6632 pio.writeArray(&m_favre[3][0], blockPathStr, "rhom_favre", nDim, ioOffset, ioSize, ioGhost);
6633 pio.writeArray(&m_favre[4][0], blockPathStr, "pm_favre", nDim, ioOffset, ioSize, ioGhost);
6634 }
6635
6636 if(m_averageVorticity) {
6637 pio.writeArray(&summedVars[offset + 0][0], blockPathStr, "vortx", nDim, ioOffset, ioSize, ioGhost);
6638 pio.writeArray(&summedVars[offset + 1][0], blockPathStr, "vorty", nDim, ioOffset, ioSize, ioGhost);
6639 pio.writeArray(&summedVars[offset + 2][0], blockPathStr, "vortz", nDim, ioOffset, ioSize, ioGhost);
6640 }
6641
6642 pio.writeArray(&square[0][0], blockPathStr, "uu", nDim, ioOffset, ioSize, ioGhost);
6643 pio.writeArray(&square[1][0], blockPathStr, "vv", nDim, ioOffset, ioSize, ioGhost);
6644 pio.writeArray(&square[2][0], blockPathStr, "ww", nDim, ioOffset, ioSize, ioGhost);
6645 pio.writeArray(&square[3][0], blockPathStr, "uv", nDim, ioOffset, ioSize, ioGhost);
6646 pio.writeArray(&square[4][0], blockPathStr, "vw", nDim, ioOffset, ioSize, ioGhost);
6647 pio.writeArray(&square[5][0], blockPathStr, "uw", nDim, ioOffset, ioSize, ioGhost);
6648 pio.writeArray(&square[6][0], blockPathStr, "pp", nDim, ioOffset, ioSize, ioGhost);
6649
6650 if(m_averageVorticity) {
6651 pio.writeArray(&square[7][0], blockPathStr, "vortxvortx", nDim, ioOffset, ioSize, ioGhost);
6652 pio.writeArray(&square[8][0], blockPathStr, "vortyvorty", nDim, ioOffset, ioSize, ioGhost);
6653 pio.writeArray(&square[9][0], blockPathStr, "vortzvortz", nDim, ioOffset, ioSize, ioGhost);
6654 }
6655
6656 if(m_kurtosis || m_skewness) {
6657 pio.writeArray(&cube[0][0], blockPathStr, "uuu", nDim, ioOffset, ioSize, ioGhost);
6658 pio.writeArray(&cube[1][0], blockPathStr, "vvv", nDim, ioOffset, ioSize, ioGhost);
6659 pio.writeArray(&cube[2][0], blockPathStr, "www", nDim, ioOffset, ioSize, ioGhost);
6660 }
6661
6662 if(m_kurtosis) {
6663 pio.writeArray(&fourth[0][0], blockPathStr, "uuuu", nDim, ioOffset, ioSize, ioGhost);
6664 pio.writeArray(&fourth[1][0], blockPathStr, "vvvv", nDim, ioOffset, ioSize, ioGhost);
6665 pio.writeArray(&fourth[2][0], blockPathStr, "wwww", nDim, ioOffset, ioSize, ioGhost);
6666 }
6667}
6668
6669
6674template <MInt nDim>
6676 // Function to write the solution to file with iolibrary
6677
6678 m_log << "writing production terms to file " << name << " ... " << endl;
6679
6680 ParallelIoHdf5 pio(name, maia::parallel_io::PIO_APPEND, m_StructuredComm);
6681
6682 writeHeaderAttributes(&pio, "solution");
6683 writePropertiesAsAttributes(&pio, "");
6684
6685 ParallelIo::size_type allCells[3];
6686 for(MInt i = 0; i < m_noBlocks; i++) {
6687 for(MInt j = 0; j < nDim; j++) {
6688 allCells[j] = m_grid->getBlockNoCells(i, j);
6689 }
6690 // create datasets for the io library
6691 stringstream path;
6692 path << i;
6693 MString blockPathStr = "block";
6694 blockPathStr += path.str();
6695
6696 // create dataset and write
6697 if(!pio.hasDataset("p1j", blockPathStr)) {
6698 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "p1j", nDim, allCells);
6699 } else {
6700 cout << "Dataset p1j exists, not creating new" << endl;
6701 }
6702 if(!pio.hasDataset("p2j", blockPathStr)) {
6703 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "p2j", nDim, allCells);
6704 }
6705 if(!pio.hasDataset("p3j", blockPathStr)) {
6706 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "p3j", nDim, allCells);
6707 }
6708 }
6709
6710 stringstream path;
6711 path << m_blockId;
6712 MString blockPathStr = "block";
6713 blockPathStr += path.str();
6714
6715 ParallelIo::size_type ioOffset[3] = {0, 0, 0};
6716 ParallelIo::size_type ioSize[3] = {0, 0, 0};
6717 ParallelIo::size_type ioGhost[3] = {m_noGhostLayers, m_noGhostLayers, m_noGhostLayers};
6718 for(MInt dim = 0; dim < nDim; ++dim) {
6719 ioOffset[dim] = m_nOffsetCells[dim];
6720 ioSize[dim] = m_nActiveCells[dim];
6721 }
6722
6723 pio.writeArray(&production[0][0], blockPathStr, "p1j", nDim, ioOffset, ioSize, ioGhost);
6724 pio.writeArray(&production[1][0], blockPathStr, "p2j", nDim, ioOffset, ioSize, ioGhost);
6725 pio.writeArray(&production[2][0], blockPathStr, "p3j", nDim, ioOffset, ioSize, ioGhost);
6726}
6727
6732template <MInt nDim>
6734 // Function to write the solution to file with iolibrary
6735
6736 m_log << "writing dissipation terms to file " << name << " ... " << endl;
6737
6738 ParallelIoHdf5 pio(name, maia::parallel_io::PIO_APPEND, m_StructuredComm);
6739
6740 writeHeaderAttributes(&pio, "solution");
6741 writePropertiesAsAttributes(&pio, "");
6742
6743 ParallelIo::size_type allCells[3];
6744 for(MInt i = 0; i < m_noBlocks; i++) {
6745 for(MInt j = 0; j < nDim; j++) {
6746 allCells[j] = m_grid->getBlockNoCells(i, j);
6747 }
6748 // create datasets for the io library
6749 stringstream path;
6750 path << i;
6751 MString blockPathStr = "block";
6752 blockPathStr += path.str();
6753
6754 // create dataset and write
6755 if(!pio.hasDataset("diss", blockPathStr)) {
6756 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, "diss", nDim, allCells);
6757 } else {
6758 cout << "Dataset diss exists, not creating new" << endl;
6759 }
6760 }
6761
6762 stringstream path;
6763 path << m_blockId;
6764 MString blockPathStr = "block";
6765 blockPathStr += path.str();
6766
6767 ParallelIo::size_type ioOffset[3] = {0, 0, 0};
6768 ParallelIo::size_type ioSize[3] = {0, 0, 0};
6769 ParallelIo::size_type ioGhost[3] = {m_noGhostLayers, m_noGhostLayers, m_noGhostLayers};
6770 for(MInt dim = 0; dim < nDim; ++dim) {
6771 ioOffset[dim] = m_nOffsetCells[dim];
6772 ioSize[dim] = m_nActiveCells[dim];
6773 }
6774
6775 pio.writeArray(&dissipation[0], blockPathStr, "diss", nDim, ioOffset, ioSize, ioGhost);
6776}
6777
6778
6783template <MInt nDim>
6784void FvStructuredSolver<nDim>::saveGradients(MString name, MFloat** gradients, MString* gradientNames) {
6785 // Function to write the solution to file with iolibrary
6786
6787 m_log << "writing gradients to file " << name << " ... " << endl;
6788
6789 ParallelIoHdf5 pio(name, maia::parallel_io::PIO_APPEND, m_StructuredComm);
6790
6791 writeHeaderAttributes(&pio, "solution");
6792 writePropertiesAsAttributes(&pio, "");
6793
6794 ParallelIo::size_type allCells[3];
6795 MInt noVars = 3 * 9;
6796 for(MInt i = 0; i < m_noBlocks; i++) {
6797 for(MInt j = 0; j < nDim; j++) {
6798 allCells[j] = m_grid->getBlockNoCells(i, j);
6799 }
6800 // create datasets for the io library
6801 stringstream path;
6802 path << i;
6803 MString blockPathStr = "block";
6804 blockPathStr += path.str();
6805
6806 // create dataset and write
6807 for(MInt var = 0; var < noVars; var++) {
6808 if(!pio.hasDataset(gradientNames[var], blockPathStr)) {
6809 pio.defineArray(maia::parallel_io::PIO_FLOAT, blockPathStr, gradientNames[var], nDim, allCells);
6810 } else {
6811 cout << "Dataset " << gradientNames[var] << " exists, not creating new" << endl;
6812 }
6813 }
6814 }
6815
6816
6817 stringstream path;
6818 path << m_blockId;
6819 MString blockPathStr = "block";
6820 blockPathStr += path.str();
6821
6822 ParallelIo::size_type ioOffset[3] = {0, 0, 0};
6823 ParallelIo::size_type ioSize[3] = {0, 0, 0};
6824 ParallelIo::size_type ioGhost[3] = {m_noGhostLayers, m_noGhostLayers, m_noGhostLayers};
6825 for(MInt dim = 0; dim < nDim; ++dim) {
6826 ioOffset[dim] = m_nOffsetCells[dim];
6827 ioSize[dim] = m_nActiveCells[dim];
6828 }
6829
6830 for(MInt var = 0; var < noVars; var++) {
6831 pio.writeArray(&gradients[var][0], blockPathStr, gradientNames[var].c_str(), nDim, ioOffset, ioSize, ioGhost);
6832 }
6833}
6834
6835
6836template <MInt nDim>
6838 TRACE();
6839
6840 MFloat globalTimeStepMin = F0;
6841
6842 MPI_Allreduce(&m_timeStep, &globalTimeStepMin, 1, MPI_DOUBLE, MPI_MIN, m_StructuredComm, AT_, "m_timeStep",
6843 "globalTimeStepMin");
6844
6845 m_timeStep = globalTimeStepMin;
6846}
6847
6848
6858template <MInt nDim>
6860 // formulation from book pp. 582
6861 MInt n = dim;
6862 MInt l = 0, k = 0, j = 0, i = 0;
6863 MFloat scale = F0, hh = F0, h = F0, g = F0, f = F0;
6864
6865 for(i = dim - 1; i > 0; i--) {
6866 l = i - 1;
6867 h = F0;
6868 scale = F0;
6869 if(l > 0) {
6870 for(k = 0; k < i; ++k) {
6871 scale += abs(A(i, k));
6872 }
6873 if(approx(scale, F0, m_eps)) {
6874 offdiag[i] = A(i, l);
6875 } else {
6876 for(k = 0; k < i; ++k) {
6877 A(i, k) /= scale;
6878 h += A(i, k) * A(i, k);
6879 }
6880 f = A(i, l);
6881 g = (f >= F0 ? -sqrt(h) : sqrt(h));
6882 offdiag[i] = scale * g;
6883 h -= f * g;
6884 A(i, l) = f - g;
6885 f = F0;
6886 for(j = 0; j < i; ++j) {
6887 g = F0;
6888 for(k = 0; k < j + 1; ++k) {
6889 g += A(j, k) * A(i, k);
6890 }
6891 for(k = j + 1; k < i; ++k) {
6892 g += A(k, j) * A(i, k);
6893 }
6894 offdiag[j] = g / h;
6895 f += offdiag[j] * A(i, j);
6896 }
6897 hh = f / (h + h);
6898 for(j = 0; j < i; j++) {
6899 f = A(i, j);
6900 g = offdiag[j] - hh * f;
6901 offdiag[j] = g;
6902 for(k = 0; k < j + 1; k++) {
6903 A(j, k) -= f * offdiag[k] + g * A(i, k);
6904 }
6905 }
6906 }
6907 } else {
6908 offdiag[i] = A(i, l);
6909 }
6910 diag[i] = h;
6911 }
6912
6913 offdiag[0] = F0;
6914 for(i = 0; i < n; ++i) {
6915 diag[i] = A(i, i);
6916 }
6917}
6918
6919
6933template <MInt nDim>
6934void FvStructuredSolver<nDim>::tqli2(MFloat* diag, MFloat* offdiag, MInt dim) //, MFloat** z)
6935{
6936 const MFloat eps = numeric_limits<MFloat>::epsilon();
6937 MInt m, l, iter, i, k;
6938 MFloat s, r, p, g, f, dd, c, b;
6939 MInt n = dim;
6940 for(i = 1; i < n; ++i)
6941 offdiag[i - 1] = offdiag[i];
6942 offdiag[n - 1] = 0.0;
6943 for(l = 0; l < n; ++l) {
6944 iter = 0;
6945 do {
6946 for(m = l; m < n - 1; m++) {
6947 dd = fabs(diag[m]) + fabs(diag[m + 1]);
6948 if(fabs(offdiag[m]) <= eps * dd) break;
6949 }
6950 if(m != l) {
6951 if(iter++ == 30) {
6952 for(k = 0; k < dim; ++k) {
6953 diag[k] = F0;
6954 }
6955 return;
6956 }
6957 g = (diag[l + 1] - diag[l]) / (2.0 * offdiag[l]);
6958 r = pythag(g, F1);
6959 r = abs(r);
6960 if(g < F0) r *= -F1;
6961 g = diag[m] - diag[l] + offdiag[l] / (g + r);
6962 s = c = F1;
6963 p = F0;
6964 for(i = m - 1; i >= l; i--) {
6965 f = s * offdiag[i];
6966 b = c * offdiag[i];
6967 offdiag[i + 1] = (r = pythag(f, g));
6968 if(approx(r, F0, eps)) {
6969 diag[i + 1] -= p;
6970 offdiag[m] = F0;
6971 break;
6972 }
6973 s = f / r;
6974 c = g / r;
6975 g = diag[i + 1] - p;
6976 r = (diag[i] - g) * s + 2.0 * c * b;
6977 diag[i + 1] = g + (p = s * r);
6978 g = c * r - b;
6979 }
6980 if(approx(r, F0, eps) && i >= l) continue;
6981 diag[l] -= p;
6982 offdiag[l] = g;
6983 offdiag[m] = F0;
6984 }
6985 } while(m != l);
6986 }
6987}
6988
6997template <MInt nDim>
6999 MFloat temp = F0;
7000 MInt j = 0;
7001 for(MInt i = 1; i < dim; i++) {
7002 temp = list[i];
7003 j = i - 1;
7004 while(j >= 0 && temp < list[j]) {
7005 list[j + 1] = list[j];
7006 j = j - 1;
7007 }
7008 list[j + 1] = temp;
7009 }
7010}
7011
7012template <MInt nDim>
7014 MFloat absa = F0, absb = F0;
7015 absa = fabs(a);
7016 absb = fabs(b);
7017 if(absa > absb)
7018 return absa * sqrt(1.0 + POW2(absb / absa));
7019 else
7020 return (approx(absb, F0, m_eps) ? F0 : absb * sqrt(1.0 + POW2(absa / absb)));
7021}
7022
7028template <MInt nDim>
7030 TRACE();
7031 MInt noNansLocal = 0;
7032 for(MInt cellid = 0; cellid < m_noCells; cellid++) {
7033 // go through every cell
7034 for(MInt i = 0; i < CV->noVariables; i++) {
7035 if(std::isnan(m_cells->variables[i][cellid])) {
7036 noNansLocal++;
7037 }
7038 }
7039 }
7040
7041 MInt noNansGlobal = 0;
7042 MPI_Allreduce(&noNansLocal, &noNansGlobal, 1, MPI_INT, MPI_SUM, m_StructuredComm, AT_, "noNansLocal", "noNansGlobal");
7043
7044 if(domainId() == 0) {
7045 cout << "GlobalTimeStep: " << globalTimeStep << " , noNansGlobal: " << noNansGlobal << endl;
7046 }
7047}
7048
7049
7050template <MInt nDim>
7052 TRACE();
7053 if(m_travelingWave || m_streamwiseTravelingWave) return;
7054
7055 if((!m_constantTimeStep && globalTimeStep % m_timeStepComputationInterval == 0) || globalTimeStep == 0) {
7056 computeTimeStep();
7057 if(noDomains() > 1) {
7058 exchangeTimeStep();
7059 }
7060
7061 m_physicalTimeStep = m_timeStep * m_timeRef;
7062
7063 setLimiterVisc();
7064 }
7065}
7066
7067
7068template <MInt nDim>
7070 TRACE();
7071
7072 if(m_limiterVisc) {
7073 // NOTE: currently only implemented in 2D
7074 ASSERT(nDim == 2, "Not implemented for 3D yet!");
7075 // xsd = 0, ysd = 1
7076
7077 for(MInt cellId = 0; cellId < m_noCells; cellId++) {
7078 const MFloat metricScale =
7079 POW2(m_cells->cellMetrics[0 * 2 + 0][cellId]) + POW2(m_cells->cellMetrics[0 * 2 + 1][cellId])
7080 + POW2(m_cells->cellMetrics[1 * 2 + 0][cellId]) + POW2(m_cells->cellMetrics[1 * 2 + 1][cellId])
7081 + 2.0
7082 * (m_cells->cellMetrics[0 * 2 + 0][cellId] * m_cells->cellMetrics[1 * 2 + 0][cellId]
7083 + m_cells->cellMetrics[0 * 2 + 1][cellId] * m_cells->cellMetrics[1 * 2 + 1][cellId]);
7084 // TODO_SS labels:FV,totest with localTimeStepping m_physicalTimeStep might not be set properly
7085 // TODO_SS labels:FV in some cases if Jacobian is negative the time step can also get negative -> think if current
7086 // implementation
7087 // would also work in those cases
7088 m_cells->fq[FQ->LIMITERVISC][cellId] =
7089 m_CFLVISC * POW2(m_cells->cellJac[cellId]) / (m_physicalTimeStep * metricScale);
7090 }
7091 }
7092}
7093
7094
7095template <MInt nDim>
7097 const MFloat waveTransSpeed = fabs(m_waveSpeed);
7098
7099 MFloat travelDist = F0;
7100 if(m_travelingWave) {
7101 if(nDim == 3) {
7102 travelDist = abs(m_grid->m_coordinates[2][0] - m_grid->m_coordinates[2][m_nPoints[2] * m_nPoints[1]]);
7103 } else {
7104 travelDist = abs(m_grid->m_coordinates[0][0] - m_grid->m_coordinates[0][1]);
7105 }
7106 } else if(m_streamwiseTravelingWave) {
7107 travelDist = m_waveLength;
7108 } else {
7109 m_log << "WARNING!!!!!!!!!!!!!!!!!!!!: dz was fixed and hardcoded !!!!!!!!!! " << endl;
7110 travelDist = 0.33200866159432146;
7111 }
7112
7113 if(!m_waveTimeStepComputed) {
7114 // first compute time step as usual and exchange it
7115 computeTimeStep();
7116 if(noDomains() > 1) {
7117 exchangeTimeStep();
7118 }
7119
7120 // number of timeSteps the wave needs to move one cell width further
7121 m_waveNoStepsPerCell = ceil((travelDist / waveTransSpeed) / (m_timeStep));
7122 if(m_waveNoStepsPerCell < 2) {
7123 m_waveNoStepsPerCell = 2; // although highly improbable, see Nyquist-Shannon-Theorem
7124 }
7125
7126 cout.precision(18);
7127 if(domainId() == 0) {
7128 cout << "Old time step = " << m_timeStep << endl;
7129 }
7130 m_log << "/////////////////// TRAVELING WAVE /////////////////////////////" << endl;
7131 m_log << "Old time step = " << m_timeStep << endl;
7132
7133 m_timeStep = (travelDist / waveTransSpeed) / (m_waveNoStepsPerCell);
7134 m_physicalTimeStep = m_timeStep * m_timeRef;
7135
7136 MBool syncSolutionInterval = false;
7137 MBool syncForceInterval = false;
7138 MBool syncBoxInterval = false;
7139 MBool syncIntpPointsInterval = false;
7140
7141
7142 // fix output writing functions in case
7143 if(m_synchronizedMGOutput) {
7144 // change the output frequency of the different io routines to be in accordance with the new time step such that
7145 // only in full number of iterations in which the moving grid has traveld one cell distance is ensured
7146 // if(m_outputOffset){
7147 // m_log << "ERROR: m_outputOffset and synchronized output cannot be combined (not implemented yet)" << endl;
7148 // mTerm(1, AT_, "ERROR: m_outputOffset and synchronized output cannot be combined (not implemented yet)");
7149 //}
7150
7151 if(domainId() == 0) {
7152 cout << "m_movingGridStepOffset: " << m_movingGridStepOffset
7153 << " m_movingGridInitialStart: " << m_movingGridInitialStart << endl;
7154 }
7155
7156
7157 if(m_outputOffset > m_movingGridStepOffset) {
7158 const MInt offsetCounter =
7159 ceil(((MFloat)m_outputOffset - (MFloat)m_movingGridStepOffset) / (MFloat)m_waveNoStepsPerCell);
7160 m_outputOffset = m_movingGridStepOffset + offsetCounter * m_waveNoStepsPerCell;
7161 } else {
7162 m_outputOffset = m_movingGridStepOffset; // for input output such that it works propberly
7163 }
7164
7165 if(m_useConvectiveUnitWrite) {
7166 m_log << "ERROR: m_useConvectiveUnitWrite and synchronized output cannot be combined (not implemented yet)"
7167 << endl;
7168 mTerm(1, AT_,
7169 "ERROR: m_useConvetiveUnitWrite and synchronized output cannot be combined (not implemented yet)");
7170 }
7171 if(m_solutionInterval) {
7172 m_solutionInterval =
7173 mMax(m_waveNoStepsPerCell,
7174 m_waveNoStepsPerCell * (MInt)floor((MFloat)m_solutionInterval / (MFloat)m_waveNoStepsPerCell));
7175 syncSolutionInterval = true;
7176 }
7177 if(m_forceOutputInterval) {
7178 m_forceOutputInterval =
7179 mMax(m_waveNoStepsPerCell,
7180 m_waveNoStepsPerCell * (MInt)floor((MFloat)m_forceOutputInterval / (MFloat)m_waveNoStepsPerCell));
7181 syncForceInterval = true;
7182 }
7183 if(m_boxOutputInterval) {
7184 m_boxOutputInterval =
7185 mMax(m_waveNoStepsPerCell,
7186 m_waveNoStepsPerCell * (MInt)floor((MFloat)m_boxOutputInterval / (MFloat)m_waveNoStepsPerCell));
7187
7188 syncBoxInterval = true;
7189 }
7190 if(m_intpPointsOutputInterval) {
7191 m_intpPointsOutputInterval =
7192 mMax(m_waveNoStepsPerCell,
7193 m_waveNoStepsPerCell * (MInt)floor((MFloat)m_boxOutputInterval / (MFloat)m_waveNoStepsPerCell));
7194 syncIntpPointsInterval = true;
7195 }
7196 }
7197
7198 if(domainId() == 0) {
7199 cout << "New time step: " << m_timeStep << " new physical time step: " << m_physicalTimeStep << endl;
7200 cout << "Number of steps to move one cell width: " << travelDist / (m_waveSpeed * m_timeStep) << " time steps"
7201 << endl;
7202 cout << "Number of steps to move one physical time step: " << F1 / m_physicalTimeStep << endl;
7203 cout << "Number of steps to move one wave length: " << m_waveLength / (m_waveSpeed * m_timeStep) << endl;
7204 cout << "Cells per wavelength: " << m_waveLength / travelDist << " travelDist: " << travelDist << endl;
7205 cout << "Time for wave to travel one wave length: " << m_waveLength / m_waveSpeed << endl;
7206 cout << "Physical time for wave to travel one wave length: " << m_waveLength / m_waveSpeed * m_timeRef << endl;
7207 cout << "solution output interval was reset: " << syncSolutionInterval << " and changed to " << m_solutionInterval
7208 << endl;
7209 cout << "box output interval was reset: " << syncBoxInterval << " and changed to " << m_boxOutputInterval << endl;
7210 cout << "force output interval was reset: " << syncForceInterval << " and changed to " << m_forceOutputInterval
7211 << endl;
7212 cout << "intpPoints output interval was reset: " << syncIntpPointsInterval << " and changed to "
7213 << m_intpPointsOutputInterval << endl;
7214 }
7215
7216 m_log << "New time step: " << m_timeStep << " new physical time step: " << m_physicalTimeStep << endl;
7217 m_log << "Number of steps to move one cell width: " << travelDist / (m_waveSpeed * m_timeStep) << " time steps"
7218 << endl;
7219 m_log << "Number of steps to move one physical time step: " << F1 / m_physicalTimeStep << endl;
7220 m_log << "Number of steps to move one wave length: " << m_waveLength / (m_waveSpeed * m_timeStep) << endl;
7221 m_log << "Cells per wavelength: " << m_waveLength / travelDist << " travelDist: " << travelDist << endl;
7222 m_log << "Time for wave to travel one wave length: " << m_waveLength / m_waveSpeed << endl;
7223 m_log << "Physical time for wave to travel one wave length: " << m_waveLength / m_waveSpeed * m_timeRef << endl;
7224 m_log << "solution output interval was reset: " << syncSolutionInterval << " and changed to " << m_solutionInterval
7225 << endl;
7226 m_log << "box output interval was reset: " << syncBoxInterval << " and changed to " << m_boxOutputInterval << endl;
7227 m_log << "force output interval was reset: " << syncForceInterval << " and changed to " << m_forceOutputInterval
7228 << endl;
7229 m_log << "intpPoints output interval was reset: " << syncIntpPointsInterval << " and changed to "
7230 << m_intpPointsOutputInterval << endl;
7231 m_log << "solution writing out will start at" << m_outputOffset << endl;
7232 m_log << "////////////////////////////////////////////////////////////////" << endl;
7233
7234 m_waveTimeStepComputed = true;
7235 }
7236
7237 if(globalTimeStep == 0 || globalTimeStep == m_restartTimeStep) {
7238 MBool syncSolutionInterval = false;
7239 MBool syncForceInterval = false;
7240 MBool syncBoxInterval = false;
7241 MBool syncIntpPointsInterval = false;
7242
7243 // fix output writing functions in case
7244 if(m_synchronizedMGOutput) {
7245 // change the output frequency of the different io routines to be in accordance with the new time step such that
7246 // only in full number of iterations in which the moving grid has traveld one cell distance is ensured
7247 // if(m_outputOffset!=m_movingGridStepOffset){
7248 // m_log << "ERROR: m_outputOffset and synchronized output cannot be combined (not implemented yet)" << endl;
7249 // mTerm(1, AT_, "ERROR: m_outputOffset and synchronized output cannot be combined (not implemented yet)");
7250 //}
7251 // shift the starting point of the outputs for the moving grid
7252
7253 if(m_outputOffset > m_movingGridStepOffset) {
7254 const MInt offsetCounter =
7255 ceil(((MFloat)m_outputOffset - (MFloat)m_movingGridStepOffset) / (MFloat)m_waveNoStepsPerCell);
7256 m_outputOffset = m_movingGridStepOffset + offsetCounter * m_waveNoStepsPerCell;
7257 } else {
7258 m_outputOffset = m_movingGridStepOffset; // for input output such that it works propberly
7259 }
7260
7261
7262 if(m_useConvectiveUnitWrite) {
7263 m_log << "ERROR: m_useConvectiveUnitWrite and synchronized output cannot be combined (not implemented yet)"
7264 << endl;
7265 mTerm(1, AT_,
7266 "ERROR: m_useConvetiveUnitWrite and synchronized output cannot be combined (not implemented yet)");
7267 }
7268 if(m_solutionInterval) {
7269 m_solutionInterval =
7270 mMax(m_waveNoStepsPerCell,
7271 m_waveNoStepsPerCell * (MInt)floor((MFloat)m_solutionInterval / (MFloat)m_waveNoStepsPerCell));
7272 syncSolutionInterval = true;
7273 }
7274 if(m_forceOutputInterval) {
7275 m_forceOutputInterval =
7276 mMax(m_waveNoStepsPerCell,
7277 m_waveNoStepsPerCell * (MInt)floor((MFloat)m_forceOutputInterval / (MFloat)m_waveNoStepsPerCell));
7278 syncForceInterval = true;
7279 }
7280 if(m_boxOutputInterval) {
7281 m_boxOutputInterval =
7282 mMax(m_waveNoStepsPerCell,
7283 m_waveNoStepsPerCell * (MInt)floor((MFloat)m_boxOutputInterval / (MFloat)m_waveNoStepsPerCell));
7284 syncBoxInterval = true;
7285 }
7286 if(m_intpPointsOutputInterval) {
7287 m_intpPointsOutputInterval =
7288 mMax(m_waveNoStepsPerCell,
7289 m_waveNoStepsPerCell * (MInt)floor((MFloat)m_boxOutputInterval / (MFloat)m_waveNoStepsPerCell));
7290 syncIntpPointsInterval = true;
7291 }
7292 }
7293
7294 m_log << "/////////////////// TRAVELING WAVE /////////////////////////////" << endl;
7295 m_log << "New time step: " << m_timeStep << " new physical time step: " << m_physicalTimeStep << endl;
7296 m_log << "Number of steps to move one cell width: " << travelDist / (m_waveSpeed * m_timeStep) << " time steps"
7297 << endl;
7298 m_log << "Number of steps to move one physical time step: " << F1 / m_physicalTimeStep << endl;
7299 m_log << "Number of steps to move one wave length: " << m_waveLength / (m_waveSpeed * m_timeStep) << endl;
7300 m_log << "Time for wave to travel one wave length: " << m_waveLength / m_waveSpeed << endl;
7301 m_log << "Cells per wavelength: " << m_waveLength / travelDist << " travelDist: " << travelDist << endl;
7302 m_log << "solution output interval was reset: " << syncSolutionInterval << " and changed to " << m_solutionInterval
7303 << endl;
7304 m_log << "box output interval was reset: " << syncBoxInterval << " and changed to " << m_boxOutputInterval << endl;
7305 m_log << "force output interval was reset: " << syncForceInterval << " and changed to " << m_forceOutputInterval
7306 << endl;
7307 m_log << "intpPoints output interval was reset: " << syncIntpPointsInterval << " and changed to "
7308 << m_intpPointsOutputInterval << endl;
7309 m_log << "solution writing out will start at" << m_outputOffset << endl;
7310 m_log << "////////////////////////////////////////////////////////////////" << endl;
7311 // correct Averaging Time Steps
7312 if(m_postprocessing) {
7313 const MInt waveNoStepsPerCell = m_waveNoStepsPerCell;
7314 if(m_averageInterval % waveNoStepsPerCell != 0) {
7315 m_log << "Changed averageInterval from " << m_averageInterval;
7316 const MInt minAverageInterval = waveNoStepsPerCell;
7317 m_averageInterval =
7318 mMax(minAverageInterval,
7319 (MInt)(waveNoStepsPerCell * floor((MFloat)m_averageInterval / (MFloat)waveNoStepsPerCell)));
7320 m_log << " to " << m_averageInterval << ", every " << m_averageInterval * m_physicalTimeStep
7321 << " convective units" << endl;
7322 }
7323
7324 const MInt waveStepOffset = m_movingGridStepOffset;
7325 if((m_averageStartTimestep - waveStepOffset) % m_averageInterval != 0) {
7326 m_log << "Changed averageStartTimeStep from " << m_averageStartTimestep;
7327 MInt offsetCounter =
7328 ceil(((MFloat)m_averageStartTimestep - (MFloat)waveStepOffset) / (MFloat)m_averageInterval);
7329 m_averageStartTimestep = waveStepOffset + offsetCounter * m_averageInterval;
7330 m_log << " to " << m_averageStartTimestep << ". Averaging every " << m_averageInterval << " time steps" << endl;
7331 }
7332
7333 if((m_averageStopTimestep - waveStepOffset) % m_averageInterval != 0) {
7334 m_log << "Changed averageStopTimeStep from " << m_averageStopTimestep;
7335 MInt offsetCounter = ceil(((MFloat)m_averageStopTimestep - (MFloat)waveStepOffset) / (MFloat)m_averageInterval);
7336 m_averageStopTimestep = waveStepOffset + offsetCounter * m_averageInterval;
7337 m_log << " to " << m_averageStopTimestep << ". Averaging every " << m_averageInterval << " time steps" << endl;
7338 }
7339 }
7340 }
7341}
7342
7343template <MInt nDim>
7345 TRACE();
7346 const MFloat eps = pow(10.0, -5.0);
7347 if(ABS(oldMa - m_Ma) > eps) {
7348 m_log << "converting restart variables from old Ma: " << oldMa << " to new Ma: " << m_Ma << " ..." << endl;
7349 const MFloat gammaMinusOne = m_gamma - 1.0;
7350 // old references
7351 MFloat T8old = 1.0 / (1.0 + 0.5 * gammaMinusOne * POW2(oldMa));
7352 MFloat p8old = pow(T8old, (m_gamma / gammaMinusOne)) / m_gamma;
7353 MFloat u8old = oldMa * sqrt(T8old);
7354 MFloat rho8old = pow(T8old, (1.0 / gammaMinusOne));
7355 // MFloat rhoU8old = rho8old*u8old;
7356 MFloat rhoE8old = p8old / gammaMinusOne + rho8old * (F1B2 * POW2(u8old));
7357 // new references
7358 MFloat T8new = 1.0 / (1.0 + 0.5 * gammaMinusOne * POW2(m_Ma));
7359 MFloat p8new = pow(T8new, (m_gamma / gammaMinusOne)) / m_gamma;
7360 MFloat u8new = m_Ma * sqrt(T8new);
7361 MFloat rho8new = pow(T8new, (1.0 / gammaMinusOne));
7362 // MFloat rhoU8new = rho8new*u8new;
7363 MFloat rhoE8new = p8new / gammaMinusOne + rho8new * (F1B2 * POW2(u8new));
7364 // ratios
7365 MFloat velRatio = u8new / u8old;
7366 MFloat rhoRatio = rho8new / rho8old;
7367 MFloat pRatio = p8new / p8old;
7368 MFloat rhoERatio = rhoE8new / rhoE8old;
7369
7370 // conversion
7371 for(MInt cellId = 0; cellId < m_noCells; ++cellId) {
7372 // density
7373 m_cells->pvariables[PV->RHO][cellId] *= rhoRatio;
7374 // velocities
7375 for(MInt i = 0; i < nDim; ++i) {
7376 m_cells->pvariables[PV->VV[i]][cellId] *= velRatio;
7377 }
7378 // energy
7379 m_cells->pvariables[PV->P][cellId] *= pRatio;
7380 }
7381
7382 if(m_useSponge) {
7383 if(m_spongeLayerType == 2) {
7384 for(MInt cellId = 0; cellId < m_noCells; ++cellId) {
7385 m_cells->fq[FQ->SPONGE_RHO][cellId] *= rhoRatio;
7386 m_cells->fq[FQ->SPONGE_RHO_E][cellId] *= rhoERatio;
7387 }
7388 }
7389
7390 if(m_spongeLayerType == 4) {
7391 for(MInt cellId = 0; cellId < m_noCells; ++cellId) {
7392 m_cells->fq[FQ->SPONGE_RHO][cellId] *= rhoRatio;
7393 }
7394 }
7395 }
7396
7397 computeConservativeVariables();
7398
7399 m_log << "converting restart variables from old Ma: " << oldMa << " to new Ma: " << m_Ma << " ... SUCCESSFUL!"
7400 << endl;
7401 }
7402 return;
7403}
7404
7405
7410template <MInt nDim>
7411void FvStructuredSolver<nDim>::getDomainDecompositionInformation(std::vector<std::pair<MString, MInt>>& domainInfo) {
7412 TRACE();
7413
7414 const MString namePrefix = "b" + std::to_string(solverId()) + "_";
7415
7416 // Number of Cells
7417 const MInt noCells = m_noCells;
7418
7419 domainInfo.emplace_back(namePrefix + "noStructuredCells", noCells);
7420}
7421
7422
7424template <MInt nDim>
7425void FvStructuredSolver<nDim>::getSolverTimings(std::vector<std::pair<MString, MFloat>>& solverTimings,
7426 const MBool NotUsed(allTimings)) {
7427 TRACE();
7428 const MString namePrefix = "b" + std::to_string(solverId()) + "_";
7429
7430
7431 solverTimings.emplace_back(namePrefix + "Viscous Flux", RETURN_TIMER_TIME(m_timers[Timers::ViscousFlux]));
7432 solverTimings.emplace_back(namePrefix + "ConvectiveFlux", RETURN_TIMER_TIME(m_timers[Timers::ConvectiveFlux]));
7433 solverTimings.emplace_back(namePrefix + "Exchange", RETURN_TIMER_TIME(m_timers[Timers::Exchange]));
7434 solverTimings.emplace_back(namePrefix + "BoundaryCondition", RETURN_TIMER_TIME(m_timers[Timers::BoundaryCondition]));
7435 solverTimings.emplace_back(namePrefix + "RungeKutta Step", RETURN_TIMER_TIME(m_timers[Timers::RungeKutta]));
7436 solverTimings.emplace_back(namePrefix + "Save output", RETURN_TIMER_TIME(m_timers[Timers::SaveOutput]));
7437 solverTimings.emplace_back(namePrefix + "Save forces", RETURN_TIMER_TIME(m_timers[Timers::SaveForces]));
7438 solverTimings.emplace_back(namePrefix + "Save auxdata", RETURN_TIMER_TIME(m_timers[Timers::SaveAuxdata]));
7439 solverTimings.emplace_back(namePrefix + "Save boxes", RETURN_TIMER_TIME(m_timers[Timers::SaveBoxes]));
7440 solverTimings.emplace_back(namePrefix + "Save intp points", RETURN_TIMER_TIME(m_timers[Timers::SaveIntpPoints]));
7441 solverTimings.emplace_back(namePrefix + "Save solution", RETURN_TIMER_TIME(m_timers[Timers::SaveSolution]));
7442 solverTimings.emplace_back(namePrefix + "Sandpaper tripping", RETURN_TIMER_TIME(m_timers[Timers::SandpaperTrip]));
7443 solverTimings.emplace_back(namePrefix + "Moving Grid", RETURN_TIMER_TIME(m_timers[Timers::MovingGrid]));
7444 solverTimings.emplace_back(namePrefix + "Moving grid volume flux", RETURN_TIMER_TIME(m_timers[Timers::MGVolumeFlux]));
7445 solverTimings.emplace_back(namePrefix + "MG Move Grid", RETURN_TIMER_TIME(m_timers[Timers::MGMoveGrid]));
7446}
7447
7448
7455template <MInt nDim>
7457 TRACE();
7458
7459 m_log << "initialization of falkner scan cooke " << endl;
7460
7461 // create file to read the fsc velocity distribution
7462 ParallelIo parallelIo("fsc.Netcdf", maia::parallel_io::PIO_READ, mpiComm());
7463
7464 // get the size of the arrays
7465 vector<ParallelIo::size_type> dims = parallelIo.getArrayDims("eta");
7466 m_fsc_noPoints = (MInt)(dims[0]);
7467 parallelIo.setOffset(m_fsc_noPoints, 0);
7468
7469 // allocate memory for the arrays
7470 mAlloc(m_fsc_eta, m_fsc_noPoints, "m_fsc_eta", AT_);
7471 mAlloc(m_fsc_fs, m_fsc_noPoints, "m_fsc_fs", AT_);
7472 mAlloc(m_fsc_f, m_fsc_noPoints, "m_fsc_f", AT_);
7473 mAlloc(m_fsc_g, m_fsc_noPoints, "m_fsc_g", AT_);
7474
7475 // read the arrays
7476 parallelIo.readArray(m_fsc_eta, "eta");
7477 parallelIo.readArray(m_fsc_fs, "fprim");
7478 parallelIo.readArray(m_fsc_g, "g");
7479 parallelIo.readScalar(&m_fsc_m, "m");
7480
7481 // FSC Parameters
7482 m_fsc_Re = cos(m_angle[1]) * m_Re;
7483
7496 m_fsc_x0 = Context::getSolverProperty<MFloat>("fscX0", m_solverId, AT_, &m_fsc_x0);
7497
7498
7499 m_fsc_dx0 = F0;
7512 m_fsc_dx0 = Context::getSolverProperty<MFloat>("fscDX0", m_solverId, AT_, &m_fsc_dx0);
7513
7514 m_fsc_y0 = F0;
7527 m_fsc_y0 = Context::getSolverProperty<MFloat>("fscY0", m_solverId, AT_, &m_fsc_y0);
7528
7529
7530 m_log << "fsc Reynolds number " << m_fsc_Re << endl;
7531 m_log << "acceleration parameter " << m_fsc_m << endl;
7532 m_log << "reference location x " << m_fsc_x0 << endl;
7533 m_log << "reference location in maia coords " << m_fsc_dx0 << endl;
7534 m_log << "y position of no-slip " << m_fsc_y0 << endl;
7535
7536 // calculate the integral of fs
7537 const MFloat detaB2 = m_fsc_eta[1] / F2;
7538 m_fsc_f[0] = F0;
7539 for(MInt i = 1; i < m_fsc_noPoints; i++)
7540 m_fsc_f[i] = m_fsc_f[i - 1] + detaB2 * (m_fsc_fs[i - 1] + m_fsc_fs[i]);
7541
7542 // debug raw distributions
7543 if(true && !domainId()) {
7544 ofstream fscf;
7545 // write pressure to file
7546 fscf.open("fsc_raw.dat", ios::trunc);
7547 if(fscf) {
7548 fscf << "#eta fs f g" << endl;
7549 for(MInt i = 0; i < m_fsc_noPoints; i++) {
7550 fscf << m_fsc_eta[i] << " " << m_fsc_fs[i] << " " << m_fsc_f[i] << " " << m_fsc_g[i] << endl;
7551 }
7552 fscf.close();
7553 }
7554 }
7555 m_log << " done " << endl;
7556}
7557
7558
7559template <MInt nDim>
7561 return getFscPressure(m_cells->coordinates[0][cellId]);
7562}
7563
7564template <MInt nDim>
7566 const MFloat dx = coordX - m_fsc_dx0;
7567 const MFloat x = m_fsc_x0 + dx;
7568
7569 const MFloat fac = CV->rhoInfinity * POW2(PV->UInfinity) * F1B2;
7570 return PV->PInfinity + fac * (F1 - pow(x / m_fsc_x0, F2 * m_fsc_m));
7571}
7572
7580template <MInt nDim>
7582 getFscVelocity(m_cells->coordinates[0][cellId], m_cells->coordinates[1][cellId], vel);
7583}
7584
7585template <MInt nDim>
7587 const MFloat dx = coordX - m_fsc_dx0;
7588 const MFloat x = m_fsc_x0 + dx;
7589 const MFloat y = coordY - m_fsc_y0;
7590 return y * sqrt((m_fsc_m + F1) * m_fsc_Re * pow(x / m_fsc_x0, m_fsc_m) / (F2 * x));
7591}
7592
7593
7594template <MInt nDim>
7596 // coordinates
7597 const MFloat eta = getFscEta(coordX, coordY);
7598 const MFloat dx = coordX - m_fsc_dx0;
7599 const MFloat x = m_fsc_x0 + dx;
7600
7601 // get f, fs
7602 MFloat fs, f;
7603 if(eta >= m_fsc_eta[m_fsc_noPoints - 1]) { // freestream
7604 fs = m_fsc_fs[m_fsc_noPoints - 1];
7605 f = m_fsc_f[m_fsc_noPoints - 1] + m_fsc_fs[m_fsc_noPoints - 1] * (eta - m_fsc_eta[m_fsc_noPoints - 1]);
7606 } else if(eta <= F0) { // set zero, this is wrong in case of blowing or suction
7607 fs = F0;
7608 f = F0;
7609 } else { // interpolate
7610 // get index
7611 const MFloat Deta = m_fsc_eta[1];
7612 const MInt etai = eta / Deta;
7613 ASSERT((etai + 1) <= (m_fsc_noPoints - 1), "error computing the index for fsc distributions");
7614 const MFloat deta = eta - m_fsc_eta[etai];
7615 const MFloat phi = deta / Deta;
7616 fs = m_fsc_fs[etai] * (F1 - phi) + m_fsc_fs[etai + 1] * phi;
7617 f = m_fsc_f[etai] * (F1 - phi) + m_fsc_f[etai + 1] * phi;
7618 }
7619
7620 // "streamwise"
7621 vel[0] = PV->UInfinity * pow(x / m_fsc_x0, m_fsc_m) * fs;
7622 // normal, computet as inside the eta range
7623 const MFloat fac = sqrt(F2 * pow(x / m_fsc_x0, m_fsc_m) / ((m_fsc_m + F1) * m_fsc_x0 * m_fsc_Re)) / F2;
7624 // eta might be < 0 but then, fs and f are zero
7625 vel[1] = PV->UInfinity * fac * ((F1 - m_fsc_m) * fs * eta - (F1 + m_fsc_m) * f);
7626
7627 // spanwise
7628 IF_CONSTEXPR(nDim > 2) {
7629 MFloat g;
7630 if(eta >= m_fsc_eta[m_fsc_noPoints - 1]) { // freestream
7631 g = m_fsc_g[m_fsc_noPoints - 1];
7632 } else if(eta <= F0) { // set zero, this is wrong in case of blowing or suction
7633 g = F0;
7634 } else { // interpolate
7635 // get index
7636 const MFloat Deta = m_fsc_eta[1];
7637 const MInt etai = eta / Deta;
7638 ASSERT((etai + 1) <= (m_fsc_noPoints - 1), "error computing the index for fsc distributions");
7639 const MFloat deta = eta - m_fsc_eta[etai];
7640 const MFloat phi = deta / Deta;
7641 g = m_fsc_g[etai] * (F1 - phi) + m_fsc_g[etai + 1] * phi;
7642 }
7643 vel[2] = PV->WInfinity * g;
7644 }
7645}
7646
7647
7655template <MInt nDim>
7657 TRACE();
7658
7659
7660 const MFloat fppwall = 0.332051914927913096446;
7661
7662 // Calculate Blasius solution
7663 const MFloat etamax = 20.0;
7664 const MFloat deta = 0.001;
7665 const MInt steps = etamax / deta;
7666
7667 MFloatScratchSpace blasius(steps + 1, 4, "m_blasius", AT_);
7668 blasius.fill(F0);
7669 blasius(0, 3) = fppwall;
7670
7671 // Lets use the shooting method for getting the Blasius solution
7672 for(MInt i = 0; i < steps; i++) {
7673 blasius(i + 1, 0) = blasius(i, 0) + deta;
7674 blasius(i + 1, 1) = blasius(i, 1) + blasius(i, 2) * deta;
7675 blasius(i + 1, 2) = blasius(i, 2) + blasius(i, 3) * deta;
7676 blasius(i + 1, 3) = blasius(i, 3) + (-0.5 * blasius(i, 1) * blasius(i, 3)) * deta;
7677 }
7678
7679 m_blasius_noPoints = steps;
7680
7681 // allocate memory for the arrays
7682 mAlloc(m_blasius_eta, m_blasius_noPoints, "m_blasius_eta", AT_);
7683 mAlloc(m_blasius_fp, m_blasius_noPoints, "m_blasius_fp", AT_);
7684 mAlloc(m_blasius_f, m_blasius_noPoints, "m_blasius_f", AT_);
7685
7686 const MFloat finalfp = blasius(steps - 1, 2);
7687
7688 for(MInt i = 0; i < steps; i++) {
7689 m_blasius_eta[i] = blasius(i, 0);
7690 m_blasius_f[i] = blasius(i, 1) / finalfp;
7691 m_blasius_fp[i] = blasius(i, 2) / finalfp;
7692 }
7693
7694 // debug raw distributions
7695 if(domainId() == 0) {
7696 ofstream blasiusf;
7697 // write pressure to file
7698 blasiusf.open("blasius_raw.dat", ios::trunc);
7699 if(blasiusf) {
7700 blasiusf << "#eta f fp" << endl;
7701 for(MInt i = 0; i < m_blasius_noPoints; i++) {
7702 blasiusf << m_blasius_eta[i] << " " << m_blasius_f[i] << " " << m_blasius_fp[i] << endl;
7703 }
7704 blasiusf.close();
7705 }
7706 }
7707
7708 m_blasius_dx0 = 0.0;
7709 m_blasius_y0 = 0.0; // position of the wall
7710}
7711
7712
7720template <MInt nDim>
7722 getBlasiusVelocity(m_cells->coordinates[0][cellId], m_cells->coordinates[1][cellId], vel);
7723}
7724
7725template <MInt nDim>
7727 const MFloat nu8 = SUTHERLANDLAW(PV->TInfinity) / CV->rhoInfinity;
7728 m_blasius_x0 = F1 / POW2(1.7208) * PV->UInfinity / nu8 * m_Re0;
7729
7730 const MFloat dx = coordX - m_blasius_dx0;
7731 const MFloat x = m_blasius_x0 + dx;
7732 const MFloat y = coordY - m_blasius_y0;
7733
7734 return y * sqrt(PV->UInfinity * m_Re0 / (nu8 * x));
7735}
7736
7737
7738template <MInt nDim>
7740 // coordinates
7741 const MFloat nu8 = SUTHERLANDLAW(PV->TInfinity) / CV->rhoInfinity;
7742 m_blasius_x0 = F1 / POW2(1.7208) * PV->UInfinity / nu8 * m_Re0;
7743 const MFloat eta = getBlasiusEta(coordX, coordY);
7744 const MFloat dx = coordX - m_blasius_dx0;
7745 const MFloat x = m_blasius_x0 + dx;
7746
7747 // get f, fp, and g
7748 MFloat fp, f;
7749 if(eta >= m_blasius_eta[m_blasius_noPoints - 1]) { // freestream
7750 fp = m_blasius_fp[m_blasius_noPoints - 1];
7751 f = m_blasius_f[m_blasius_noPoints - 1]
7752 + m_blasius_fp[m_blasius_noPoints - 1] * (eta - m_blasius_eta[m_blasius_noPoints - 1]);
7753 } else if(eta <= F0) { // set zero, this is wrong in case of blowing or suction
7754 fp = F0;
7755 f = F0;
7756 } else { // interpolate
7757 // get index
7758 const MFloat Deta = m_blasius_eta[1];
7759 const MInt etai = eta / Deta;
7760 ASSERT((etai + 1) <= (m_blasius_noPoints - 1), "error computing the index for Blasius distributions");
7761 const MFloat deta = eta - m_blasius_eta[etai];
7762 const MFloat phi = deta / Deta;
7763 fp = m_blasius_fp[etai] * (F1 - phi) + m_blasius_fp[etai + 1] * phi;
7764 f = m_blasius_f[etai] * (F1 - phi) + m_blasius_f[etai + 1] * phi;
7765 }
7766
7767 vel[0] = PV->UInfinity * fp;
7768 vel[1] = F1B2 * sqrt(PV->UInfinity * nu8 / (x * m_Re0)) * (eta * fp - f);
7769 IF_CONSTEXPR(nDim == 3) { vel[2] = 0.0; }
7770}
7771
7772
7777template <MInt nDim>
7779 TRACE();
7780 RECORD_TIMER_START(m_timers[Timers::RunInit]);
7781 initializeRungeKutta();
7782
7783 // Note: timers needed here for subtimers started in exchange() called from initSolutionStep()
7784 RECORD_TIMER_START(m_timers[Timers::Run]);
7785 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
7786 initSolutionStep(-1);
7787 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
7788 RECORD_TIMER_STOP(m_timers[Timers::Run]);
7789
7790 setTimeStep();
7791 RECORD_TIMER_STOP(m_timers[Timers::RunInit]);
7792}
7793
7794template <MInt nDim>
7796 this->postprocessPreInit();
7797 this->postprocessPreSolve();
7798}
7802
7803template <MInt nDim>
7805 TRACE();
7806
7807 if(m_ransMethod == RANS_KEPSILON) {
7808 m_bForce = true;
7809 m_detailAuxData = true;
7810 }
7811
7812 if(m_bForce) {
7813 const MInt noFields = nDim + m_detailAuxData * 2 * nDim;
7814
7815 MInt noAuxDataMaps = m_windowInfo->physicalAuxDataMap.size();
7816 if(noAuxDataMaps > 0) {
7817 mAlloc(m_cells->cfOffsets, noAuxDataMaps, "m_cells->cfOffsets", 0, AT_);
7818 mAlloc(m_cells->cpOffsets, noAuxDataMaps, "m_cells->cpOffsets", 0, AT_);
7819 mAlloc(m_cells->powerOffsets, noAuxDataMaps, "m_cells->powerOffsets", 0, AT_);
7820 }
7821 MInt totalSizeCf = 0, totalSizeCp = 0, totalSizePower = 0;
7822 for(MInt i = 0; i < noAuxDataMaps; ++i) {
7823 MInt dataSize = 1;
7824 for(MInt j = 0; j < nDim; ++j) {
7825 if(m_windowInfo->physicalAuxDataMap[i]->end1[j] == m_windowInfo->physicalAuxDataMap[i]->start1[j]) {
7826 continue;
7827 }
7828 dataSize *= m_windowInfo->physicalAuxDataMap[i]->end1[j] - m_windowInfo->physicalAuxDataMap[i]->start1[j];
7829 }
7830 m_cells->cfOffsets[i] = totalSizeCf;
7831 m_cells->cpOffsets[i] = totalSizeCp;
7832 m_cells->powerOffsets[i] = totalSizePower;
7833 totalSizeCf += dataSize * noFields;
7834 totalSizeCp += dataSize;
7835 totalSizePower += dataSize * nDim;
7836 }
7837
7838 if(totalSizeCf > 0) {
7839 mAlloc(m_cells->cf, totalSizeCf, "m_cells->cf", -1.23456123456, AT_);
7840 }
7841 if(totalSizeCp > 0) {
7842 mAlloc(m_cells->cp, totalSizeCp, "m_cells->cp", -1.23456123456, AT_);
7843 }
7844
7845 if(m_bPower) {
7846 if(totalSizePower > 0) {
7847 mAlloc(m_cells->powerVisc, totalSizePower, "m_cells->power", -1.23456123456, AT_);
7848 mAlloc(m_cells->powerPres, totalSizePower, "m_cells->power", -1.23456123456, AT_);
7849 }
7850 }
7851
7852 m_forceHeaderNames.clear();
7853 m_forceHeaderNames.push_back("n");
7854 m_forceHeaderNames.push_back("t_ac");
7855 m_forceHeaderNames.push_back("t_conv");
7856 m_forceHeaderNames.push_back("f_x");
7857 m_forceHeaderNames.push_back("f_x,v");
7858 m_forceHeaderNames.push_back("f_x,p");
7859 m_forceHeaderNames.push_back("f_x,c");
7860 m_forceHeaderNames.push_back("f_y");
7861 m_forceHeaderNames.push_back("f_y,v");
7862 m_forceHeaderNames.push_back("f_y,p");
7863 m_forceHeaderNames.push_back("f_y,c");
7864 IF_CONSTEXPR(nDim == 3) {
7865 m_forceHeaderNames.push_back("f_z");
7866 m_forceHeaderNames.push_back("f_z,v");
7867 m_forceHeaderNames.push_back("f_z,p");
7868 m_forceHeaderNames.push_back("f_z,c");
7869 }
7870 m_forceHeaderNames.push_back("area");
7871 if(m_bPower) {
7872 m_forceHeaderNames.push_back("P_x");
7873 m_forceHeaderNames.push_back("P_x,v");
7874 m_forceHeaderNames.push_back("P_x,p");
7875 m_forceHeaderNames.push_back("P_y");
7876 m_forceHeaderNames.push_back("P_y,v");
7877 m_forceHeaderNames.push_back("P_y,p");
7878 IF_CONSTEXPR(nDim == 3) {
7879 m_forceHeaderNames.push_back("P_z");
7880 m_forceHeaderNames.push_back("P_z,v");
7881 m_forceHeaderNames.push_back("P_z,p");
7882 }
7883 }
7884
7885 m_noForceDataFields = (MInt)m_forceHeaderNames.size();
7886 m_forceCounter = 0;
7887
7888 const MInt noWalls = m_windowInfo->m_auxDataWindowIds.size();
7889 if(m_forceAsciiOutputInterval > 0 && noWalls * m_noForceDataFields > 0) {
7890 mAlloc(m_forceData, m_forceAsciiOutputInterval, noWalls * m_noForceDataFields, "m_forceData", F0, AT_);
7891 }
7892
7893 // Allocate memory for integral coefficients
7894 if(noWalls * m_noForceDataFields > 0) {
7895 mAlloc(m_forceCoef, noWalls * m_noForceDataFields, "m_forceCoef", F0, AT_);
7896 }
7897 }
7898
7899
7900 IF_CONSTEXPR(nDim == 3) {
7901 if(m_bForceLineAverage) {
7902 // compute Domain Width for Averaging
7903 computeDomainWidth();
7904 }
7905 }
7906
7907 if(domainId() == 0 && m_forceAsciiOutputInterval != 0) {
7908 // we need to decide how many files to open
7909 const MInt noWalls = m_windowInfo->m_auxDataWindowIds.size();
7910
7911 m_lastForceOutputTimeStep = -1;
7912 m_lastForceComputationTimeStep = -1;
7913
7914 // create file header if file does not exist
7915 for(MInt i = 0; i < noWalls; ++i) {
7916 stringstream iWall;
7917 iWall << i;
7918 MString filename = "./forces." + iWall.str() + ".dat";
7919
7920
7921 if(FILE* file = fopen(filename.c_str(), "r")) {
7922 fclose(file);
7923 } else {
7924 FILE* f_forces;
7925 f_forces = fopen(filename.c_str(), "a+");
7926
7927 fprintf(f_forces,
7928 "# Force coefficient file, the force coefficents in the 2 or 3 space directions\n"
7929 "# are listed in columns, the subscript v denotes a viscous force, p a pressure force,\n"
7930 "# and c the compressible contribution of the stress tensor\n");
7931 fprintf(f_forces, "# 1:%s ", m_forceHeaderNames[0].c_str());
7932 for(MInt j = 1; j < (MInt)m_forceHeaderNames.size(); j++) {
7933 fprintf(f_forces, " %d:%s ", (j + 1), m_forceHeaderNames[j].c_str());
7934 }
7935 fprintf(f_forces, "\n");
7936 fclose(f_forces);
7937 }
7938 }
7939 }
7940}
7941
7947template <MInt nDim>
7949 const MInt noWalls = m_windowInfo->m_auxDataWindowIds.size();
7950 MPI_Allreduce(MPI_IN_PLACE, m_forceCoef, noWalls * m_noForceDataFields, MPI_DOUBLE, MPI_SUM, m_StructuredComm, AT_,
7951 "MPI_IN_PLACE", "m_forceCoef");
7952
7953 if(m_bForceLineAverage) {
7954 for(MInt i = 0; i < noWalls * m_noForceDataFields; ++i) {
7955 m_forceCoef[i] /= m_globalDomainWidth;
7956 }
7957 }
7958}
7959
7960
7968template <MInt nDim>
7970 const MInt noWalls = m_windowInfo->m_auxDataWindowIds.size();
7971
7972 MFloatScratchSpace force(noWalls * m_noForceDataFields, AT_, "force");
7973 for(MInt i = 0; i < noWalls * m_noForceDataFields; ++i) {
7974 force(i) = m_forceCoef[i];
7975 }
7976
7977
7978 MPI_Reduce(force.begin(), m_forceCoef, noWalls * m_noForceDataFields, MPI_DOUBLE, MPI_SUM, 0, m_StructuredComm, AT_,
7979 "force", "forceCoef");
7980 if(m_bForceLineAverage) {
7981 for(MInt i = 0; i < noWalls * m_noForceDataFields; ++i) {
7982 m_forceCoef[i] /= m_globalDomainWidth;
7983 }
7984 }
7985}
7986
7987
7988template <MInt nDim>
7990 if(m_bForce && m_bPower) {
7991 computeFrictionPressureCoef(true);
7992 } else {
7993 computeFrictionPressureCoef(false);
7994 }
7995
7996 if(m_bForce) computeForceCoef();
7997}
7998
7999
8000template <MInt nDim>
8002 if(m_bForce && m_bPower) {
8003 computeFrictionPressureCoef(true);
8004 } else {
8005 computeFrictionPressureCoef(false);
8006 }
8007
8008 if(m_bForce) computeForceCoefRoot();
8009}
8013
8014// TODO_SS labels:FV SVD stuff belongs into some math cpp file
8018// this one is for the singularities
8019template <MInt nDim>
8021 MInt sID, MFloatScratchSpace& tmpA, MFloatScratchSpace& tmpC,
8022 MFloatScratchSpace& weights, const MInt recDim) {
8023 if(noNghbrIds == 0) return F0;
8024
8025 const MFloat normalizationFactor = 1 / 0.01; // reduces the condition number of the eq system
8026
8027 for(MInt n = 0; n < noNghbrIds; n++) {
8028 MInt nghbrId = nghbr[n];
8029 MFloat dx[nDim];
8030 for(MInt i = 0; i < nDim; i++) {
8031 dx[i] = (m_cells->coordinates[i][nghbrId] - m_grid->m_coordinates[i][ijk]) * normalizationFactor;
8032 }
8033
8034 tmpA(n, 0) = F1 * normalizationFactor;
8035 for(MInt i = 0; i < nDim; i++) {
8036 tmpA(n, i + 1) = dx[i];
8037 }
8038 }
8039
8040 maia::math::invert(tmpA, weights, tmpC, noNghbrIds, recDim);
8041
8042 // condition number could be calculated using:
8043 // condNum = svd.singularValues()(0)/svd.singularValues()(size-1);
8044 // but would double the computational effort...
8045
8046 for(MInt n = 0; n < noNghbrIds; n++) {
8047 for(MInt i = 0; i < nDim + 1; i++) {
8048 m_singularity[sID].ReconstructionConstants[i][ID + n] = tmpC(i, n) * normalizationFactor;
8049 }
8050 }
8051
8052 return 0;
8053}
8054
8058
8059
8060template <MInt nDim>
8062 exchange(m_sndComm, m_rcvComm);
8063}
8064
8069template <MInt nDim>
8070void FvStructuredSolver<nDim>::exchange(std::vector<std::unique_ptr<StructuredComm<nDim>>>& sndComm,
8071 std::vector<std::unique_ptr<StructuredComm<nDim>>>& rcvComm) {
8072 RECORD_TIMER_START(m_timers[Timers::Exchange]);
8073
8074
8078 if(noDomains() > 1) {
8079 std::vector<MPI_Request> sndRequests;
8080 std::vector<MPI_Request> rcvRequests;
8081 std::vector<MPI_Status> sndStatus;
8082 std::vector<MPI_Status> rcvStatus;
8083 sndRequests.reserve(sndComm.size());
8084 rcvRequests.reserve(rcvComm.size());
8085
8086 RECORD_TIMER_START(m_timers[Timers::Gather]);
8087 gather(false, sndComm);
8088 RECORD_TIMER_STOP(m_timers[Timers::Gather]);
8089
8090 RECORD_TIMER_START(m_timers[Timers::Send]);
8091 send(false, sndComm, sndRequests);
8092 RECORD_TIMER_STOP(m_timers[Timers::Send]);
8093
8094 RECORD_TIMER_START(m_timers[Timers::Receive]);
8095 receive(false, rcvComm, rcvRequests);
8096 RECORD_TIMER_STOP(m_timers[Timers::Receive]);
8097
8098 RECORD_TIMER_START(m_timers[Timers::SendWait]);
8099 sndStatus.resize(sndRequests.size());
8100 MPI_Waitall(sndRequests.size(), &sndRequests[0], &sndStatus[0], AT_);
8101 RECORD_TIMER_STOP(m_timers[Timers::SendWait]);
8102
8103 RECORD_TIMER_START(m_timers[Timers::ReceiveWait]);
8104 rcvStatus.resize(rcvRequests.size());
8105 MPI_Waitall(rcvRequests.size(), &rcvRequests[0], &rcvStatus[0], AT_);
8106 RECORD_TIMER_STOP(m_timers[Timers::ReceiveWait]);
8107
8108 RECORD_TIMER_START(m_timers[Timers::Scatter]);
8109 scatter(false, rcvComm);
8110 RECORD_TIMER_STOP(m_timers[Timers::Scatter]);
8111 }
8112
8116
8117 for(MInt periodicDir = 0; periodicDir < nDim; periodicDir++) {
8118 std::vector<MPI_Request> sndRequests;
8119 std::vector<MPI_Request> rcvRequests;
8120 std::vector<MPI_Status> sndStatus;
8121 std::vector<MPI_Status> rcvStatus;
8122 sndRequests.reserve(sndComm.size());
8123 rcvRequests.reserve(rcvComm.size());
8124
8125 m_currentPeriodicDirection = periodicDir;
8126 RECORD_TIMER_START(m_timers[Timers::Gather]);
8127 gather(true, sndComm);
8128 RECORD_TIMER_STOP(m_timers[Timers::Gather]);
8129
8130 RECORD_TIMER_START(m_timers[Timers::Send]);
8131 send(true, sndComm, sndRequests);
8132 RECORD_TIMER_STOP(m_timers[Timers::Send]);
8133
8134 RECORD_TIMER_START(m_timers[Timers::Receive]);
8135 receive(true, rcvComm, rcvRequests);
8136 RECORD_TIMER_STOP(m_timers[Timers::Receive]);
8137
8138 RECORD_TIMER_START(m_timers[Timers::SendWait]);
8139 sndStatus.resize(sndRequests.size());
8140 MPI_Waitall(sndRequests.size(), &sndRequests[0], &sndStatus[0], AT_);
8141 RECORD_TIMER_STOP(m_timers[Timers::SendWait]);
8142
8143 RECORD_TIMER_START(m_timers[Timers::ReceiveWait]);
8144 rcvStatus.resize(rcvRequests.size());
8145 MPI_Waitall(rcvRequests.size(), &rcvRequests[0], &rcvStatus[0], AT_);
8146 RECORD_TIMER_STOP(m_timers[Timers::ReceiveWait]);
8147
8148 RECORD_TIMER_START(m_timers[Timers::Scatter]);
8149 scatter(true, rcvComm);
8150 RECORD_TIMER_STOP(m_timers[Timers::Scatter]);
8151 }
8152
8153 RECORD_TIMER_STOP(m_timers[Timers::Exchange]);
8154}
8155
8156
8157template <MInt nDim>
8158void FvStructuredSolver<nDim>::send(const MBool periodicExchange,
8159 std::vector<std::unique_ptr<StructuredComm<nDim>>>& sndComm,
8160 std::vector<MPI_Request>& sndRequests) {
8161 for(auto& snd : sndComm) {
8162 if(periodicExchange && skipPeriodicDirection(snd)) continue;
8163
8164 MPI_Request request{};
8165 const MInt tag = domainId() + (snd->tagHelper) * noDomains();
8166 const MInt err = MPI_Isend((void*)&snd->cellBuffer[0], snd->cellBufferSize, MPI_DOUBLE, snd->nghbrId, tag,
8167 m_StructuredComm, &request, AT_, "snd->cellBuffer");
8168 sndRequests.push_back(request);
8169 if(err) cout << "rank " << domainId() << " sending throws error " << endl;
8170 }
8171}
8172
8173template <MInt nDim>
8174void FvStructuredSolver<nDim>::receive(const MBool periodicExchange,
8175 std::vector<std::unique_ptr<StructuredComm<nDim>>>& rcvComm,
8176 std::vector<MPI_Request>& rcvRequests) {
8177 for(auto& rcv : rcvComm) {
8178 if(periodicExchange && skipPeriodicDirection(rcv)) continue;
8179
8180 MPI_Request request{};
8181 const MInt tag = rcv->nghbrId + (rcv->tagHelper) * noDomains();
8182 const MInt err = MPI_Irecv((void*)&rcv->cellBuffer[0], rcv->cellBufferSize, MPI_DOUBLE, rcv->nghbrId, tag,
8183 m_StructuredComm, &request, AT_, "rcv->cellBuffer");
8184 rcvRequests.push_back(request);
8185 if(err) cout << "rank " << domainId() << " sending throws error " << endl;
8186 }
8187}
8188
8189
8190template <MInt nDim>
8192 const MInt currentDirection = (comm->bcId - 4401) / 2;
8193 return ((MBool)(m_currentPeriodicDirection - currentDirection));
8194}
8195
8196template <MInt nDim>
8198 if(comm->commType == PERIODIC_BC || comm->commType == PERIODIC_BC_SINGULAR) {
8199 return true;
8200 } else {
8201 return false;
8202 }
8203}
8204
8205
8210template <MInt nDim>
8212 TRACE();
8213
8214 resetRHS();
8215
8216 Muscl();
8217
8218 if(!m_euler) {
8219 RECORD_TIMER_START(m_timers[Timers::ViscousFlux]);
8220 viscousFlux();
8221 RECORD_TIMER_STOP(m_timers[Timers::ViscousFlux]);
8222 }
8223
8224 if(m_considerVolumeForces) {
8225 setVolumeForce();
8226 computeVolumeForces();
8227 }
8228
8229 if(m_blockType == "porous") {
8230 if(m_rans)
8231 computePorousRHS(true);
8232 else
8233 computePorousRHS(false);
8234 }
8235}
8236
8241template <MInt nDim>
8243 RECORD_TIMER_START(m_timers[Timers::UpdateSponge]);
8244 updateSpongeLayer();
8245 RECORD_TIMER_STOP(m_timers[Timers::UpdateSponge]);
8246}
8247
8248template <MInt nDim>
8250 computePrimitiveVariables();
8251
8252 exchange();
8253
8254 if(m_zonal) {
8255 computeCumulativeAverage(false);
8256 if(globalTimeStep % m_zonalExchangeInterval == 0 && m_RKStep == 0) {
8257 spanwiseAvgZonal(m_zonalSpanwiseAvgVars);
8258 zonalExchange();
8259 }
8260 }
8261
8262 RECORD_TIMER_START(m_timers[Timers::BoundaryCondition]);
8263 applyBoundaryCondition();
8264 RECORD_TIMER_STOP(m_timers[Timers::BoundaryCondition]);
8265}
8266
8267template <MInt nDim>
8269 RECORD_TIMER_START(m_timers[Timers::Run]);
8270 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
8271 rhs();
8272
8273 rhsBnd();
8274
8275 RECORD_TIMER_START(m_timers[Timers::RungeKutta]);
8276 const MBool step = rungeKuttaStep();
8277 RECORD_TIMER_STOP(m_timers[Timers::RungeKutta]);
8278
8279 RECORD_TIMER_START(m_timers[Timers::SetTimeStep]);
8280 if(step) setTimeStep();
8281 RECORD_TIMER_STOP(m_timers[Timers::SetTimeStep]);
8282
8283 lhsBnd();
8284
8285 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
8286 RECORD_TIMER_STOP(m_timers[Timers::Run]);
8287 return step;
8288}
8289
8290
8295template <MInt nDim>
8297 TRACE();
8298 RECORD_TIMER_START(m_timers[Timers::Run]);
8299 RECORD_TIMER_START(m_timers[Timers::MainLoop]);
8300 m_timeStepConverged = maxResidual();
8301 RECORD_TIMER_STOP(m_timers[Timers::MainLoop]);
8302 RECORD_TIMER_STOP(m_timers[Timers::Run]);
8303}
8304
8305
8306template <MInt nDim>
8308 RECORD_TIMER_START(m_timers[Timers::Run]);
8309 // write a solution file before the solution run ends
8310
8311 if(m_lastOutputTimeStep != globalTimeStep) {
8312 if(m_forceAsciiOutputInterval != 0) {
8313 saveForcesToAsciiFile(true);
8314 }
8315 if(m_pointsToAsciiOutputInterval != 0) {
8316 savePointsToAsciiFile(true);
8317 }
8318 saveSolution(true);
8319 saveAverageRestart();
8320 }
8321
8322 this->postprocessPostSolve();
8323 RECORD_TIMER_STOP(m_timers[Timers::Run]);
8324}
8325
8326
8327// Explicit instantiations for 2D and 3D
8328template class FvStructuredSolver<2>;
8329template class FvStructuredSolver<3>;
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
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
Base class of the structured solver.
void saveSolution(MBool)
Saves the soution to hdf5 file.
virtual MFloat getBlasiusEta(MFloat coordX, MFloat coordY)
MBool isPeriodicComm(std::unique_ptr< StructuredComm< nDim > > &)
void saveDissipation(MString, MFloat *)
Writes the dissipation into a given file.
void setInputOutputProperties()
Reads properties and initializes variables associated with input/output.
std::unique_ptr< FvStructuredSolverWindowInfo< nDim > > m_windowInfo
MInt timer(const MInt timerId) const
void initializeFvStructuredSolver(MBool *propertiesGroups)
Structured Solver Constructor reads and allocate properties/variables.
void checkNans()
Checks whole domain for NaNs and adds the number of NaNs globally.
virtual void initStructuredPostprocessing()
PostProcessingSolver interface:
void receive(const MBool, std::vector< std::unique_ptr< StructuredComm< nDim > > > &, std::vector< MPI_Request > &)
FvStructuredSolver(MInt solverId, StructuredGrid< nDim > *, MBool *propertiesGroups, const MPI_Comm comm)
Constructor of the structured solver.
void postTimeStep() override
: Performs the post time step
void saveSolverSolution(MBool=false, const MBool=false) override
MFloat pythag(MFloat a, MFloat b)
void send(const MBool, std::vector< std::unique_ptr< StructuredComm< nDim > > > &, std::vector< MPI_Request > &)
void loadRestartFile()
Load Restart File (primitive and conservative output) general formulation.
void saveGradients(MString, MFloat **, MString *)
Writes the gradients into a given file.
virtual void initBlasius()
Init for Blasius boundary layer.
void getDomainDecompositionInformation(std::vector< std::pair< MString, MInt > > &domainInfo) override
Return decomposition information, i.e. number of local elements,...
void saveForcesToAsciiFile(MBool)
Function to save the force coefficients and power to an ASCII file.
MFloat computeRecConstSVD(const MInt ijk, const MInt noNghbrIds, MInt *nghbr, MInt ID, MInt sID, MFloatScratchSpace &tmpA, MFloatScratchSpace &tmpC, MFloatScratchSpace &weights, const MInt recDim)
AUX DATA ENDS /////////////////////////////////////////////////////////////.
MBool skipPeriodicDirection(std::unique_ptr< StructuredComm< nDim > > &)
void tred2(MFloatScratchSpace &A, MInt dim, MFloat *diag, MFloat *offdiag)
Householder Reduction according to Numercial Recipies in C: The Art of Scientific Computing.
void getSolverTimings(std::vector< std::pair< MString, MFloat > > &solverTimings, const MBool allTimings) override
Get solver timings.
void setBodyForceProperties()
Reads and initializes properties associated with the Moving Grid Methods.
std::array< MInt, Timers::_count > m_timers
void finalizeInitSolver() override
virtual void saveAverageRestart()
void setMovingGridProperties()
Reads and initializes properties associated with the Moving Grid Methods.
std::vector< std::unique_ptr< StructuredComm< nDim > > > m_sndComm
StructuredGrid< nDim > * m_grid
MInt determineRestartTimeStep() const override
Load the restart time step from the restart file (useNonSpecifiedRestartFile enabled)
virtual void computeConservativeVariables()
void shiftCellValuesRestart(MBool)
MBool loadBoxFile(MString, MString, MInt, MInt)
Load Box file general formulation.
SingularInformation * m_singularity
void convertRestartVariables(MFloat oldMa)
void saveAveragedVariables(MString, MInt, MFloat **)
Saves the averaged (mean) variables from postprocessing to an HDF5 file.
void savePartitions()
Saves the partitioned grid into an HDF5 file. Not used in production use but useful for debugging.
virtual void getBlasiusVelocity(MInt cellId, MFloat *const vel)
Load variables for the specified timeStep.
void saveProductionTerms(MString, MFloat **)
Writes the production terms into a given file.
virtual MFloat getFscEta(MFloat coordX, MFloat coordY)
std::unique_ptr< MPrimitiveVariables< nDim > > PV
void setRungeKuttaProperties()
This function reads the properties required for Runge Kutta time stepping.
void saveForceCoefficient(ParallelIoHdf5 *parallelIoHdf5)
Saves force coefficients to an HDF5 file.
void setZonalProperties()
Set which zones are RANS and which are LES or if full LES or full RANS.
virtual void initFsc()
Init for Falkner-Skan-Cooke flow.
void setTestcaseProperties()
Reads and initializes properties associated with the Testcase.
void setNumericalProperties()
Reads and initializes properties associated with the numerical method.
virtual MFloat getFscPressure(MInt cellId)
void tqli2(MFloat *diag, MFloat *offdiag, MInt dim)
Compute Eigenvalues with implicit shift according to Numercial Recipies in C: The Art of Scientific C...
void computeForceCoef()
Function to compute the force coefficient cl, split split into the viscous part cLv and the pressure ...
virtual void writePropertiesAsAttributes(ParallelIoHdf5 *pio, MString path)
Overloaded version of writePropertiesAsAttributes that receives ParallelIoHdf5 object pointer instead...
void initializeFQField()
Counts the number of necessary FQ fields, allocates them and corrects the indexes of the FQ variable ...
void initSolver() override
void exchange()
SVD STUFF ENDS /////////////////////////////////////////////////////////////.
void setPorousProperties()
Set properties for porous blocks.
std::vector< std::unique_ptr< StructuredComm< nDim > > > m_rcvComm
MBool solutionStep() override
virtual void getFscVelocity(MInt cellId, MFloat *const vel)
Load variables for the specified timeStep.
void resetRHS()
Reset the right hand side to zero.
void computeForceCoefRoot()
Function to compute the coefficient, split split into the viscous part cLv and the pressure part cLp ...
void allocateAuxDataMaps()
AUX DATA //////////////////////////////////////////////////////////////////.
void insertSort(MInt dim, MFloat *list)
Sorting function to sort list in ascending order.
virtual void writeHeaderAttributes(ParallelIoHdf5 *pio, MString fileType)
Overloaded version of writeHeaderAttributes that receives ParallelIoHdf5 object pointer instead of 'f...
StructuredCell * m_cells
void saveVarToPrimitive(MInt, MInt, MFloat)
void open(const MString &filename, const MString &projectName, MInt fileType=0, MPI_Comm mpiComm=MPI_COMM_WORLD, MBool rootOnlyHardwired=false)
Opens a file by passing the parameters to InfoOut_<xyz>FileBuffer::open(...).
Definition: infoout.cpp:975
void defineArray(maiabd_type type, const MString &name, size_type totalCount)
Create a new array in the file.
Definition: parallelio.h:783
void writeArray(const T *array, const MString &name, size_type memoryStride=-1, size_type diskStride=-1)
Write array data to file. [MPI]
Definition: parallelio.h:1046
MBool hasDataset(const MString &name, MInt dimension)
Check if the file contains an dataset with the given name and dimension.
Definition: parallelio.h:467
void getAttribute(T *value, const MString &name, const MString &datasetName="")
Retrieve a file or dataset attribute.
Definition: parallelio.h:1788
void setAttribute(const T &value, const MString &name, const MString &datasetName="")
Set a file or dataset attribute. [MPI]
Definition: parallelio.h:1438
void readArray(T *array, const MString &name, size_type memoryStride=-1, size_type diskStride=-1)
Read array data from file. [MPI]
Definition: parallelio.h:1523
static size_t getTotalMemory()
Returns the amount of total available memory in scratch.
Definition: scratch.h:157
This class is a ScratchSpace.
Definition: scratch.h:758
void fill(T val)
fill the scratch with a given value
Definition: scratch.h:311
iterator begin()
Definition: scratch.h:273
Parent class of all solvers This class is the base for all solvers. I.e. all solver class (e....
Definition: solver.h:29
virtual MInt domainId() const
Return the domainId (rank)
Definition: solver.h:383
const MInt m_solverId
a unique solver identifier
Definition: solver.h:90
virtual MInt noDomains() const
Definition: solver.h:387
MFloat ** pvariables
Structured grid class.
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
@ PERIODIC_BC_SINGULAR
Definition: enums.h:343
@ PERIODIC_BC
Definition: enums.h:343
@ EULER
Definition: enums.h:176
RansMethod
Definition: enums.h:51
@ RANS_SA_DV
Definition: enums.h:54
@ RANS_KEPSILON
Definition: enums.h:58
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW2(const Real x)
Definition: functions.h:119
Real ABS(const Real x)
Definition: functions.h:85
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
constexpr T mMax(const T &x, const T &y)
Definition: functions.h:94
MInt noRansEquations(RansMethod ransMethod)
MInt globalTimeStep
void printAllocatedMemory(const MLong oldAllocatedBytes, const MString &solverName, const MPI_Comm comm)
Prints currently allocated memory.
InfoOutFile m_log
int32_t MInt
Definition: maiatypes.h:62
uint32_t MUint
Definition: maiatypes.h:63
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
int64_t MLong
Definition: maiatypes.h:64
bool MBool
Definition: maiatypes.h:58
char MChar
Definition: maiatypes.h:56
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_Allgatherv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, const int recvcounts[], const int displs[], MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgatherv
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request, const MString &name, const MString &varname)
same as MPI_Irecv
int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm, const MString &name, const MString &varname)
same as MPI_Comm_create, but updates the number of MPI communicators
int MPI_Group_incl(MPI_Group group, int n, const int ranks[], MPI_Group *newgroup, const MString &name)
same as MPI_Group_incl
int MPI_Comm_group(MPI_Comm comm, MPI_Group *group, const MString &name, const MString &varname)
same as MPI_Comm_group
int MPI_Waitall(int count, MPI_Request *request, MPI_Status *status, const MString &name)
same as MPI_Waitall
int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Reduce
int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allreduce
int MPI_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_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather
void const MInt cellId
Definition: collector.h:239
T cos(const T a, const T b, const T x)
Cosine slope filter.
Definition: filter.h:125
void invert(MFloat *A, const MInt m, const MInt n)
Definition: maiamath.cpp:171
const MInt PIO_REPLACE
Definition: parallelio.h:36
const MInt PIO_APPEND
Definition: parallelio.h:38
const MInt PIO_FLOAT
Definition: parallelio.h:46
const MInt PIO_READ
Definition: parallelio.h:40
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292
Definition: contexttypes.h:19
define array structures