MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
dgccacousticperturbsourcefiles.h
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#ifndef DGCOUPLINGCONDITIONACOUSTICPERTURB_H_
8#define DGCOUPLINGCONDITIONACOUSTICPERTURB_H_
9
10#include <algorithm>
11#include <iostream>
12#include <limits>
13#include <sstream>
14#include <type_traits>
15#include "COMM/mpioverride.h"
20#include "IO/context.h"
21#include "IO/parallelio.h"
22#include "UTIL/timer.h"
23#include "coupling.h"
24#include "couplingdgape.h"
25#include "typetraits.h"
26
27class Solver;
28template <MInt nDim, class SysEqn>
30
31template <MInt nDim, class SysEqn>
39template <MInt nDim, class FvSysEqn>
40class DgCcAcousticPerturb final : public CouplingDgApe<nDim, CouplingFv<nDim, FvSysEqn>> {
41 // Typedefs
42 public:
43 using Base = Coupling;
44
47 using BaseFv::fvSolver;
48
50 using BaseDg::dgSolver;
66 using BaseDg::m_timers;
71 using BaseDg::sysEqn;
74 using CV = typename BaseDg::CV;
75 using MV = typename BaseDg::MV;
76 using ST = typename BaseDg::ST;
77 using SysEqn = typename BaseDg::SysEqn;
78 using Timers = typename BaseDg::Timers;
79
80 // TODO labels:COUPLER,DG use couplingId instead of solverId to request coupling related properties?
81 using BaseDg::solverId;
82
83 // Methods
84 DgCcAcousticPerturb(const MInt couplingId, FvCartesianSolverType* fvSolver_, DgCartesianSolverType* const dgSolver_)
85 : Base(couplingId), BaseDg(couplingId, dgSolver_, fvSolver_) {}
86 virtual ~DgCcAcousticPerturb();
87
88 // Main coupling functions
89 void init() override {
92 };
93
94 void finalizeCouplerInit() override { calcTimeStep(); };
95
97 void balancePre() override {
98 m_loadBalancingReinitStage = 0; // Set reinitialization stage
99 this->initCoupler(); // Perform main (re-)initialization of coupler
100 };
101 void balancePost() override {
102 // Nothing to be done here
103 m_loadBalancingReinitStage = -1; // Reset reinitialization stage
104 };
105
107 MInt noCellDataDlb() const override {
108 return 1; // One (float) data field to communicate
109 };
110 MInt cellDataTypeDlb(const MInt dataId) const override {
111 TERMM_IF_NOT_COND(dataId == 0, "invalid data id");
112 return MFLOAT;
113 };
114 MInt cellDataSizeDlb(const MInt NotUsed(dataId), const MInt NotUsed(cellId)) override;
115 // Note: not-templated, only MFloat version required here
116 void getCellDataDlb(const MInt dataId, const MInt oldNoCells, const MInt* const bufferIdToCellId,
117 MFloat* const data) override;
118 void setCellDataDlb(const MInt NotUsed(dataId), const MFloat* const NotUsed(data)) override;
119
121 MBool forceTimeStep() const { return true; }
122
123 private:
124 void sanityCheck();
125
126 FvCartesianSolverType& donorSolver(const MInt xSolverId = 0) const override { return fvSolver(xSolverId); };
127 void getDonorVelocityAndVorticity(const std::vector<MInt>& donorCellIds, MFloatScratchSpace& p_velocity,
128 MFloatScratchSpace& p_vorticity) override;
129
131 void calcSourceLambLinearized(const MFloat* const velocity, const MFloat* const vorticity,
132 MFloat* sourceTerms) override;
133 void calcSourceLambNonlinear(const MFloat* const velocity, const MFloat* const vorticity,
134 MFloat* const sourceTerms) override;
135 void calcSourceQmII(const MFloat* const velocity, MFloat* const sourceTerms) override;
136 void calcSourceQmIII(const MFloat* const velocity, MFloat* sourceTerms) override;
137 void calcSourceQe(const MFloat* const velocity, const MFloat time, MFloat* const sourceTerms) override;
138 void calcSourceQc(const MFloat* const velocity, MFloat* const sourceTerms, const MFloat time,
139 const MInt timeStep) override;
140
141 // Properties: file and variable names
142 // File name pattern for instantaneous data files
143 // MString m_instantaneousDataFileNamePattern{};
144 // Field width for time step in file name pattern for instantaneous data files
145 // MInt m_instantaneousDataFileNamePatternWidth;
146 // Names of instantaneous velocity variables in solution files
147 // labels:COUPLER Note: the default initializer '{}' was omitted due to a bug in GCC 4.9.x
148 // std::array<MString, noVelocities()> m_instantaneousVelocitiesVarNames;
149 // Names of instantaneous vorticity variables in solution files
150 // labels:COUPLER Note: the default initializer '{}' was omitted due to a bug in GCC 4.9.x
151 // std::array<MString, noVorticities()> m_instantaneousVorticitiesVarNames;
152
153
155
156 std::vector<MFloat> m_oldPressure{};
157};
158
163template <MInt nDim, class FvSysEqn>
165 TRACE();
166
167 MFloat maxGlobalConservationError = -1.0;
168 MFloat maxGlobalL2Error = -1.0;
169
170 // Compute global maximum conservation error if activated
171 if(m_checkConservation && m_hasDgCartesianSolver) {
172 MPI_Allreduce(&m_maxConservationError, &maxGlobalConservationError, 1, maia::type_traits<MFloat>::mpiType(),
173 MPI_MAX, dgSolver().mpiComm(), AT_, "m_maxConservationError", "maxGlobalConservationError");
174
175 m_log << "Global maximum Galerkin projection conservation error: " << std::scientific << maxGlobalConservationError
176 << std::endl;
177 m_log << "Local maximum Galerkin projection conservation error: " << std::scientific << m_maxConservationError
178 << std::endl;
179 }
180
181 // Compute global maximum L2 projection error if activated
182 if(m_calcProjectionError && m_hasDgCartesianSolver) {
183 MPI_Allreduce(&m_maxL2Error, &maxGlobalL2Error, 1, maia::type_traits<MFloat>::mpiType(), MPI_MAX,
184 dgSolver().mpiComm(), AT_, "m_maxL2Error", "maxGlobalL2Error");
185
186 m_log << "Global maximum Galerking projection L2 error: " << std::scientific << maxGlobalL2Error << std::endl;
187 m_log << "Local maximum Galerking projection L2 error: " << std::scientific << m_maxL2Error << std::endl;
188 }
189
190 // Write the maximum global errors to file
191 if(m_hasDgCartesianSolver && dgSolver().domainId() == 0 && (m_checkConservation || m_calcProjectionError)) {
192 std::ofstream errorFile(outputDir() + "errors.txt");
193
194 if(m_checkConservation) {
195 errorFile << "maxGlobalConservationError: " << std::scientific << maxGlobalConservationError << std::endl;
196 }
197 if(m_calcProjectionError) {
198 errorFile << "maxGlobalProjectionError: " << std::scientific << maxGlobalL2Error << std::endl;
199 }
200
201 errorFile.close();
202 }
203
204 RECORD_TIMER_STOP(m_timers[Timers::Class]);
205}
206
207
212template <MInt nDim, class FvSysEqn>
214 TRACE();
215
216 if(!fvSolver().calcSlopesAfterStep()) {
217 TERMM(1,
218 "Enable calcSlopesAfterStep for FV-solver for coupled simulation (else the slopes are not "
219 "initialized prior to the first source term calculation and will contain garbage)");
220 }
221}
222
232template <MInt nDim, class FvSysEqn>
234 const MFloat* const vorticity,
235 MFloat* const sourceTerms) {
236 TRACE();
237 RECORD_TIMER_START(m_timers[Timers::CalcSourceLamb]);
238
239 // Index of first lamb vector component in m_meanVars
240 const MInt lambIndex = m_meanVarsIndex[MV::LAMB0[0]];
241
242 std::array<MFloat, MAX_SPACE_DIMENSIONS> lambVector{};
243
244 // Calculate source terms on all 'active' donor leaf cells, i.e. that are
245 // mapped to elements with nonzero filter values
246 for(MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
247 const MInt donorId = m_calcSourceDonorCells[donorIndex];
248 // Create convenience pointers
249 const MFloat* meanVars = &m_meanVars[donorIndex * noMeanVars()];
250 const MFloat* velo = &velocity[donorId * noVelocities()];
251 const MFloat* vort = &vorticity[donorId * noVorticities()];
252
253 // Compute instantaneous Lamb vector
254 if constexpr(nDim == 2) {
255 lambVector[0] = -vort[0] * velo[1];
256 lambVector[1] = vort[0] * velo[0];
257 } else {
258 lambVector[0] = vort[1] * velo[2] - vort[2] * velo[1];
259 lambVector[1] = vort[2] * velo[0] - vort[0] * velo[2];
260 lambVector[2] = vort[0] * velo[1] - vort[1] * velo[0];
261 }
262
263 // The complete source term is:
264 // S = -L' = -(w x u - bar(w x u))
265 // Since the Lamb vector is defined with vorticity as 'nabla x u' but MAIA
266 // calculates it as '0.5 nabla x u', we multiply the resulting Lamb vector
267 // by 2.0
268 for(MInt dim = 0; dim < nDim; dim++) {
269 // Note: source terms are accumulated, thus "+=" and not "="
270 sourceTerms[donorId * SysEqn::noVars() + dim] += -2.0 * (lambVector[dim] - meanVars[lambIndex + dim]);
271 }
272 }
273
274 RECORD_TIMER_STOP(m_timers[Timers::CalcSourceLamb]);
275}
276
277
286template <MInt nDim, class FvSysEqn>
288 MFloat* const sourceTerms) {
289 TRACE();
290 RECORD_TIMER_START(m_timers[Timers::CalcSourceQmII]);
291
292 const MInt rhoIndex = m_meanVarsIndex[MV::RHO0];
293 const MInt pIndex = m_meanVarsIndex[MV::P0];
294 const MInt drhoIndex = m_meanVarsIndex[MV::DRHO[0]];
295 const MInt dpIndex = m_meanVarsIndex[MV::DP[0]];
296 const MInt dprhoIndex = m_meanVarsIndex[MV::GRADPRHO[0]];
297
298 // Calculate source terms on all donor leaf cells that are mapped to elements
299 // with nonzero filter values
300 for(MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
301 const MInt donorId = m_calcSourceDonorCells[donorIndex];
302 // Create convenience pointers
303 const MFloat* meanVars = &m_meanVars[donorIndex * noMeanVars()];
304 const MFloat curRho = fvSolver().a_variable(donorId, fvSolver().CV->RHO);
305 const MFloat curP = fvSolver().a_pvariable(donorId, fvSolver().PV->P);
306 const MFloat rhoM = meanVars[rhoIndex];
307 const MFloat pM = meanVars[pIndex];
308
309 // bar(grad(rho))
310 std::array<MFloat, nDim> drhoM;
311 for(MInt dim = 0; dim < nDim; dim++) {
312 drhoM[dim] = meanVars[drhoIndex + dim];
313 }
314
315 // bar(grad(p))
316 std::array<MFloat, nDim> dpM;
317 for(MInt dim = 0; dim < nDim; dim++) {
318 dpM[dim] = meanVars[dpIndex + dim];
319 }
320
321 // bar(grad(p)/rho)
322 std::array<MFloat, nDim> dprhoM;
323 for(MInt dim = 0; dim < nDim; dim++) {
324 dprhoM[dim] = meanVars[dprhoIndex + dim];
325 }
326
327 std::array<MFloat, nDim> qmIISource;
328 for(MInt dim = 0; dim < nDim; dim++) {
329 // Calculate source term, starting with term 1
330 qmIISource[dim] = ((fvSolver().a_slope(donorId, fvSolver().PV->P, dim)) - dpM[dim]) / rhoM
331 // term 2
332 - ((curP - pM) / (rhoM * rhoM)) * drhoM[dim]
333 // term 3
334 - (fvSolver().a_slope(donorId, fvSolver().PV->P, dim)) / curRho
335 // term 4
336 + dprhoM[dim];
337 }
338
339 // Store source term at output memory location
340 for(MInt dim = 0; dim < nDim; dim++) {
341 // Note: source terms are accumulated, thus "+=" and not "="
342 sourceTerms[donorId * SysEqn::noVars() + CV::UU[0] + dim] += qmIISource[dim];
343 }
344 }
345
346 RECORD_TIMER_STOP(m_timers[Timers::CalcSourceQmII]);
347}
348
349
353template <MInt nDim, class FvSysEqn>
354void DgCcAcousticPerturb<nDim, FvSysEqn>::calcSourceQmIII(const MFloat* const velocity, MFloat* sourceTerms) {
355 TRACE();
356 RECORD_TIMER_START(m_timers[Timers::CalcSourceQmIII]);
357 TERMM(1, "requires testing");
358
359 const MInt umIndex = m_meanVarsIndex[MV::UU0[0]];
360
361 // Calculate source terms on all donor leaf cells that are mapped to elements
362 // with nonzero filter values
363 for(MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
364 const MInt donorId = m_calcSourceDonorCells[donorIndex];
365 // Create convenience pointers
366 const MFloat* meanVars = &m_meanVars[donorIndex * noMeanVars()];
367
368 std::array<MFloat, nDim> qmIIISource;
369 std::fill_n(&qmIIISource[0], nDim, 0.0);
370
371 // Calculate source term
372 for(MInt dim = 0; dim < nDim; dim++) {
373 const MFloat velDiff = velocity[donorId * nDim + dim] - meanVars[umIndex + dim];
374
375 for(MInt i = 0; i < nDim; i++) {
376 const MFloat velGrad = fvSolver().a_slope(donorId, fvSolver().PV->VV[dim], i);
377 const MFloat velGradM = meanVars[m_meanVarsIndex[MV::GRADU[dim * nDim + i]]];
378
379 qmIIISource[i] += velDiff * (velGrad - velGradM);
380 }
381
382 // Substract mean term
383 qmIIISource[dim] -= meanVars[m_meanVarsIndex[MV::UGRADU[dim]]];
384
385 for(MInt i = 0; i < nDim; i++) {
386 const MInt gradUPos = i * nDim + dim;
387 qmIIISource[dim] += meanVars[m_meanVarsIndex[MV::UU0[i]]] * meanVars[m_meanVarsIndex[MV::GRADU[gradUPos]]];
388 }
389 }
390
391 // Store source term at output memory location
392 for(MInt dim = 0; dim < nDim; dim++) {
393 // Note: source terms are accumulated, thus "-=" and not "="
394 sourceTerms[donorId * SysEqn::noVars() + CV::UU[0] + dim] -= qmIIISource[dim];
395 }
396 }
397
398 RECORD_TIMER_STOP(m_timers[Timers::CalcSourceQmIII]);
399}
400
401
411template <MInt nDim, class FvSysEqn>
413 const MFloat* const vorticity,
414 MFloat* sourceTerms) {
415 TRACE();
416 RECORD_TIMER_START(m_timers[Timers::CalcSourceLamb]);
417
418 // Indices of first velocity/vorticity component in m_meanVars
419 const MInt veloIndex = m_meanVarsIndex[MV::UU0[0]];
420 const MInt vortIndex = m_meanVarsIndex[MV::VORT0[0]];
421
422 std::array<MFloat, MAX_SPACE_DIMENSIONS> veloP{};
423 std::array<MFloat, MAX_SPACE_DIMENSIONS> vortP{};
424
425 // Calculate source terms on all 'active' donor leaf cells, i.e. that are
426 // mapped to elements with nonzero filter values
427 for(MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
428 const MInt donorId = m_calcSourceDonorCells[donorIndex];
429 // Create convenience pointers
430 const MFloat* meanVars = &m_meanVars[donorIndex * noMeanVars()];
431 const MFloat* velo = &velocity[donorId * noVelocities()];
432 const MFloat* vort = &vorticity[donorId * noVorticities()];
433
434 // Compute velocity fluctuations
435 for(MInt dim = 0; dim < nDim; dim++) {
436 veloP[dim] = velo[dim] - meanVars[veloIndex + dim];
437 }
438 // Compute vorticity fluctuations
439 for(MInt i = 0; i < noVorticities(); i++) {
440 vortP[i] = vort[i] - meanVars[vortIndex + i];
441 }
442
443 // The complete source term is:
444 // S = -L' = -(w' X u0 + w0 X u')
445 // Since the Lamb vector is defined with vorticity as 'nabla x u' but MAIA
446 // calculates it as '0.5 nabla x u', we multiply the resulting Lamb vector
447 // by 2.0
448 const MInt sourcesOffset = donorId * SysEqn::noVars() + CV::UU[0];
449 IF_CONSTEXPR(nDim == 2) { // 2D
450 // x-component: -(-wz' * u0y - w0z * uy')
451 sourceTerms[sourcesOffset] += -2.0 * (-vortP[0] * meanVars[veloIndex + 1] - meanVars[vortIndex] * veloP[1]);
452
453 // y-component: -(wz' * u0x + w0z * ux')
454 sourceTerms[sourcesOffset + 1] += -2.0 * (vortP[0] * meanVars[veloIndex] + meanVars[vortIndex] * veloP[0]);
455 }
456 else { // 3D
457 // x-component: -(wy' * u0z - wz' * u0y + w0y * uz' - w0z * uy')
458 sourceTerms[sourcesOffset] += -2.0
459 * (vortP[1] * meanVars[veloIndex + 2] - vortP[2] * meanVars[veloIndex + 1]
460 + meanVars[vortIndex + 1] * veloP[2] - meanVars[vortIndex + 2] * veloP[1]);
461
462 // y-component: -(wz' * u0x - wx' * u0z + w0z * ux' - w0x * uz')
463 sourceTerms[sourcesOffset + 1] += -2.0
464 * (vortP[2] * meanVars[veloIndex] - vortP[0] * meanVars[veloIndex + 2]
465 + meanVars[vortIndex + 2] * veloP[0] - meanVars[vortIndex] * veloP[2]);
466
467 // z-component: -(wx' * u0y - wy' * u0x + w0x * uy' - w0y * ux')
468 sourceTerms[sourcesOffset + 2] += -2.0
469 * (vortP[0] * meanVars[veloIndex + 1] - vortP[1] * meanVars[veloIndex]
470 + meanVars[vortIndex] * veloP[1] - meanVars[vortIndex + 1] * veloP[0]);
471 }
472 }
473
474 RECORD_TIMER_STOP(m_timers[Timers::CalcSourceLamb]);
475}
476
477
486template <MInt nDim, class FvSysEqn>
488 const MFloat time,
489 MFloat* const sourceTerms) {
490 TRACE();
491 RECORD_TIMER_START(m_timers[Timers::CalcSourceQe]);
492 TERMM(1, "untested in new coupling condition");
493
494 // If this is the first invocation, we need to perform some initializations.
495 if(m_isFirstSourceCalculation) {
496 // Create persistent storage for old pressure values
497 m_oldPressure.resize(m_noActiveDonorCells);
498
499 if(m_isRestart) {
500 // If this is a restart, initialize old pressure values from oldVariables, which should have
501 // been loaded by setting the property "restartOldVariables" to true.
502 // @ansgar TODO labels:COUPLER,FV support for balance, redistribute oldPressure/oldVariables in FV solver
503 MFloatScratchSpace buffer(m_noDonorCells, AT_, "buffer");
504 fvSolver().oldPressure(&buffer[0]);
505 for(MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
506 const MInt donorId = m_calcSourceDonorCells[donorIndex];
507 m_oldPressure[donorIndex] = buffer[donorId];
508 }
509 } else {
510 // If this is *not* a restart, assume that this is the first time step. In this case, the old
511 // pressure values are initialized with the current values to have a gradient of zero
512 for(MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
513 const MInt donorId = m_calcSourceDonorCells[donorIndex];
514 m_oldPressure[donorIndex] = fvSolver().a_pvariable(donorId, fvSolver().PV->P);
515 }
516 }
517
518 // Calculate slopes for the calculation of the velocity divergence
519 fvSolver().LSReconstructCellCenter();
520 }
521
522 // Calculate dt (set to infinity if this is the first time step of a non-restarted simulation)
523 const MFloat dt =
524 (m_isFirstSourceCalculation && !m_isRestart) ? std::numeric_limits<MFloat>::infinity() : time - m_previousTime;
525
526 // Calculate source terms on all donor leaf cells that are mapped to elements with nonzero filter
527 // values
528 const MInt rhoIndex = m_meanVarsIndex[MV::RHO0];
529 const MInt pIndex = m_meanVarsIndex[MV::P0];
530 const MInt cIndex = m_meanVarsIndex[MV::C0];
531 const MInt veloIndex = m_meanVarsIndex[MV::UU0[0]];
532 const MInt dcIndex = m_meanVarsIndex[MV::DC0[0]];
533 std::array<MInt, nDim> divIndex;
534 for(MInt i = 0; i < nDim; i++) {
535 divIndex[i] = m_meanVarsIndex[MV::DU[i]];
536 }
537 const MInt drhoIndex = m_meanVarsIndex[MV::DRHO[0]];
538 const MInt dpIndex = m_meanVarsIndex[MV::DP[0]];
539
540 for(MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
541 const MInt donorId = m_calcSourceDonorCells[donorIndex];
542
543 // Calculate dp/dt and store current pressure for the next time step
544 const MFloat curP = fvSolver().a_pvariable(donorId, fvSolver().PV->P);
545 const MFloat dpdt = (curP - m_oldPressure[donorIndex]) / dt;
546 m_oldPressure[donorIndex] = curP;
547
548 // Create convenience pointers
549 const MFloat* meanVars = &m_meanVars[donorIndex * noMeanVars()];
550
551 // bar(u)
552 std::array<MFloat, nDim> veloM;
553 for(MInt dim = 0; dim < nDim; dim++) {
554 veloM[dim] = meanVars[veloIndex + dim];
555 }
556
557 // bar(grad(c))
558 std::array<MFloat, nDim> dcM;
559 for(MInt dim = 0; dim < nDim; dim++) {
560 dcM[dim] = meanVars[dcIndex + dim];
561 }
562
563 // bar(grad(rho))
564 std::array<MFloat, nDim> drhoM;
565 for(MInt dim = 0; dim < nDim; dim++) {
566 drhoM[dim] = meanVars[drhoIndex + dim];
567 }
568
569 // bar(grad(p))
570 std::array<MFloat, nDim> dpM;
571 for(MInt dim = 0; dim < nDim; dim++) {
572 dpM[dim] = meanVars[dpIndex + dim];
573 }
574
575 // Mean of du/dx, dv/dy, dw/dz for the divergence u
576 MFloat divUm = 0.0;
577 for(MInt dim = 0; dim < nDim; dim++) {
578 divUm += meanVars[divIndex[dim]];
579 }
580
581 MFloat divU = 0.0;
582 for(MInt dim = 0; dim < nDim; dim++) {
583 divU += fvSolver().a_slope(donorId, fvSolver().PV->VV[dim], dim);
584 }
585
586 // Compute drho/dt = -(rho* div(u) + u * grad(rho))
587 const MFloat* const velo = &velocity[donorId * noVelocities()];
588 MFloat drhodttmp = 0.0;
589 for(MInt dim = 0; dim < nDim; dim++) {
590 drhodttmp += velo[dim] * fvSolver().a_slope(donorId, fvSolver().PV->RHO, dim);
591 }
592 const MFloat curRho = fvSolver().a_variable(donorId, fvSolver().CV->RHO);
593 const MFloat drhodt = -curRho * divU - drhodttmp;
594
595 // Compute q_e
596 const MFloat rhoM = meanVars[rhoIndex];
597 const MFloat pM = meanVars[pIndex];
598 const MFloat cM = meanVars[cIndex];
599 const MFloat cTerm = cM * cM;
600 MFloat qeSource = 0.0;
601 qeSource += drhodt - (1.0 / cTerm) * dpdt;
602 qeSource += (curRho - rhoM) * divUm;
603 qeSource -= ((curP - pM) / cTerm) * divUm;
604 for(MInt dim = 0; dim < nDim; dim++) {
605 // bar(u) * (grad(rho) - bar(grad(rho)))
606 qeSource += veloM[dim] * ((fvSolver().a_slope(donorId, fvSolver().PV->RHO, dim)) - drhoM[dim]);
607 qeSource -= (1.0 / cTerm) * veloM[dim] * ((fvSolver().a_slope(donorId, fvSolver().PV->P, dim)) - dpM[dim]);
608 qeSource += 2.0 * ((curP - pM) / (cM * cM * cM)) * veloM[dim] * dcM[dim];
609 }
610
611 // Note: the multiplication with c^2 is technically not part of q_e
612 qeSource *= -cTerm;
613
614 // Store source term at output memory location
615 // Note: source terms are accumulated, thus "+=" and not "="
616 sourceTerms[donorId * SysEqn::noVars() + CV::P] += qeSource;
617 }
618
619 RECORD_TIMER_STOP(m_timers[Timers::CalcSourceQe]);
620}
621
622
632template <MInt nDim, class FvSysEqn>
634 MFloat* const sourceTerms,
635 const MFloat NotUsed(time),
636 const MInt NotUsed(timeStep)) {
637 TRACE();
638 RECORD_TIMER_START(m_timers[Timers::CalcSourceQc]);
639
640 const MInt veloIndex = m_meanVarsIndex[MV::UU0[0]];
641 const MInt drhoIndex = m_meanVarsIndex[MV::DRHO[0]];
642 const MInt rhoDivUIndex = m_meanVarsIndex[MV::RHODIVU[0]];
643 const MInt uGradRhoIndex = m_meanVarsIndex[MV::UGRADRHO[0]];
644 std::array<MInt, nDim> divIndex;
645 for(MInt i = 0; i < nDim; i++) {
646 divIndex[i] = m_meanVarsIndex[MV::DU[i]];
647 }
648 const MInt cIndex = m_meanVarsIndex[MV::C0];
649 const MInt rhoIndex = m_meanVarsIndex[MV::RHO0];
650
651 // Calculate source terms on all donor leaf cells that are mapped to
652 // elements
653 // with nonzero filter values
654 for(MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
655 const MInt donorId = m_calcSourceDonorCells[donorIndex];
656
657 // Create convenience pointer
658 const MFloat* const meanVars = &m_meanVars[donorIndex * noMeanVars()];
659
660 // bar(u)
661 std::array<MFloat, nDim> veloM;
662 for(MInt dim = 0; dim < nDim; dim++) {
663 veloM[dim] = meanVars[veloIndex + dim];
664 }
665
666 // bar(grad(rho))
667 std::array<MFloat, nDim> drhoM;
668 for(MInt dim = 0; dim < nDim; dim++) {
669 drhoM[dim] = meanVars[drhoIndex + dim];
670 }
671
672 // bar(rho * div(u))
673 MFloat rhodivuM = 0.0;
674 for(MInt dim = 0; dim < nDim; dim++) {
675 rhodivuM += meanVars[rhoDivUIndex + dim];
676 }
677
678 // bar(u * grad(rho))
679 MFloat ugradrhoM = 0.0;
680 for(MInt dim = 0; dim < nDim; dim++) {
681 ugradrhoM += meanVars[uGradRhoIndex + dim];
682 }
683
684 MFloat divUm = 0.0;
685 for(MInt dim = 0; dim < nDim; dim++) {
686 divUm += meanVars[divIndex[dim]];
687 }
688
689 MFloat divU = 0.0;
690 divU += fvSolver().a_slope(donorId, fvSolver().PV->U, 0);
691 divU += fvSolver().a_slope(donorId, fvSolver().PV->V, 1);
692 IF_CONSTEXPR(nDim == 3) { divU += fvSolver().a_slope(donorId, fvSolver().PV->W, 2); }
693
694 // Compute q_c
695 const MFloat rhoM = meanVars[rhoIndex];
696 const MFloat curRho = fvSolver().a_variable(donorId, fvSolver().CV->RHO);
697 const MFloat* const velo = &velocity[donorId * noVelocities()];
698 MFloat qcSource = 0.0;
699 qcSource += (curRho - rhoM) * (divU - divUm);
700 qcSource -= rhodivuM;
701 qcSource -= ugradrhoM;
702 qcSource += rhoM * divUm;
703 for(MInt dim = 0; dim < nDim; dim++) {
704 qcSource += (velo[dim] - veloM[dim]) * ((fvSolver().a_slope(donorId, fvSolver().PV->RHO, dim)) - drhoM[dim]);
705 qcSource += veloM[dim] * drhoM[dim];
706 }
707
708 // Note: the multiplication with c^2 is technically not part of q_c
709 qcSource *= -meanVars[cIndex] * meanVars[cIndex];
710
711 // Store source term at output memory location
712 // Note: source terms are accumulated, thus "+=" and not "="
713 sourceTerms[donorId * SysEqn::noVars() + CV::P] += qcSource;
714 }
715
716 RECORD_TIMER_STOP(m_timers[Timers::CalcSourceQc]);
717}
718
719template <MInt nDim, class FvSysEqn>
721 MFloatScratchSpace& p_velocity,
722 MFloatScratchSpace& p_vorticity) {
723 // Load velocities of all donor leaf cells (if there are any on this domain)
724 for(auto donorId : donorCellIds) {
725 for(MInt varId = 0; varId < noVelocities(); varId++) {
726 p_velocity(donorId, varId) = fvSolver().a_pvariable(donorId, fvSolver().PV->VV[varId]);
727 }
728 }
729
730 // Only calculate vorticity if this domain has FV cells at all, otherwise
731 // the FV solver pointer is null and a segmentation fault occurs
732 // TODO labels:COUPLER,FV only compute vorticity on donor cells where it is needed?
733 if(m_hasDonorCartesianSolver) {
734 fvSolver().getVorticityT(&p_vorticity[0]);
735 }
736}
737
744template <MInt nDim, class FvSysEqn>
746 TRACE();
747
748 if(m_fixedTimeStep < 0.0) {
749 TERMM(1, "Fixed time step less than zero.");
750 }
751
752 fvSolver().forceTimeStep(m_fixedTimeStep);
753 dgSolver().forceTimeStep(m_fixedTimeStep);
754
755 // FIXME labels:COUPLER Return proper time step determined by both solvers
756 return m_fixedTimeStep;
757}
758
759template <MInt nDim, class FvSysEqn>
761 TRACE();
762 TERMM_IF_NOT_COND(dataId == 0, "invalid data id");
763
764 // Convert to solver cell id and check
765 const MInt fvCellId = fvSolver().grid().tree().grid2solver(gridCellId);
766 if(fvCellId < 0) {
767 return 0;
768 }
769
770 MInt dataSize = 0;
771 // TODO labels:COUPLER Check that ids in m_calcSourceDonorCells are sorted in get/setCellDataDlb
772 const MBool foundDonorCell =
773 std::binary_search(m_calcSourceDonorCells.begin(), m_calcSourceDonorCells.end(), fvCellId);
774 if(foundDonorCell) {
775 dataSize = noMeanVars();
776 }
777 return dataSize;
778}
779
780
781template <MInt nDim, class FvSysEqn>
783 const MInt NotUsed(oldNoCells),
784 const MInt* const NotUsed(bufferIdToCellId),
785 MFloat* const data) {
786 TRACE();
787 TERMM_IF_NOT_COND(dataId == 0, "invalid data id");
788
789 const MBool donorIdsSorted = std::is_sorted(m_calcSourceDonorCells.begin(), m_calcSourceDonorCells.end());
790 TERMM_IF_NOT_COND(donorIdsSorted, "donor ids not sorted");
791
792 if(m_noActiveDonorCells > 0) {
793 std::copy_n(&m_meanVars[0], m_noActiveDonorCells * noMeanVars(), data);
794 }
795}
796
797
798template <MInt nDim, class FvSysEqn>
800 TRACE();
801 TERMM_IF_NOT_COND(dataId == 0, "invalid data id");
802
803 // Return if not on the right reinitialization stage
804 if(m_loadBalancingReinitStage != 0) {
805 return;
806 }
807
808 const MBool donorIdsSorted = std::is_sorted(m_calcSourceDonorCells.begin(), m_calcSourceDonorCells.end());
809 TERMM_IF_NOT_COND(donorIdsSorted, "donor ids not sorted");
810
811 if(m_noActiveDonorCells > 0) {
812 std::copy_n(data, m_noActiveDonorCells * noMeanVars(), &m_meanVars[0]);
813 }
814}
815
816#endif // DGCOUPLINGCONDITIONACOUSTICPERTURB_H_
Intermediate class for coupling DG solver with APE sysEqn.
void init() override
static constexpr MInt noVelocities()
Return number of velocity variables.
DgGalerkinProjection< nDim > ProjectionType
MBool m_isRestart
Store whether this is a restart (in case special treatment is necessary)
MBool m_checkConservation
Check if each Galerkin projection is conservative.
std::array< MInt, s_totalNoMeanVars > m_meanVarsIndex
MBool m_isFirstSourceCalculation
Store whether this is the first calculation of the source terms.
MInt noMeanVars() const
Return number of mean variables.
std::array< MInt, Timers::_count > m_timers
static constexpr MInt noVorticities()
Return number of vorticity variables.
MBool m_calcProjectionError
Calculate the L2 error of the Galerkin projection.
MFloat m_maxL2Error
Maximum computed L2 error of the Galerkin projection.
std::vector< MInt > m_calcSourceDonorCells
List of all donor cell ids for which source terms need to be computed.
MInt m_noDonorCells
Total number of donor cells on this domain.
MeanVariables< nDim > MV
Hold indices for mean variables.
MFloat m_previousTime
Previous time for the calculation of time derivatives.
void initCoupler()
Initialize the coupling condition (data structures).
MInt m_noActiveDonorCells
MBool m_hasDonorCartesianSolver
Store whether this domain has Cartesian donor solver cells.
MFloat m_fixedTimeStep
Fixed time step to use.
MBool m_hasDgCartesianSolver
Store whether this domain has DG cells/elements.
std::vector< MFloat > m_meanVars
Local storage for mean variables of the donor cells.
DgSysEqnAcousticPerturb< nDim > SysEqn
MFloat m_maxConservationError
Maximum conservation error.
typename BaseDg::solverType DgCartesianSolverType
MString outputDir() const
Return output directory.
Definition: coupling.h:339
DgSysEqnAcousticPerturb< nDim > & sysEqn()
Return reference to SysEqn object.
Definition: coupling.h:318
solverType & dgSolver() const
Return MPI communicator.
Definition: coupling.h:310
MInt solverId() const
Return solver id.
Definition: coupling.h:315
solverType & fvSolver(const MInt solverId=0) const
Definition: coupling.h:386
FvCartesianSolverXD< nDim, FvSysEqn > solverType
Definition: coupling.h:363
Coupling condition for direct-hybrid LES-CAA computations.
void balancePre() override
Load balancing.
typename BaseDg::ProjectionType ProjectionType
MBool forceTimeStep() const
Return true if time step calculation should be overruled by coupling.
typename BaseDg::DgCartesianSolverType DgCartesianSolverType
void calcSourceLambLinearized(const MFloat *const velocity, const MFloat *const vorticity, MFloat *sourceTerms) override
Calculate the linearized Lamb vector coupling source terms on all donor cells where it is needed.
MFloat calcTimeStep()
Return the time step size dt as determined by the coupling condition.
void sanityCheck()
Perform sanity checks.
void calcSourceLambNonlinear(const MFloat *const velocity, const MFloat *const vorticity, MFloat *const sourceTerms) override
Calculate the nonlinear Lamb vector coupling source terms on all donor cells where it is needed.
void setCellDataDlb(const MInt NotUsed(dataId), const MFloat *const NotUsed(data)) override
typename BaseDg::Timers Timers
FvCartesianSolverType & donorSolver(const MInt xSolverId=0) const override
void calcSourceQc(const MFloat *const velocity, MFloat *const sourceTerms, const MFloat time, const MInt timeStep) override
Calculate the q_c source terms on all donor cells where it is needed.
void calcSourceQe(const MFloat *const velocity, const MFloat time, MFloat *const sourceTerms) override
Calculate the q_e source terms on all donor cells where it is needed.
MInt cellDataSizeDlb(const MInt NotUsed(dataId), const MInt NotUsed(cellId)) override
void getCellDataDlb(const MInt dataId, const MInt oldNoCells, const MInt *const bufferIdToCellId, MFloat *const data) override
MInt noCellDataDlb() const override
Methods to inquire coupler data during balancing.
void calcSourceQmIII(const MFloat *const velocity, MFloat *sourceTerms) override
Calculate the q_mIII source terms on all donor cells where it is needed.
DgCcAcousticPerturb(const MInt couplingId, FvCartesianSolverType *fvSolver_, DgCartesianSolverType *const dgSolver_)
MInt m_loadBalancingReinitStage
DLB reinitialization stage.
void getDonorVelocityAndVorticity(const std::vector< MInt > &donorCellIds, MFloatScratchSpace &p_velocity, MFloatScratchSpace &p_vorticity) override
typename BaseFv::solverType FvCartesianSolverType
virtual ~DgCcAcousticPerturb()
Stop the object lifetime timer and calculate global maximum errors.
std::vector< MFloat > m_oldPressure
Store previous pressure term for dp/dt calculation.
typename BaseDg::SysEqn SysEqn
MInt cellDataTypeDlb(const MInt dataId) const override
void calcSourceQmII(const MFloat *const velocity, MFloat *const sourceTerms) override
Calculate the q_mII source terms on all donor cells where it is needed.
This class is a ScratchSpace.
Definition: scratch.h:758
Parent class of all solvers This class is the base for all solvers. I.e. all solver class (e....
Definition: solver.h:29
@ MFLOAT
Definition: enums.h:269
InfoOutFile m_log
int32_t MInt
Definition: maiatypes.h:62
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