MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
postprocessingfv.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The m-AIA AUTHORS
2//
3// This file is part of m-AIA (https://git.rwth-aachen.de/aia/m-AIA/m-AIA)
4//
5// SPDX-License-Identifier: LGPL-3.0-only
6
7#include "postprocessingfv.h"
8//#include "postprocessing.h"
9#include "postprocessing.cpp"
10
11using namespace std;
12
13template <MInt nDim, class SysEqn>
15 PostData<nDim>* data,
17 : PostProcessingInterface(postprocessingId_),
18 PostProcessing<nDim, PostProcessingFv<nDim, SysEqn>>(postprocessingId_, data) {
19 m_ppSolver = ppSolver_;
20}
21
22
23template <MInt nDim, class SysEqn>
25
26template <MInt nDim, class SysEqn>
28 TRACE();
29
31
32 solver().m_skewness = this->m_skewness;
33 solver().m_kurtosis = this->m_kurtosis;
34 solver().m_activeMeanVars = this->m_activeMeanVars;
35
36 // for(MInt i = 0; i < (signed)this->m_activeMeanVars.size(); i++){
37 // solver().m_activeMeanVars.insert(this->m_activeMeanVars[i]);
38 // }
39}
40
41
42template <MInt nDim, class SysEqn>
44 TRACE();
45 m_pointData.reset(new PointData<nDim, SolverType>{*m_ppSolver});
46 m_pointData->setInputOutputProperties();
47 m_pointData->init();
48}
49
50template <MInt nDim, class SysEqn>
52 if(!isActive()) return;
53 m_pointData->save(m_finalTimeStep);
54}
55
56template <MInt nDim, class SysEqn>
58 TRACE();
59 m_surfaceData.reset(new SurfaceData<nDim, SolverType>{*m_ppSolver});
60 m_surfaceData->setInputOutputProperties();
61 m_surfaceData->init();
62}
63
64template <MInt nDim, class SysEqn>
66 if(!isActive()) return;
67 m_surfaceData->save(m_finalTimeStep);
68}
69
70template <MInt nDim, class SysEqn>
72 TRACE();
73 m_volumeData.reset(new VolumeData<nDim, SolverType>{*m_ppSolver});
74 m_volumeData->setInputOutputProperties();
75 m_volumeData->init();
76}
77
78template <MInt nDim, class SysEqn>
80 if(!isActive()) return;
81 m_volumeData->save(m_finalTimeStep);
82}
83
84template <MInt nDim, class SysEqn>
86 TRACE();
87
89
90 solver().m_movingAvgInterval = this->m_movingAverageInterval;
91}
92
93template <MInt nDim, class SysEqn>
95 TRACE();
96
98
99 solver().m_averageVorticity = this->m_averageVorticity;
100 solver().m_averageSpeedOfSound = this->m_averageSpeedOfSound;
101}
102
103
104template <MInt nDim, class SysEqn>
106 TRACE();
107
108 if(!solver().grid().isActive()) return;
109
110 if(m_postprocessFileName != "") {
111 m_log << " ^ * probe line for file " << m_postprocessFileName << endl;
112 // TERMM(1, "FIXME untested");
113 IF_CONSTEXPR(SysEqn::m_noRansEquations == 0) postData().loadMeanFile(m_postprocessFileName);
114 probeLinePeriodic();
115 } else {
116 for(MInt t = m_averageStartTimestep; t <= m_averageStopTimestep; t += m_averageInterval) {
117 solver().loadSampleVariables(t);
118 probeLinePeriodic();
119 }
120 }
121}
122
123template <MInt nDim, class SysEqn>
125 TRACE();
126
127 using namespace maia::parallel_io;
128
129 // check for average timestep or postprocessFileName
130 if((globalTimeStep >= m_averageStartTimestep && (globalTimeStep - m_averageStartTimestep) % m_averageInterval == 0
131 && globalTimeStep <= m_averageStopTimestep)
132 || globalTimeStep == 0) {
133 MInt noVars = m_noVariables;
134 if(m_postData->isMeanFile()) {
135 noVars = m_postData->fileNoVars();
136 }
137
138 MInt step = (m_postData->isMeanFile()) ? 0 : globalTimeStep;
139 stringstream fileName;
140 fileName << solver().outputDir() << "probeLines_" << step << ParallelIo::fileExt();
141 ParallelIo parallelIo(fileName.str(), maia::parallel_io::PIO_REPLACE, solver().mpiComm());
142
143 // define all arrays in output file
144 for(MInt probeLineId = 0; probeLineId < m_noProbeLines; probeLineId++) {
145 stringstream varNameBase;
146 varNameBase << "line_" << probeLineId;
147 string coordName = varNameBase.str() + "_coordinates";
148
149 parallelIo.defineArray(PIO_FLOAT, coordName, m_globalNoProbeLineIds[probeLineId]);
150 parallelIo.setAttribute(probeLineId, "lineId", coordName);
151
152 varNameBase << "_var_";
153 for(MInt varId = 0; varId < noVars; varId++) {
154 stringstream varName;
155 varName << varNameBase.str() << varId;
156 parallelIo.defineArray(PIO_FLOAT, varName.str(), m_globalNoProbeLineIds[probeLineId]);
157 parallelIo.setAttribute(probeLineId, "lineId", varName.str());
158 }
159 }
160
161 for(MInt probeLineId = 0; probeLineId < m_noProbeLines; probeLineId++) {
162 if(m_probeLineDirection[probeLineId] < 0 || m_probeLineDirection[probeLineId] >= nDim) {
163 continue;
164 }
165
166 m_log << " ^ * probe line timestep " << globalTimeStep << " for line #" << probeLineId << endl;
167
168 MInt noIds = m_noProbeLineIds[probeLineId];
169 if(noIds == 0) {
170 noIds = 1;
171 } // avoid dereferencing array with length 0 in writeArray(...)
172 ScratchSpace<MFloat> vars(noVars * noIds, "vars", FUN_);
173
174 MInt probeId;
175 const MFloat* cellVars = 0;
176
177 // collect local variables
178 for(MInt i = 0; i < m_noProbeLineIds[probeLineId]; i++) {
179 probeId = m_probeLineIds[probeLineId][i];
180 PostProcessing<nDim, PostProcessingFv<nDim, SysEqn>>::getSampleVariables(probeId, cellVars, false);
181 for(MInt varId = 0; varId < noVars; varId++) {
182 vars[i * noVars + varId] = cellVars[varId];
183 }
184 }
185
186 parallelIo.setOffset(m_noProbeLineIds[probeLineId], m_probeLineOffsets[probeLineId]);
187
188 // write to file
189 stringstream varNameBase;
190 varNameBase << "line_" << probeLineId;
191 string coordName = varNameBase.str() + "_coordinates";
192 parallelIo.writeArray(m_probeLinePositions[probeLineId], coordName);
193
194 varNameBase << "_var_";
195 for(MInt varId = 0; varId < noVars; varId++) { // write all variables to file
196 stringstream varName;
197 varName << varNameBase.str() << varId;
198 parallelIo.writeArray(&(vars[varId]), varName.str(), noVars);
199 }
200 }
201 } else {
202 // PROBE_LINE_POST
203 //--------------------------------------------------------------------------
204 //--------------------------------------------------------------------------
205
206 for(MInt probeLineId = 0; probeLineId < m_noProbeLines; probeLineId++) {
207 if(m_probeLineAverageDirection[probeLineId] < 0 || m_probeLineAverageDirection[probeLineId] >= nDim) {
208 continue;
209 }
210
211 MInt probeId;
212
213 if(m_probeLineDirection[probeLineId] == 1 || m_probeLineDirection[probeLineId] == 0) {
214 MInt noVars;
215 if(solver().m_rans) {
216 noVars = m_noVariables + 1; // k
217 } else {
218 noVars = postData().noVariables();
219 }
220
221 MInt noIds = m_globalNoProbeLineIds[probeLineId];
222 if(noIds == 0) {
223 noIds = 1;
224 }
225
226 // ScratchSpace<MFloat> vars( noVars*ids, "vars", FUN_ );
227 ScratchSpace<MFloat> avgVars(noVars * noIds, "avgVars", FUN_);
228 ScratchSpace<MFloat> globalAvgVars(noVars * noIds, "globalAvgVars", FUN_);
229 avgVars.fill(F0);
230 globalAvgVars.fill(F0);
231
232 if(solver().m_rans) {
233 // RANS SOLVER
234 for(MInt p = 0; p < m_globalNoProbeLineIds[probeLineId]; p++) {
235 // collect local variables
236 for(MInt i = 0; i < m_noProbeLineAverageIds[probeLineId][p]; i++) {
237 probeId = m_probeLineAverageIds[probeLineId][p][i];
238 const MFloat* cellVars = 0;
239 PostProcessing<nDim, PostProcessingFv<nDim, SysEqn>>::getSampleVariables(probeId, cellVars, false);
240
241 // RANS Variables
242 for(MInt varId = 0; varId < m_noVariables; varId++) {
243 avgVars[p * noVars + varId] += cellVars[varId];
244 }
245
246 // turbulent kinetic energy
247 MFloat k = F0;
248 const MFloat* cellVarsDeriv1;
249 getSampleVarsDerivatives(probeId, cellVarsDeriv1);
250 const MFloatTensor deriv1(const_cast<MFloat*>(cellVarsDeriv1), m_noVariables, nDim);
251 MFloat SijSij = F0;
252 for(MInt d1 = 0; d1 < nDim; d1++) {
253 for(MInt d2 = 0; d2 < nDim; d2++) {
254 MFloat sij = 0.5 * (deriv1(d1, d2) + deriv1(d2, d1));
255 SijSij += sij * sij;
256 }
257 }
258
259 k = sqrt(2.0 * SijSij / 0.09) * cellVars[5] / solver().sysEqn().m_Re0;
260
261 avgVars[p * noVars + m_noVariables] += k;
262 }
263 }
264 } else {
265 // LES SOLVER
266 for(MInt p = 0; p < m_globalNoProbeLineIds[probeLineId]; p++) {
267 // collect local variables
268 for(MInt i = 0; i < m_noProbeLineAverageIds[probeLineId][p]; i++) {
269 // const MFloat* cellVars = 0;
270 probeId = m_probeLineAverageIds[probeLineId][p][i];
271 // PostProcessingBlock<nDim, Block>::getSampleVariables( probeId, cellVars );
272 MInt dataId = convertIdParent(solver(), postData(), probeId);
273 if(dataId != -1) {
274 for(MInt varId = 0; varId < noVars; varId++) {
275 avgVars[p * noVars + varId] += postData().m_averagedVars[dataId][varId];
276 }
277
278 // SijSij
279 // calculating strain rate tensor Sij = 0.5(dui/dxj + duj/dxi)
280 std::vector<std::vector<MFloat>> du(nDim, std::vector<MFloat>(nDim, F0));
281 const MInt recData = solver().a_reconstructionData(probeId);
282 std::vector<MFloat> u{postData().m_averagedVars[dataId][0], postData().m_averagedVars[dataId][1],
283 postData().m_averagedVars[dataId][2]};
284
285 for(MInt nghbr = 0; nghbr < solver().a_noReconstructionNeighbors(probeId); nghbr++) {
286 const MInt recNghbrId = solver().a_reconstructionNeighborId(probeId, nghbr);
287 if(recNghbrId > -1 && recNghbrId < solver().noInternalCells()) {
288 MInt dataNgbhrId = convertIdParent(solver(), postData(), recNghbrId);
289 if(dataNgbhrId > -1) {
290 // std::ignore = recData;
291 // std::ignore = u;
292 const MFloat recConst_x = solver().m_reconstructionConstants[nDim * (recData + nghbr) + 0];
293 const MFloat recConst_y = solver().m_reconstructionConstants[nDim * (recData + nghbr) + 1];
294 const MFloat recConst_z = solver().m_reconstructionConstants[nDim * (recData + nghbr) + 2];
295 for(MInt dim = 0; dim < nDim; ++dim) {
296 MFloat delta_u = postData().m_averagedVars[dataNgbhrId][dim] - u[dim];
297 du[dim][0] += recConst_x * delta_u;
298 du[dim][1] += recConst_y * delta_u;
299 du[dim][2] += recConst_z * delta_u;
300 }
301 }
302 }
303 }
304 std::vector<std::vector<MFloat>> sij(nDim, std::vector<MFloat>(nDim, F0));
305 MFloat SijSij = F0;
306 for(MInt d1 = 0; d1 < nDim; d1++) {
307 for(MInt d2 = 0; d2 < nDim; d2++) {
308 sij[d1][d2] = 0.5 * (du[d1][d2] + du[d2][d1]);
309 SijSij += sij[d1][d2] * sij[d1][d2];
310 }
311 }
312 avgVars[p * noVars + (noVars - 1)] += SijSij;
313 }
314 }
315 }
316 }
317
318 MPI_Allreduce(&avgVars[0], &globalAvgVars[0], noVars * noIds, MPI_DOUBLE, MPI_SUM, solver().mpiComm(), AT_,
319 "avgVars", "globalAvgVars");
320
321
322 if(solver().domainId() == 0) {
323 // Calculate spanwise average
324 //--------------------------------------------------------------------
325 MInt tempId = 0;
326 for(MInt p = 0; p < m_globalNoProbeLineIds[probeLineId]; p++) {
327 for(MInt varId = 0; varId < noVars; varId++) {
328 m_globalProbeLineAverageVars[probeLineId][p][varId] =
329 globalAvgVars[tempId] / m_globalNoProbeLineAverageIds[probeLineId][p];
330 tempId++;
331 }
332 }
333
334 // vector<MInt> outputIds;
335 // if(solver().m_rans) {
336 // outputIds = {0, 1, 2, 3, 4, 5, 6};
337 // } else {
338 // outputIds = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
339 // }
340 //--------------------------------------------------------------------
341
342
343 // OUTPUT
344 //--------------------------------------------------------------------
345 // Sorting
346 ScratchSpace<MFloat> sorting(m_globalNoProbeLineIds[probeLineId], "sorting", FUN_);
347 vector<int> sortingIndex(m_globalNoProbeLineIds[probeLineId]);
348 for(MInt p = 0; p < m_globalNoProbeLineIds[probeLineId]; p++) {
349 sorting[p] = m_probeLineAverageCoordinates[probeLineId][p];
350 }
351 int x = 0;
352 iota(sortingIndex.begin(), sortingIndex.end(), x++); // Initializing
353 sort(sortingIndex.begin(), sortingIndex.end(), [&](int i, int j) { return sorting[i] < sorting[j]; });
354
355 // Write text file
356 MString dir;
357 if(solver().m_rans) {
358 dir = "#y um vm wm rhom pm num ym k";
359 } else {
360 if(solver().m_solverId == 1) {
361 dir = "#y um vm wm rhom pm num ym u'u' u'v' u'w' v'v' v'w' w'w' p'";
362 } else {
363 dir = "#y um vm wm rhom pm u'u' u'v' u'w' v'v' v'w' w'w' p' SijSij";
364 }
365 }
366 ofstream lineprob;
367 lineprob.precision(8);
368 MString fname = "probeLine" + to_string(solver().m_solverId) + "_" + to_string(probeLineId) + "_"
369 + to_string(globalTimeStep) + ".txt";
370 cerr << "Writing " << fname << endl;
371 lineprob.open(fname);
372 for(MInt p = 0; p < m_globalNoProbeLineIds[probeLineId]; p++) {
373 MInt index = sortingIndex[p];
374 MString line = "";
375 line.append(to_string(m_probeLineAverageCoordinates[probeLineId][index]));
376 if(p == 0) lineprob << dir << endl;
377 for(MInt k = 0; k < noVars; k++) {
378 MInt varId = k; // outputIds[k];
379 line.append(" " + to_string(m_globalProbeLineAverageVars[probeLineId][index][varId]));
380 }
381 lineprob << line << endl;
382 }
383 lineprob.close();
384 //--------------------------------------------------------------------
385 }
386 } else if(m_probeLineDirection[probeLineId] == 2) {
387 //
388 }
389 }
390 }
391}
392
393template <MInt nDim, class SysEqn>
395 TRACE();
396
398
399 if(solver().domainId() == 0) {
400 cerr << "Allocating Post-processing Fv data!" << endl;
401 }
402
403 const MInt vapourPenSize = nDim == 3 ? 16 : 12;
404 mAlloc(m_vapourPen, m_sprayDataSize, vapourPenSize, "m_vapourPen", F0, AT_);
405 mAlloc(m_vapourCV, m_sprayDataSize, 5 + 2 * nDim, "m_vapourCV", F0, AT_);
406}
407
408template <MInt nDim, class SysEqn>
410 TRACE();
411
412 // calculate dimensionless vapour information from finite volume solver
413 const MBool hasSpecies = solver().m_noSpecies > 0 ? true : false;
414
415 // reset
416 for(MInt i = 0; i < 5 + 2 * nDim; i++) {
417 m_vapourCV[m_sprayDataStep][i] = 0;
418 }
419
420 if(solver().isActive()) {
421 for(MInt cellId = 0; cellId < solver().noInternalCells(); cellId++) {
422 if(!solver().c_isLeafCell(cellId)) continue;
423 if(solver().a_isInactive(cellId)) continue;
424 const MFloat cellV = 1 / solver().a_FcellVolume(cellId);
425 const MFloat rho = solver().a_variable(cellId, solver().m_sysEqn.CV->RHO);
426 const MFloat rhoY = hasSpecies ? solver().a_variable(cellId, solver().m_sysEqn.CV->RHO_Y[speciesId]) : 0;
427
428 m_vapourCV[m_sprayDataStep][0] += cellV * rhoY;
429 m_vapourCV[m_sprayDataStep][1] += cellV * (rho - rhoY);
430 m_vapourCV[m_sprayDataStep][2] += cellV * solver().a_variable(cellId, solver().m_sysEqn.CV->RHO_E);
431 m_vapourCV[m_sprayDataStep][3] += cellV * solver().a_variable(cellId, solver().m_sysEqn.CV->RHO_U);
432 m_vapourCV[m_sprayDataStep][4] += cellV * solver().a_variable(cellId, solver().m_sysEqn.CV->RHO_V);
433 IF_CONSTEXPR(nDim == 3) {
434 m_vapourCV[m_sprayDataStep][5] += cellV * solver().a_variable(cellId, solver().m_sysEqn.CV->RHO_W);
435 }
436 }
437 if(solver().m_hasExternalSource) {
438 MInt numVars = 2 + nDim;
439 for(MInt i = 0; i < numVars; i++) {
440 MFloat source = (solver().m_vapourData.find(globalTimeStep)->second)[i];
441 m_vapourCV[m_sprayDataStep][3 + nDim + i] = source;
442 }
443 }
444 }
445}
446
447template <MInt nDim, class SysEqn>
449 TRACE();
450
451 const MInt noYLimits = 3;
452 const MInt refLvl = 10;
453 const MFloat yLimitRefLvl = 0.001;
454
455 // concentration limits for differecent penetration lengths
456 array<MFloat, noYLimits> yLimits{};
457 yLimits[0] = 0.001;
458 yLimits[1] = 0.01;
459 yLimits[2] = 0.05;
460
461 // x,y,z, axial penetration and distance
462 array<array<MFloat, noYLimits>, nDim + 1> maxVapPen{};
463 array<MFloat, nDim> maxVapPenRefLvl{};
464 for(MInt n = 0; n < noYLimits; n++) {
465 for(MInt i = 0; i < nDim + 1; i++) {
466 maxVapPen[i][n] = 0.0;
467 }
468 }
469 for(MInt i = 0; i < nDim; i++) {
470 maxVapPenRefLvl[i] = 0.0;
471 }
472
473 auto assignLarger = [&](MFloat& A, MFloat b) {
474 if(b > A) {
475 A = b;
476 }
477 };
478
479 const MBool hasSpecies = solver().m_noSpecies > 0 ? true : false;
480
481 if(solver().isActive() && hasSpecies) {
482 for(MInt cellId = 0; cellId < solver().noInternalCells(); cellId++) {
483 if(solver().a_isInactive(cellId)) continue;
484 if(solver().c_isLeafCell(cellId)) {
485 const MFloat rho = solver().a_variable(cellId, nDim + 1);
486 const MFloat Y = hasSpecies ? solver().a_variable(cellId, nDim + 2) / rho : 0;
487 array<MFloat, nDim> centerCoords{};
488
489 for(MInt n = 0; n < noYLimits; n++) {
490 if(Y > yLimits[n]) {
491 for(MInt i = 0; i < nDim; i++) {
492 centerCoords[i] = solver().a_coordinate(cellId, i);
493 }
494 array<MFloat, nDim + 1> distance{};
495 for(int i = 0; i < nDim; i++) {
496 distance[i] = abs(centerCoords[i] - spawnCoord[i]);
497 }
498 distance[nDim] = maia::math::distance(centerCoords, spawnCoord);
499
500 for(int i = 0; i < nDim + 1; i++) {
501 assignLarger(maxVapPen[i][n], distance[i]);
502 }
503 } else {
504 break;
505 }
506 }
507 } else {
508 if(solver().a_level(cellId) == refLvl) {
509 solver().reduceData(cellId, &solver().a_variable(0, 0), solver().CV->noVariables);
510 const MFloat rho = solver().a_variable(cellId, nDim + 1);
511 const MFloat Y = hasSpecies ? solver().a_variable(cellId, nDim + 2) / rho : 0;
512 if(Y > yLimitRefLvl) {
513 for(MInt i = 0; i < nDim; i++) {
514 assignLarger(maxVapPenRefLvl[i], solver().a_coordinate(cellId, i));
515 }
516 }
517 }
518 }
519 }
520 }
521
522 // save data:
523 MInt it = 0;
524 for(MInt n = 0; n < noYLimits; n++) {
525 // absolute distance
526 m_vapourPen[m_sprayDataStep][it++] = maxVapPen[nDim][n];
527 // x/y/z-distance
528 for(MInt i = 0; i < nDim; i++) {
529 m_vapourPen[m_sprayDataStep][it++] = maxVapPen[i][n];
530 }
531 }
532 for(MInt i = 0; i < nDim; i++) {
533 m_vapourPen[m_sprayDataStep][it++] = maxVapPenRefLvl[i];
534 }
535}
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
This class is responsible for the point data feature. It records the state of all sampling variables ...
Definition: samplingdata.h:164
Definition: postdata.h:23
virtual ~PostProcessingFv()
void initSurfaceSamplingData() override
void probeLinePeriodic() override
void savePointSamplingData() override
void vapourPenetration(MFloat spawnCoord[nDim])
void initVolumeSamplingData() override
void initAveragingProperties() override
Initialize properties relevant for temporal averaging.
void probeLinePeriodicPost() override
void saveVolumeSamplingData() override
SolverType * m_ppSolver
void initPointSamplingData() override
void saveSurfaceSamplingData() override
void initPostProcessing() override
void vapourMass(const MInt)
PostProcessingFv(MInt postprocessingId_, PostData< nDim > *data, SolverType *ppSolver_)
void initSprayData() override
void initMovingAverage() override
Initializes properties and allocates memory for moving averaging.
This class is a ScratchSpace.
Definition: scratch.h:758
void fill(T val)
fill the scratch with a given value
Definition: scratch.h:311
Surface data sampling class. Records all sampling variables on all surface elements and outputs addit...
Definition: samplingdata.h:190
Class to handle sampling of volume data.
Definition: samplingdata.h:220
MInt convertIdParent(SolverA &solverA, SolverB &solverB, const MInt solverAId)
Conversion from solverA id to the solverB id If no cell on the same level is found,...
Definition: couplingutils.h:46
MInt globalTimeStep
InfoOutFile m_log
int32_t MInt
Definition: maiatypes.h:62
std::basic_string< char > MString
Definition: maiatypes.h:55
double MFloat
Definition: maiatypes.h:52
bool MBool
Definition: maiatypes.h:58
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
MFloat distance(const MFloat *a, const MFloat *b)
Definition: maiamath.h:249
const MInt PIO_REPLACE
Definition: parallelio.h:36
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292