7#ifndef COUPLINGDGAPE_H_
8#define COUPLINGDGAPE_H_
38 static constexpr const MInt nDim = 2;
39 static constexpr const MInt noVorticities = 1;
42 static constexpr const MInt LAMB0_X = 0;
43 static constexpr const MInt LAMB0_Y = 1;
44 static constexpr const MInt LAMB0[nDim] = {0, 1};
47 static constexpr const MInt U0 = 2;
48 static constexpr const MInt V0 = 3;
49 static constexpr const MInt UU0[nDim] = {2, 3};
51 static constexpr const MInt RHO0 = 4;
52 static constexpr const MInt P0 = 5;
53 static constexpr const MInt C0 = 6;
56 static constexpr const MInt DC0_X = 7;
57 static constexpr const MInt DC0_Y = 8;
58 static constexpr const MInt DC0[nDim] = {7, 8};
61 static constexpr const MInt VORT0_Z = 9;
62 static constexpr const MInt VORT0[noVorticities] = {9};
65 static constexpr const MInt DU_DX = 10;
66 static constexpr const MInt DU_DY = 11;
68 static constexpr const MInt DV_DX = 12;
69 static constexpr const MInt DV_DY = 13;
71 static constexpr const MInt GRADU[nDim * nDim] = {10, 11, 12, 13};
76 static constexpr const MInt DU[nDim] = {10, 13};
79 static constexpr const MInt DRHO_DX = 14;
80 static constexpr const MInt DRHO_DY = 15;
81 static constexpr const MInt DRHO[nDim] = {14, 15};
84 static constexpr const MInt DP_DX = 16;
85 static constexpr const MInt DP_DY = 17;
86 static constexpr const MInt DP[nDim] = {16, 17};
89 static constexpr const MInt RHODIVU_X = 18;
90 static constexpr const MInt RHODIVU_Y = 19;
91 static constexpr const MInt RHODIVU[nDim] = {18, 19};
94 static constexpr const MInt UGRADRHO_X = 20;
95 static constexpr const MInt UGRADRHO_Y = 21;
96 static constexpr const MInt UGRADRHO[nDim] = {20, 21};
99 static constexpr const MInt GRADPRHO_X = 22;
100 static constexpr const MInt GRADPRHO_Y = 23;
101 static constexpr const MInt GRADPRHO[nDim] = {22, 23};
104 static constexpr const MInt UGRADU_X = 24;
105 static constexpr const MInt UGRADU_Y = 25;
106 static constexpr const MInt UGRADU[nDim] = {24, 25};
110 static constexpr const MInt totalNoMeanVars = 26;
111 static const std::array<MString, totalNoMeanVars>
names;
116 static constexpr const MInt nDim = 3;
117 static constexpr const MInt noVorticities = 3;
120 static constexpr const MInt LAMB0_X = 0;
121 static constexpr const MInt LAMB0_Y = 1;
122 static constexpr const MInt LAMB0_Z = 2;
123 static constexpr const MInt LAMB0[nDim] = {0, 1, 2};
125 static constexpr const MInt U0 = 3;
126 static constexpr const MInt V0 = 4;
127 static constexpr const MInt W0 = 5;
128 static constexpr const MInt UU0[nDim] = {3, 4, 5};
130 static constexpr const MInt RHO0 = 6;
131 static constexpr const MInt P0 = 7;
132 static constexpr const MInt C0 = 8;
135 static constexpr const MInt DC0_X = 9;
136 static constexpr const MInt DC0_Y = 10;
137 static constexpr const MInt DC0_Z = 11;
138 static constexpr const MInt DC0[nDim] = {9, 10, 11};
141 static constexpr const MInt VORT0_X = 12;
142 static constexpr const MInt VORT0_Y = 13;
143 static constexpr const MInt VORT0_Z = 14;
144 static constexpr const MInt VORT0[noVorticities] = {12, 13, 14};
147 static constexpr const MInt DU_DX = 15;
148 static constexpr const MInt DU_DY = 16;
149 static constexpr const MInt DU_DZ = 17;
151 static constexpr const MInt DV_DX = 18;
152 static constexpr const MInt DV_DY = 19;
153 static constexpr const MInt DV_DZ = 20;
155 static constexpr const MInt DW_DX = 21;
156 static constexpr const MInt DW_DY = 22;
157 static constexpr const MInt DW_DZ = 23;
159 static constexpr const MInt GRADU[nDim * nDim] = {15, 16, 17, 18, 19, 20, 21, 22, 23};
164 static constexpr const MInt DU[nDim] = {15, 19, 23};
167 static constexpr const MInt DRHO_DX = 24;
168 static constexpr const MInt DRHO_DY = 25;
169 static constexpr const MInt DRHO_DZ = 26;
170 static constexpr const MInt DRHO[nDim] = {24, 25, 26};
173 static constexpr const MInt DP_DX = 27;
174 static constexpr const MInt DP_DY = 28;
175 static constexpr const MInt DP_DZ = 29;
176 static constexpr const MInt DP[nDim] = {27, 28, 29};
179 static constexpr const MInt RHODIVU_X = 30;
180 static constexpr const MInt RHODIVU_Y = 31;
181 static constexpr const MInt RHODIVU_Z = 32;
182 static constexpr const MInt RHODIVU[nDim] = {30, 31, 32};
185 static constexpr const MInt UGRADRHO_X = 33;
186 static constexpr const MInt UGRADRHO_Y = 34;
187 static constexpr const MInt UGRADRHO_Z = 35;
188 static constexpr const MInt UGRADRHO[nDim] = {33, 34, 35};
191 static constexpr const MInt GRADPRHO_X = 36;
192 static constexpr const MInt GRADPRHO_Y = 37;
193 static constexpr const MInt GRADPRHO_Z = 38;
194 static constexpr const MInt GRADPRHO[nDim] = {36, 37, 38};
197 static constexpr const MInt UGRADU_X = 39;
198 static constexpr const MInt UGRADU_Y = 40;
199 static constexpr const MInt UGRADU_Z = 41;
200 static constexpr const MInt UGRADU[nDim] = {39, 40, 41};
204 static constexpr const MInt totalNoMeanVars = 42;
205 static const std::array<MString, totalNoMeanVars>
names;
213template <MInt nDim,
class CouplingDonor>
267#ifdef MAIA_TIMER_FUNCTION
290 domainInfo.emplace_back(namePrefix +
"noCoupledDgElements", noCoupledDgElements);
291 domainInfo.emplace_back(namePrefix +
"noCoupledDonorCells", noCoupledDonorCells);
294#ifdef MAIA_TIMER_FUNCTION
336 MFloat*
const sourceTerms) = 0;
341 const MInt timeStep) = 0;
366 std::numeric_limits<MFloat>::quiet_NaN();
471template <MInt nDim,
class CouplingDonor>
473 static constexpr const MInt Q_mI = 0;
474 static constexpr const MInt Q_mI_linear = 1;
475 static constexpr const MInt Q_mII = 2;
476 static constexpr const MInt Q_mIII = 3;
477 static constexpr const MInt Q_mIV = 4;
478 static constexpr const MInt Q_c = 5;
479 static constexpr const MInt Q_e = 6;
481 static constexpr const MInt totalNoSourceTerms = 7;
485template <MInt nDim,
class CouplingDonor>
486const std::array<MString, CouplingDgApe<nDim, CouplingDonor>::ST::totalNoSourceTerms>
488 {
"q_mI",
"q_mI_linear",
"q_mII",
"q_mIII",
"q_mIV",
"q_c",
"q_e"}};
499template <MInt nDim,
class CouplingDonor>
504 m_sourceTermFilter(dg->solverId()) {
508 static_assert(MV::totalNoMeanVars ==
s_totalNoMeanVars,
"Total number of mean vars is inconsistent");
518template <MInt nDim,
class CouplingDonor>
521 RECORD_TIMER_START(m_timers[Timers::PreCouple]);
523 const MInt timeStep = (m_hasDgCartesianSolver) ? dgSolver().getCurrentTimeStep() : -1;
524 const MFloat time = (m_hasDgCartesianSolver) ? dgSolver().time() : -1.0;
526 if(m_hasDgCartesianSolver && timeStep == m_previousTimeStep) {
527 TERMM(1,
"Error: preCouple already called for this time step.");
531 storeSources(time, timeStep);
533 applyStoredSources(time);
535 m_previousTimeStep = timeStep;
537 RECORD_TIMER_STOP(m_timers[Timers::PreCouple]);
548template <MInt nDim,
class CouplingDonor>
551 RECORD_TIMER_START(m_timers[Timers::InitialCondition]);
554 loadMeanQuantities();
556 RECORD_TIMER_STOP(m_timers[Timers::InitialCondition]);
565template <MInt nDim,
class CouplingDonor>
568 RECORD_TIMER_START(m_timers[Timers::Init]);
570 m_hasDgCartesianSolver = dgSolver().isActive();
571 if(!m_hasDgCartesianSolver) {
572 TERMM_IF_NOT_COND(noElements() == 0,
"inactive DG solver should have no elements");
577 m_noDonorCells = donorSolver().noInternalCells();
578 if(m_noDonorCells < 0) {
581 m_hasDonorCartesianSolver = (m_noDonorCells > 0);
582 TERMM_IF_NOT_COND(m_hasDonorCartesianSolver == donorSolver().isActive(),
"Donor solver status error");
585 m_maxNoNodesXD = (m_hasDgCartesianSolver) ?
ipow(maxPolyDeg() + 1, nDim) : -1;
594 m_filter.resize(std::max(noElements() * m_maxNoNodesXD, 0));
596 m_filterDonor.resize(m_noDonorCells);
600 m_calcSourceElements.reserve(noElements());
608 if(m_saveSourceTermFilter) {
610 saveFilterValuesDonor();
616 m_sourceTerms.resize(std::max(
static_cast<MInt>(m_calcSourceElements.size()) * m_maxNoNodesXD * SysEqn::noVars(), 0));
619 std::set<MInt> calcSourceDonorCells;
620 for(
MInt elementId : m_calcSourceElements) {
621 calcSourceDonorCells.insert(m_elementDonorMap[elementId].begin(), m_elementDonorMap[elementId].end());
624 m_noActiveDonorCells = calcSourceDonorCells.size();
625 if(!m_hasDgCartesianSolver) {
626 TERMM_IF_COND(m_noActiveDonorCells > 0,
"Inactive DG solver cannot have active donor cells.");
630 m_calcSourceDonorCells.resize(m_noActiveDonorCells);
631 m_calcSourceDonorCells.assign(calcSourceDonorCells.begin(), calcSourceDonorCells.end());
634 m_meanVars.resize(m_noActiveDonorCells * noMeanVars());
636 if(m_noCutModesLowPass > 0 && m_hasDgCartesianSolver) {
642 const MInt defaultSbpMode = 0;
646 const MString defaultSbpOperator =
"";
648 Context::getSolverProperty<MString>(
"sbpOperator", solverId(), AT_, &defaultSbpOperator);
651 MInt initNoNodes1D = -1;
652 initNoNodes1D = Context::getSolverProperty<MInt>(
"initNoNodes", solverId(), AT_, &initNoNodes1D);
655 const MString defaultDgIntegrationMethod =
"DG_INTEGRATE_GAUSS";
657 Context::getSolverProperty<MString>(
"dgIntegrationMethod", solverId(), AT_, &defaultDgIntegrationMethod));
660 const MString defaultDgPolynomialType =
"DG_POLY_LEGENDRE";
661 const MInt dgPolynomialType =
662 string2enum(Context::getSolverProperty<MString>(
"dgPolynomialType", solverId(), AT_, &defaultDgPolynomialType));
669 std::vector<DgInterpolation> interpolation(maxPolyDeg() + 1);
670 for(
MInt i = std::max(0, minPolyDeg() - m_noCutModesLowPass); i < maxPolyDeg() + 1; i++) {
671 const MInt noNodes1D = sbpMode ? initNoNodes1D : (i + 1);
672 interpolation[i].init(i, polyType, noNodes1D, intMethod, sbpMode, sbpOperator);
680 m_vdmLowPass.clear();
681 m_vdmLowPass.resize(maxPolyDeg() + 1 - m_noCutModesLowPass);
684 for(
MInt polyDeg = std::max(0, minPolyDeg() - m_noCutModesLowPass);
685 polyDeg < maxPolyDeg() + 1 - m_noCutModesLowPass;
687 const MInt noNodesIn = polyDeg + 1;
688 const MInt noNodesOut = polyDeg + 1 + m_noCutModesLowPass;
689 m_vdmLowPass[polyDeg].resize(noNodesOut, noNodesIn);
691 const DgInterpolation& interpOut = interpolation[polyDeg + m_noCutModesLowPass];
697 &m_vdmLowPass[polyDeg][0]);
700 m_vdmLowPass.clear();
703 RECORD_TIMER_STOP(m_timers[Timers::Init]);
709template <MInt nDim,
class CouplingDonor>
712 RECORD_TIMER_START(m_timers[Timers::Init]);
714 if(dgSolver().m_restart) {
716 const MFloat time = dgSolver().time();
721 initRestart(time, m_fixedTimeStep);
724 calcInitialCondition(-1.0);
725 RECORD_TIMER_STOP(m_timers[Timers::Init]);
729 if(m_hasDgCartesianSolver) {
732 dgSolver().initialCondition();
737 RECORD_TIMER_START(m_timers[Timers::Init]);
740 if(m_hasDgCartesianSolver && SysEqn::noNodeVars() > 0) {
741 dgSolver().updateNodeVariables();
742 dgSolver().extendNodeVariables();
746 RECORD_TIMER_STOP(m_timers[Timers::Init]);
757template <MInt nDim,
class CouplingDonor>
761 if(!m_hasDgCartesianSolver) {
763 m_projection.clear();
764 m_elementDonorMap.clear();
765 m_elementDonorLevels.clear();
766 m_elementDonorPos.clear();
771 std::vector<std::vector<MInt>> elementGridMap(noElements());
773 for(
MInt elementId = 0; elementId < noElements(); elementId++) {
774 const MInt cellId = elements().cellId(elementId);
775 const MInt gridCellId = dgSolver().grid().tree().solver2grid(cellId);
777 elementGridMap[elementId].clear();
780 dgSolver().grid().raw().createLeafCellMapping(donorSolver().solverId(), gridCellId, elementGridMap[elementId]);
785 m_projection.clear();
786 m_projection.reserve(maxPolyDeg() + 1);
790 if(m_hasDonorCartesianSolver) {
791 noLevels = donorSolver().grid().maxLevel() - donorSolver().grid().minLevel() + 1;
794 m_log <<
"Initialize Galerkin projections for " << noLevels <<
" levels." << std::endl;
797 for(
MInt i = 0; i < std::max(0, minPolyDeg() - m_noCutModesLowPass); i++) {
802 for(
MInt i = std::max(0, minPolyDeg() - m_noCutModesLowPass); i <= maxPolyDeg(); i++) {
803 m_log <<
"Initialize Galerkin projection (p = " << i <<
")... ";
804 m_projection.push_back(
ProjectionType(i, noLevels, dgSolver().grid().lengthLevel0(), dgSolver().solverId()));
805 m_log <<
"done" << std::endl;
809 m_elementDonorMap.resize(noElements());
810 m_elementDonorLevels.resize(noElements());
811 m_elementDonorPos.resize(noElements());
814 for(
MInt elementId = 0; elementId < noElements(); elementId++) {
815 const MInt polyDeg = elements().polyDeg(elementId);
818 m_elementDonorMap[elementId].clear();
819 m_elementDonorLevels[elementId].clear();
820 m_elementDonorPos[elementId].clear();
823 if(elementGridMap[elementId].empty()) {
827 const MInt noMappedLeafCells = elementGridMap[elementId].size();
828 MIntScratchSpace donorCellLevels(noMappedLeafCells, AT_,
"donorCellLevels");
829 MFloatScratchSpace donorCellCoordinates(noMappedLeafCells, nDim, AT_,
"donorCellCoordinates");
832 const MInt targetCellId = elements().cellId(elementId);
833 const MInt targetLevel = dgSolver().grid().tree().level(targetCellId);
834 const MFloat halfCellLength = 0.5 * dgSolver().grid().cellLengthAtLevel(targetLevel);
835 const MFloat* targetElementCenter = &dgSolver().grid().tree().coordinate(targetCellId, 0);
838 if(m_projectionFilter) {
839 MBool hasProjection =
false;
840 for(
MInt dimId = 0; dimId < nDim; dimId++) {
841 const MFloat coord = targetElementCenter[dimId];
842 if(coord + halfCellLength < m_projectionFilterBox[dimId]
843 || coord - halfCellLength > m_projectionFilterBox[nDim + dimId]) {
844 hasProjection =
true;
853 MInt noDonorCells = 0;
855 for(
MInt i = 0; i < noMappedLeafCells; i++) {
856 const MInt donorGridCellId = elementGridMap[elementId][i];
857 const MInt donorCellId = donorSolver().grid().tree().grid2solver(donorGridCellId);
859 if(donorCellId < 0) {
860 TERMM(1,
"Error in mapped donor leaf cells.");
864 m_elementDonorMap[elementId].push_back(donorCellId);
866 donorCellLevels[noDonorCells] = donorSolver().grid().tree().level(donorCellId);
873 for(
MInt d = 0; d < nDim; d++) {
874 donorCellCoordinates(noDonorCells, d) = donorSolver().grid().tree().coordinate(donorCellId, d);
880 if(noDonorCells == 0) {
881 TERMM(1,
"Donor cells for element (elementId=" + std::to_string(elementId)
882 +
") not found, but elementGridMap[elementId] "
883 "with elementGridMap[elementId].size()="
884 + std::to_string(elementGridMap[elementId].size()) +
" contains mapped donor cells.");
888 m_elementDonorLevels[elementId].resize(noDonorCells);
889 m_elementDonorPos[elementId].resize(noDonorCells);
893 if(noDonorCells == 1) {
894 const MInt donorCellId = m_elementDonorMap[elementId][0];
895 const MInt donorLevel = donorSolver().grid().tree().level(donorCellId);
896 if(targetLevel > donorLevel) {
897 m_elementDonorLevels[elementId][0] = donorLevel - targetLevel;
898 m_elementDonorPos[elementId][0] = -1;
905 m_projection[polyDeg].calcProjectionInformation(noDonorCells, &donorCellLevels[0], &donorCellCoordinates[0],
906 targetLevel, targetElementCenter, m_elementDonorPos[elementId],
907 m_elementDonorLevels[elementId]);
917template <MInt nDim,
class CouplingDonor>
925 m_previousTime = time - dt;
927 RECORD_TIMER_START(m_timers[Timers::InitialCondition]);
930 loadMeanQuantities(
true);
931 RECORD_TIMER_STOP(m_timers[Timers::InitialCondition]);
939template <MInt nDim,
class CouplingDonor>
944 m_calcSourceElements.clear();
946 if(!m_hasDgCartesianSolver) {
948 m_elementInsideBody.clear();
952 const MInt filterOffset = m_maxNoNodesXD;
956 std::fill(hasNonZeroFilter.
begin(), hasNonZeroFilter.
end(),
false);
959 m_elementInsideBody.resize(noElements());
960 std::fill(m_elementInsideBody.begin(), m_elementInsideBody.end(), 0);
962 MInt noInsideElements = 0;
964 for(
MInt elementId = 0; elementId < noElements(); elementId++) {
965 const MInt noNodes1D = elements().polyDeg(elementId) + 1;
966 const MInt noNodesXD =
ipow(noNodes1D, nDim);
969 const MFloat*
const coordinates = &elements().nodeCoordinates(elementId);
972 MFloat*
const elementFilter = &m_filter[elementId * filterOffset];
975 m_sourceTermFilter.filter(coordinates, noNodesXD, elementFilter);
979 if(m_projectionFilter) {
980 MBool hasProjection =
false;
981 for(
MInt dimId = 0; dimId < nDim; dimId++) {
982 const MFloat coord = coordinates[dimId];
983 if(coord < m_projectionFilterBox[dimId] || coord > m_projectionFilterBox[nDim + dimId]) {
984 hasProjection =
true;
989 std::fill_n(elementFilter, noNodesXD, 0.0);
995 hasNonZeroFilter[elementId] =
996 std::any_of(elementFilter, elementFilter + noNodesXD, [](
MFloat filter) {
return filter > MFloatEps; });
1000 if(hasNonZeroFilter[elementId] && m_elementDonorMap[elementId].empty()) {
1001 m_elementInsideBody[elementId] = 1;
1004 hasNonZeroFilter[elementId] =
false;
1005 std::fill_n(elementFilter, noNodesXD, 0.0);
1008 std::cerr <<
"Element " << std::to_string(elementId)
1009 <<
" has nonzero filter value(s), but there are no donor "
1010 "cells mapped to this element. It will be considered to be inside the geometry."
1012 TERMM(1,
"TODO check! (element has nonzero filter but no donor cells)");
1017 AT_,
"MPI_IN_PLACE",
"noInsideElements");
1018 if(noInsideElements > 0) {
1019 m_log <<
"WARNING: Number of DG elements considered to be inside the geometry: " << noInsideElements << std::endl;
1020 if(dgSolver().domainId() == 0) {
1021 std::cerr <<
"WARNING: Number of DG elements considered to be inside the geometry: " << noInsideElements
1027 const MInt noNonZeroElements = std::count(hasNonZeroFilter.
begin(), hasNonZeroFilter.
end(),
true);
1028 m_calcSourceElements.resize(noNonZeroElements);
1033 for(
MInt elementId = 0, nonZeroElementId = 0; elementId < noElements(); elementId++) {
1034 if(hasNonZeroFilter[elementId]) {
1035 if(!m_elementDonorMap[elementId].empty()) {
1036 m_calcSourceElements[nonZeroElementId] = elementId;
1039 TERMM(1,
"Element " + std::to_string(elementId)
1040 +
" has nonzero filter value(s), but there are no donor "
1041 "cells mapped to this element. Go fix the source term "
1042 "filter in your property file.");
1048 if(m_hasDonorCartesianSolver) {
1049 for(
MInt i = 0; i < m_noDonorCells; i++) {
1050 const MFloat*
const coordinates = &donorSolver().a_coordinate(i, 0);
1051 MFloat*
const cellFilter = &m_filterDonor[i];
1053 m_sourceTermFilter.filter(coordinates, 1, cellFilter);
1062template <MInt nDim,
class CouplingDonor>
1067 NEW_TIMER_GROUP_NOCREATE(m_timers[Timers::TimerGroup],
1068 "CouplingDgApe (solverId = " + std::to_string(solverId()) +
")");
1069 NEW_TIMER_NOCREATE(m_timers[Timers::Class],
"total object lifetime", m_timers[Timers::TimerGroup]);
1070 RECORD_TIMER_START(m_timers[Timers::Class]);
1073 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Constructor],
"Constructor", m_timers[Timers::Class]);
1074 RECORD_TIMER_START(m_timers[Timers::Constructor]);
1077 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Init],
"init", m_timers[Timers::Class]);
1078 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::InitialCondition],
"calcInitialCondition", m_timers[Timers::Class]);
1079 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LoadMeanQuantities],
"loadMeanQuantities",
1080 m_timers[Timers::InitialCondition]);
1082 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::PreCouple],
"PreCouple", m_timers[Timers::Class]);
1083 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::StoreSources],
"storeSources", m_timers[Timers::PreCouple]);
1084 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LoadInstantaneous],
"loadInstantaneousQuantities",
1085 m_timers[Timers::StoreSources]);
1087 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcSources],
"calcSources", m_timers[Timers::StoreSources]);
1088 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcSourceLamb],
"calcSourceLamb", m_timers[Timers::CalcSources]);
1089 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcSourceQmII],
"calcSourceQmII", m_timers[Timers::CalcSources]);
1090 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcSourceQmIII],
"calcSourceQmIII", m_timers[Timers::CalcSources]);
1091 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcSourceQe],
"calcSourceQe", m_timers[Timers::CalcSources]);
1092 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::CalcSourceQc],
"calcSourceQc", m_timers[Timers::CalcSources]);
1094 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ProjectSourceTerms],
"projectSourceTerms", m_timers[Timers::StoreSources]);
1095 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::ApplyStoredSources],
"applyStoredSources", m_timers[Timers::PreCouple]);
1098 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::Accumulated],
"selected accumulated timers", m_timers[Timers::Class]);
1099 NEW_SUB_TIMER_NOCREATE(m_timers[Timers::LoadCouplingData],
"loadCouplingData", m_timers[Timers::Accumulated]);
1112template <MInt nDim,
class CouplingDonor>
1118 RECORD_TIMER_START(m_timers[Timers::Accumulated]);
1119 RECORD_TIMER_START(m_timers[Timers::LoadCouplingData]);
1122 ParallelIo file(filename, PIO_READ, dgSolver().grid().raw().mpiComm());
1126 MBool foundVariable =
false;
1128 std::vector<MString> datasets = file.getDatasetNames();
1130 for(
auto&& dataset : datasets) {
1131 if(file.hasAttribute(
"name", dataset)) {
1132 file.getAttribute(&variableName,
"name", dataset);
1133 if(variableName == name_) {
1134 datasetName = dataset;
1135 foundVariable =
true;
1142 ParallelIo::size_type count = 0;
1143 ParallelIo::size_type start = 0;
1145 if(m_hasDonorCartesianSolver) {
1146 count = donorSolver().noInternalCells();
1147 start = donorSolver().domainOffset(donorSolver().domainId());
1150 file.setOffset(count, start);
1151 file.readArray(data, datasetName, stride);
1153 const MInt noInternalCells = donorSolver().noInternalCells();
1154 performUnitConversion(variableName, noInternalCells, stride, data);
1157 RECORD_TIMER_STOP(m_timers[Timers::LoadCouplingData]);
1158 RECORD_TIMER_STOP(m_timers[Timers::Accumulated]);
1159 return foundVariable;
1166template <MInt nDim,
class CouplingDonor>
1169 RECORD_TIMER_START(m_timers[Timers::LoadMeanQuantities]);
1172 std::array<
MFloat, SysEqn::noNodeVars()> defaultNodeVars;
1173 sysEqn().getDefaultNodeVars(&defaultNodeVars[0]);
1176 std::array<
MFloat, SysEqn::noNodeVars()> defaultNodeVarsBody;
1177 sysEqn().getDefaultNodeVarsBody(&defaultNodeVarsBody[0]);
1180 MBool skipLoadMeanFile =
false;
1181 skipLoadMeanFile = Context::getSolverProperty<MBool>(
"skipLoadMeanFile", solverId(), AT_, &skipLoadMeanFile);
1185 if(!skipNodeVars && !skipLoadMeanFile) {
1186 m_log <<
"Coupling condition: loading node vars from mean file." << std::endl;
1187 MFloatScratchSpace data(std::max(m_noDonorCells, 1), SysEqn::noNodeVars(), AT_,
"data");
1189 std::vector<MInt> undefinedNodeVarIds;
1190 for(
MInt varId = 0; varId < SysEqn::noNodeVars(); varId++) {
1191 if(!loadCouplingData(m_meanDataFileName, MV::nodeVarNames[varId], SysEqn::noNodeVars(), &data(0, varId))) {
1193 undefinedNodeVarIds.push_back(varId);
1198 if(!undefinedNodeVarIds.empty()) {
1199 std::stringstream ss;
1200 ss <<
"Warning: Following dataset/s with attribute 'name' have not been found in file '" << m_meanDataFileName
1202 for(
MInt i : undefinedNodeVarIds) {
1203 ss << MV::nodeVarNames[i] <<
", ";
1205 ss << std::endl <<
"Those dataset/s have to be specified by the initial condition.";
1211 m_log << ss.str() << std::endl;
1215 const MBool previousLowPassFilterState = m_useLowPassFilter;
1216 m_useLowPassFilter =
false;
1219#pragma omp parallel for
1222 for(
MInt elementId = 0; elementId < noElements(); elementId++) {
1223 const MInt noDonorCells = m_elementDonorMap[elementId].size();
1224 const MInt noNonMappedCells = m_elementDonorPos[elementId].size() - noDonorCells;
1229 if((m_elementInsideBody[elementId] == 0) && noNonMappedCells == 0) {
1230 projectToElement(elementId, SysEqn::noNodeVars(), &data[0], &defaultNodeVars[0],
1231 &elements().nodeVars(elementId));
1233 projectToElement(elementId, SysEqn::noNodeVars(), &data[0], &defaultNodeVarsBody[0],
1234 &elements().nodeVars(elementId));
1239 m_useLowPassFilter = previousLowPassFilterState;
1241 m_log <<
"Coupling condition: skipped loading node vars from mean file." << std::endl;
1245 if(!skipLoadMeanFile) {
1246 MFloatScratchSpace meanVars(std::max(m_noDonorCells, 1), noMeanVars(), AT_,
"meanVars");
1247 m_log <<
"Coupling condition noMeanVars: " << noMeanVars() << std::endl;
1249 std::vector<MInt> undefinedMeanVarIds;
1250 for(
MInt varId = 0; varId < noMeanVars(); varId++) {
1251 m_log <<
"Load coupling data: " << varId <<
" " << MV::names[m_activeMeanVars[varId]] << std::endl;
1252 if(!loadCouplingData(m_meanDataFileName, MV::names[m_activeMeanVars[varId]], noMeanVars(), &meanVars[varId])) {
1254 undefinedMeanVarIds.push_back(varId);
1259 if(!undefinedMeanVarIds.empty()) {
1260 std::stringstream ss;
1261 ss <<
"Warning: Following dataset/s with attribute 'name' have not been found in file '" << m_meanDataFileName
1263 for(
MInt i : undefinedMeanVarIds) {
1264 ss << MV::names[m_activeMeanVars[i]] <<
", ";
1272 for(
MInt donorIndex = 0; donorIndex < m_noActiveDonorCells; donorIndex++) {
1273 const MInt donorId = m_calcSourceDonorCells[donorIndex];
1274 std::copy_n(&meanVars(donorId, 0), noMeanVars(), &m_meanVars[donorIndex * noMeanVars()]);
1277 m_log <<
"Coupling condition: skip loading mean vars, set to zero instead." << std::endl;
1278 std::fill(m_meanVars.begin(), m_meanVars.end(), 0.0);
1281 RECORD_TIMER_STOP(m_timers[Timers::LoadMeanQuantities]);
1296template <MInt nDim,
class CouplingDonor>
1300 const MInt polyDeg = elements().polyDeg(elementId);
1301 const MInt noNodesXD =
ipow(polyDeg + 1, nDim);
1302 const MInt noDonorCells = m_elementDonorMap[elementId].size();
1304 const MInt noNonMappedCells = m_elementDonorPos[elementId].size() - noDonorCells;
1307 if(noDonorCells > 1) {
1309 if(!m_useLowPassFilter || m_noCutModesLowPass == 0) {
1310 m_projection[polyDeg].apply(noDonorCells, noNonMappedCells, &m_elementDonorMap[elementId][0],
1311 &m_elementDonorLevels[elementId][0], &m_elementDonorPos[elementId][0], &data[0],
1312 defaultValues, noVars, target);
1315 m_projection[polyDeg - m_noCutModesLowPass].apply(
1316 noDonorCells, noNonMappedCells, &m_elementDonorMap[elementId][0], &m_elementDonorLevels[elementId][0],
1317 &m_elementDonorPos[elementId][0], &data[0], defaultValues, noVars, &tmp[0]);
1318 maia::dg::interpolation::interpolateNodes<nDim>(&tmp[0],
1319 &m_vdmLowPass[polyDeg - m_noCutModesLowPass][0],
1320 polyDeg + 1 - m_noCutModesLowPass,
1326 if(m_checkConservation || m_calcProjectionError) {
1327 if(noNonMappedCells > 0) {
1328 TERMM(1,
"Fix conservation/projection error comp. for the case with non-mapped cells");
1331 const MInt cellId = elements().cellId(elementId);
1332 const MFloat targetLength = dgSolver().grid().cellLengthAtCell(cellId);
1336 if(m_checkConservation) {
1337 m_projection[polyDeg].calcConservationError(noDonorCells, &m_elementDonorMap[elementId][0],
1338 &m_elementDonorLevels[elementId][0], &data[0], noVars, targetLength,
1339 target, &errors[0]);
1341 const MFloat maxError = *(std::max_element(errors.
begin(), errors.
end()));
1342 m_maxConservationError = std::max(m_maxConservationError, maxError);
1346 if(m_calcProjectionError) {
1347 m_projection[polyDeg].calcL2Error(noDonorCells, &m_elementDonorMap[elementId][0],
1348 &m_elementDonorLevels[elementId][0], &m_elementDonorPos[elementId][0],
1349 &data[0], noVars, targetLength, target, &errors[0]);
1352 const MFloat maxError = *(std::max_element(errors.
begin(), errors.
end()));
1353 m_maxL2Error = std::max(m_maxL2Error, maxError);
1356 }
else if(noDonorCells == 1) {
1361 const MInt donorCellId = m_elementDonorMap[elementId][0];
1362 const MInt offset = donorCellId * noVars;
1363 for(
MInt i = 0; i < noNodesXD; i++) {
1364 for(
MInt v = 0; v < noVars; v++) {
1365 targetF(i, v) = data[offset + v];
1371 for(
MInt i = 0; i < noNodesXD; i++) {
1372 for(
MInt v = 0; v < noVars; v++) {
1373 targetF(i, v) = defaultValues[v];
1383template <MInt nDim,
class CouplingDonor>
1387 m_log <<
"Saving file with filter values ... ";
1389 if(!m_hasDgCartesianSolver) {
1393 const std::vector<MString> filterVarName{
"sourcefilter:" + m_sourceTermFilter.name()};
1394 saveNodalData(
"sourcefilter", 1, filterVarName, &m_filter[0]);
1396 m_log <<
"done" << std::endl;
1400template <MInt nDim,
class CouplingDonor>
1403 m_log <<
"Saving file with filter values on donor cells... ";
1405 if(!m_hasDonorCartesianSolver) {
1409 std::stringstream fileName;
1410 fileName << donorSolver().outputDir() <<
"sourcefilterDonor" << ParallelIo::fileExt();
1413 ParallelIo parallelIo(fileName.str(), PIO_REPLACE, donorSolver().mpiComm());
1415 const MInt localNoCells = m_noDonorCells;
1417 ParallelIo::size_type offset = 0;
1418 ParallelIo::size_type globalNoCells = 0;
1419 parallelIo.calcOffset(localNoCells, &offset, &globalNoCells, donorSolver().mpiComm());
1422 parallelIo.setAttribute(globalNoCells,
"noCells");
1423 parallelIo.setAttribute(donorSolver().grid().gridInputFileName(),
"gridFile");
1424 parallelIo.setAttribute(donorSolver().solverId(),
"solverId");
1426 const MString name_ =
"sourcefilter:" + m_sourceTermFilter.name();
1427 parallelIo.defineArray(PIO_FLOAT, name_, globalNoCells);
1428 parallelIo.setOffset(localNoCells, offset);
1429 parallelIo.writeArray(&m_filterDonor[0], name_);
1431 m_log <<
"done" << std::endl;
1438template <MInt nDim,
class CouplingDonor>
1441 RECORD_TIMER_START(m_timers[Timers::ApplyStoredSources]);
1443 const MInt dataSize = m_maxNoNodesXD * SysEqn::noVars();
1455 const MInt noSourceElements = m_calcSourceElements.size();
1459 const MInt elementId = m_calcSourceElements[elementIndex];
1460 const MInt noNodes1D = elements().polyDeg(elementId) + 1;
1461 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
1462 MFloatTensor r(externalSource() + elementId * dataSize, noNodes1D, noNodes1D, noNodes1D3, SysEqn::noVars());
1463 MFloatTensor s(&m_sourceTerms[0] + elementIndex * dataSize, noNodes1D, noNodes1D, noNodes1D3, SysEqn::noVars());
1466 for(
MInt i = 0; i < noNodes1D; i++) {
1467 for(
MInt j = 0; j < noNodes1D; j++) {
1468 for(
MInt k = 0; k < noNodes1D3; k++) {
1469 for(
MInt l = 0; l < SysEqn::noVars(); l++) {
1470 r(i, j, k, l) += m_sourceFactor * s(i, j, k, l);
1477 RECORD_TIMER_STOP(m_timers[Timers::ApplyStoredSources]);
1491template <MInt nDim,
class CouplingDonor>
1494 RECORD_TIMER_START(m_timers[Timers::StoreSources]);
1497 MFloatScratchSpace velocity(std::max(m_noDonorCells, 1), noVelocities(), AT_,
"velocity");
1498 MFloatScratchSpace vorticity(std::max(m_noDonorCells, 1), noVorticities(), AT_,
"vorticity");
1504 RECORD_TIMER_START(m_timers[Timers::LoadInstantaneous]);
1505 getDonorVelocityAndVorticity(m_calcSourceDonorCells, velocity, vorticity);
1506 RECORD_TIMER_STOP(m_timers[Timers::LoadInstantaneous]);
1509 MFloatScratchSpace sourceTerms(std::max(m_noDonorCells, 1), SysEqn::noVars(), AT_,
"sourceTerms");
1510 std::fill(sourceTerms.
begin(), sourceTerms.
end(), 0.0);
1512 RECORD_TIMER_START(m_timers[Timers::CalcSources]);
1514 for(
auto&& sourceTerm : m_activeSourceTerms) {
1515 switch(sourceTerm) {
1518 calcSourceLambNonlinear(&velocity[0], &vorticity[0], &sourceTerms(0, 0));
1520 case ST::Q_mI_linear:
1522 calcSourceLambLinearized(&velocity[0], &vorticity[0], &sourceTerms(0, 0));
1526 calcSourceQmII(&velocity[0], &sourceTerms(0, 0));
1529 calcSourceQmIII(&velocity[0], &sourceTerms(0, 0));
1533 calcSourceQe(&velocity[0], time, &sourceTerms(0, 0));
1536 calcSourceQc(&velocity[0], &sourceTerms(0, 0), time, timeStep);
1539 TERMM(1,
"Source term '" + s_sourceTermNames[sourceTerm] +
"' not implemented.");
1543 RECORD_TIMER_STOP(m_timers[Timers::CalcSources]);
1546 m_isFirstSourceCalculation =
false;
1549 if(m_saveSourceTermsInterval > 0 && timeStep % m_saveSourceTermsInterval == 0 && m_saveSourceTermsDonorGrid) {
1553 saveSourceTermsDonorGrid(timeStep, &sourceTerms[0]);
1556 startLoadTimer(AT_);
1560 if(m_applySourceFilterDonor) {
1562 const MInt noVars = SysEqn::noVars();
1563 for(
MInt i = 0; i < m_noDonorCells; i++) {
1564 const MFloat filter = m_filterDonor[i];
1565 for(
MInt j = 0; j < noVars; j++) {
1566 sourceTerms[i * noVars + j] *= filter;
1579 const std::array<MFloat, MAX_SPACE_DIMENSIONS + 1> defaultSourceTerms = {{0.0, 0.0, 0.0, 0.0}};
1582 RECORD_TIMER_START(m_timers[Timers::ProjectSourceTerms]);
1583 const MInt noSourceElements = m_calcSourceElements.size();
1584 const MInt sourceOffset = m_maxNoNodesXD * SysEqn::noVars();
1587 const MInt elementId = m_calcSourceElements[elementIndex];
1588 const MInt noNodes1D = elements().polyDeg(elementId) + 1;
1589 const MInt noNodesXD =
ipow(noNodes1D, nDim);
1590 const MInt elementOffset = elementIndex * sourceOffset;
1592 MFloatTensor elementSourceTerms(&m_sourceTerms[elementOffset], noNodesXD, SysEqn::noVars());
1593 MFloatTensor filter(&m_filter[elementId * m_maxNoNodesXD], noNodesXD);
1596 projectToElement(elementId, SysEqn::noVars(), &sourceTerms[0], &defaultSourceTerms[0], &elementSourceTerms[0]);
1599 if(!m_applySourceFilterDonor) {
1600 for(
MInt i = 0; i < noNodesXD; i++) {
1601 for(
MInt v = 0; v < SysEqn::noVars(); v++) {
1602 elementSourceTerms(i, v) *= filter(i);
1607 RECORD_TIMER_STOP(m_timers[Timers::ProjectSourceTerms]);
1610 m_previousTime = time;
1613 if(m_saveSourceTermsInterval > 0 && timeStep % m_saveSourceTermsInterval == 0) {
1617 saveSourceTermsTargetGrid(timeStep);
1620 startLoadTimer(AT_);
1623 RECORD_TIMER_STOP(m_timers[Timers::StoreSources]);
1633template <MInt nDim,
class CouplingDonor>
1638 if(!m_hasDonorCartesianSolver) {
1642 const MInt noVariables = SysEqn::noVars();
1644 std::stringstream fileName;
1645 fileName << donorSolver().outputDir() <<
"sourceTermsDonorGrid_" << std::setw(8) << std::setfill(
'0') << timeStep
1646 << ParallelIo::fileExt();
1649 std::vector<MString> sourceTermNames(noVariables);
1650 if constexpr(nDim == 2) {
1651 sourceTermNames = std::vector<MString>{
"source_u",
"source_v",
"source_p"};
1653 sourceTermNames = std::vector<MString>{
"source_u",
"source_v",
"source_w",
"source_p"};
1658 ParallelIo parallelIo(fileName.str(), PIO_REPLACE, donorSolver().mpiComm());
1660 const MInt localNoCells = m_noDonorCells;
1662 ParallelIo::size_type offset = 0;
1663 ParallelIo::size_type globalNoCells = 0;
1664 parallelIo.calcOffset(localNoCells, &offset, &globalNoCells, donorSolver().mpiComm());
1667 parallelIo.setAttribute(globalNoCells,
"noCells");
1668 parallelIo.setAttribute(donorSolver().grid().gridInputFileName(),
"gridFile");
1669 parallelIo.setAttribute(donorSolver().solverId(),
"solverId");
1672 for(
MInt i = 0; i < noVariables; i++) {
1673 const MString name_ =
"variables" + std::to_string(i);
1674 parallelIo.defineArray(PIO_FLOAT, name_, globalNoCells);
1675 parallelIo.setAttribute(sourceTermNames[i],
"name", name_);
1678 parallelIo.setOffset(localNoCells, offset);
1681 for(
MInt i = 0; i < noVariables; i++) {
1682 const MString name_ =
"variables" + std::to_string(i);
1683 parallelIo.writeArray(&data[i], name_, noVariables);
1693template <MInt nDim,
class CouplingDonor>
1698 const MInt noVariables = SysEqn::noVars();
1699 const MInt dataSize = m_maxNoNodesXD * noVariables;
1705 const MInt noSourceElements = m_calcSourceElements.size();
1706 for(
MInt eId = 0; eId < noSourceElements; eId++) {
1707 const MInt elementId = m_calcSourceElements[eId];
1708 const MInt noNodesXD =
ipow(elements().polyDeg(elementId) + 1, nDim);
1711 MFloat*
const dest = &sourceTerms[elementId * dataSize];
1712 const MFloat*
const src = &m_sourceTerms[eId * dataSize];
1715 std::copy_n(src, noNodesXD * noVariables, dest);
1718 std::stringstream fileNameBase;
1719 fileNameBase <<
"sourceTerms_" << std::setw(8) << std::setfill(
'0') << timeStep;
1722 std::vector<MString> sourceTermNames(noVariables);
1723 if constexpr(nDim == 2) {
1724 sourceTermNames = std::vector<MString>{
"source_u",
"source_v",
"source_p"};
1726 sourceTermNames = std::vector<MString>{
"source_u",
"source_v",
"source_w",
"source_p"};
1730 saveNodalData(fileNameBase.str(), noVariables, sourceTermNames, &sourceTerms[0]);
1739template <MInt nDim,
class CouplingDonor>
1750 m_meanDataFileName = Context::getSolverProperty<MString>(
"meanDataFileName", solverId(), AT_);
1764 if(noSourceTerms == 0) {
1765 TERMM(1,
"No source term was specified.");
1768 MBool q_mI_active =
false;
1770 for(
MInt i = 0; i < noSourceTerms; i++) {
1771 const MString sourceTermName = Context::getSolverProperty<MString>(
"sourceTerms", solverId(), AT_, i);
1774 auto sourceTermIt = std::find(s_sourceTermNames.begin(), s_sourceTermNames.end(), sourceTermName);
1777 if(sourceTermIt == s_sourceTermNames.end()) {
1778 TERMM(1,
"The given source term '" + sourceTermName +
"' was not found.");
1782 const MInt sourceTerm = std::distance(s_sourceTermNames.begin(), sourceTermIt);
1785 if(std::find(m_activeSourceTerms.begin(), m_activeSourceTerms.end(), sourceTerm) != m_activeSourceTerms.end()) {
1786 TERMM(1,
"Given source term '" + sourceTermName +
"' already present. Check your property file.");
1790 if(sourceTerm == ST::Q_mI || sourceTerm == ST::Q_mI_linear) {
1792 TERMM(1,
"Source terms 'q_mI' and 'q_mI_linear' cannot be active at the same time.");
1798 m_activeSourceTerms.push_back(sourceTerm);
1801 std::sort(m_activeSourceTerms.begin(), m_activeSourceTerms.end());
1803 m_log <<
"Direct-hybrid CFD-CAA multi-solver coupling condition" << std::endl;
1804 m_log <<
"Activated coupling source terms:" << std::endl;
1805 for(
auto&& sourceTerm : m_activeSourceTerms) {
1806 m_log << s_sourceTermNames[sourceTerm] << std::endl;
1808 m_log <<
"Number of active source terms: " << noSourceTerms << std::endl;
1822 m_saveSourceTermsInterval = -1;
1823 m_saveSourceTermsInterval =
1824 Context::getSolverProperty<MInt>(
"saveSourceTermsInterval", solverId(), AT_, &m_saveSourceTermsInterval);
1834 m_saveSourceTermsDonorGrid =
false;
1835 m_saveSourceTermsDonorGrid =
1836 Context::getSolverProperty<MBool>(
"saveSourceTermsDonorGrid", solverId(), AT_, &m_saveSourceTermsDonorGrid);
1840 std::set<MInt> neededMeanVars;
1841 for(
auto&& sourceTerm : m_activeSourceTerms) {
1842 std::vector<MInt> sourceTermMeanVars;
1844 neededMeanVarsForSourceTerm(sourceTerm, sourceTermMeanVars);
1846 neededMeanVars.insert(sourceTermMeanVars.begin(), sourceTermMeanVars.end());
1848 m_activeMeanVars.assign(neededMeanVars.begin(), neededMeanVars.end());
1852 std::fill_n(m_meanVarsIndex.begin(), s_totalNoMeanVars, -1);
1853 MInt meanVarPos = 0;
1855 for(
MInt meanVar : m_activeMeanVars) {
1856 m_meanVarsIndex[meanVar] = meanVarPos;
1867 m_fixedTimeStep = Context::getSolverProperty<MFloat>(
"fixedTimeStep", solverId(), AT_, &m_fixedTimeStep);
1870 m_sourceTermFilter.init();
1880 m_applySourceFilterDonor =
false;
1881 m_applySourceFilterDonor =
1882 Context::getSolverProperty<MBool>(
"applySourceFilterDonor", solverId(), AT_, &m_applySourceFilterDonor);
1892 m_saveSourceTermFilter =
false;
1893 m_saveSourceTermFilter =
1894 Context::getSolverProperty<MBool>(
"saveSourceTermFilter", solverId(), AT_, &m_saveSourceTermFilter);
1904 m_checkConservation =
false;
1905 m_checkConservation = Context::getSolverProperty<MBool>(
"checkConservation", solverId(), AT_, &m_checkConservation);
1916 m_calcProjectionError =
false;
1917 m_calcProjectionError =
1918 Context::getSolverProperty<MBool>(
"calcProjectionError", solverId(), AT_, &m_calcProjectionError);
1927 m_sourceFactor = 1.0;
1928 m_sourceFactor = Context::getSolverProperty<MFloat>(
"sourceFactor", solverId(), AT_, &m_sourceFactor);
1937 m_noCutModesLowPass = 0;
1938 m_noCutModesLowPass = Context::getSolverProperty<MInt>(
"noCutModesLowPass", solverId(), AT_, &m_noCutModesLowPass);
1948 m_projectionFilter =
false;
1949 m_projectionFilter = Context::getSolverProperty<MBool>(
"projectionFilter", solverId(), AT_, &m_projectionFilter);
1951 if(m_projectionFilter) {
1952 m_log <<
"Using projection filter box" << std::endl;
1953 m_projectionFilterBox.resize(2 * nDim);
1954 for(
MInt i = 0; i < 2 * nDim; i++) {
1962 m_projectionFilterBox[i] = Context::getSolverProperty<MFloat>(
"projectionFilterBox", solverId(), AT_, i);
1963 m_log <<
"projection filter box " << i <<
" " << m_projectionFilterBox[i] << std::endl;
1977template <MInt nDim,
class CouplingDonor>
1979 std::vector<MInt>& meanVars)
const {
1983 switch(sourceTerm) {
1986 for(
MInt i = 0; i < nDim; i++) {
1987 meanVars.push_back(MV::LAMB0[i]);
1990 case ST::Q_mI_linear:
1992 for(
MInt i = 0; i < nDim; i++) {
1993 meanVars.push_back(MV::UU0[i]);
1996 for(
MInt i = 0; i < noVorticities(); i++) {
1997 meanVars.push_back(MV::VORT0[i]);
2002 meanVars.push_back(MV::RHO0);
2003 meanVars.push_back(MV::P0);
2005 for(
MInt i = 0; i < nDim; i++) {
2006 meanVars.push_back(MV::DRHO[i]);
2009 for(
MInt i = 0; i < nDim; i++) {
2010 meanVars.push_back(MV::DP[i]);
2013 for(
MInt i = 0; i < nDim; i++) {
2014 meanVars.push_back(MV::GRADPRHO[i]);
2019 for(
MInt i = 0; i < nDim; i++) {
2020 meanVars.push_back(MV::UU0[i]);
2023 for(
MInt i = 0; i < nDim * nDim; i++) {
2024 meanVars.push_back(MV::GRADU[i]);
2027 for(
MInt i = 0; i < nDim; i++) {
2028 meanVars.push_back(MV::UGRADU[i]);
2032 meanVars.push_back(MV::RHO0);
2033 meanVars.push_back(MV::P0);
2034 meanVars.push_back(MV::C0);
2036 for(
MInt i = 0; i < nDim; i++) {
2037 meanVars.push_back(MV::UU0[i]);
2040 for(
MInt i = 0; i < nDim; i++) {
2041 meanVars.push_back(MV::DC0[i]);
2044 for(
MInt i = 0; i < nDim; i++) {
2045 meanVars.push_back(MV::DU[i]);
2048 for(
MInt i = 0; i < nDim; i++) {
2049 meanVars.push_back(MV::DRHO[i]);
2052 for(
MInt i = 0; i < nDim; i++) {
2053 meanVars.push_back(MV::DP[i]);
2058 meanVars.push_back(MV::RHO0);
2059 meanVars.push_back(MV::P0);
2060 meanVars.push_back(MV::C0);
2062 for(
MInt i = 0; i < nDim; i++) {
2063 meanVars.push_back(MV::UU0[i]);
2066 for(
MInt i = 0; i < nDim; i++) {
2067 meanVars.push_back(MV::DU[i]);
2070 for(
MInt i = 0; i < nDim; i++) {
2071 meanVars.push_back(MV::DRHO[i]);
2074 for(
MInt i = 0; i < nDim; i++) {
2075 meanVars.push_back(MV::RHODIVU[i]);
2078 for(
MInt i = 0; i < nDim; i++) {
2079 meanVars.push_back(MV::UGRADRHO[i]);
2083 TERMM(1,
"Source term '" + s_sourceTermNames[sourceTerm] +
"' not implemented yet.");
static MInt propertyLength(const MString &name, MInt solverId=m_noSolvers)
Returns the number of elements of a property.
static T getSolverProperty(const MString name, const MInt solverId, const MString &nameOfCallingFunction, const T *default_value, MInt pos=0)
Intermediate class for coupling DG solver with APE sysEqn.
std::vector< std::vector< MInt > > m_elementDonorMap
Mapping from donor cells to elements.
void postCouple(MInt) override final
std::vector< std::vector< MInt > > m_elementDonorPos
Donor cell positions on the corresponding cell level.
static const std::array< MString, ST::totalNoSourceTerms > s_sourceTermNames
Hold indices for source terms.
void projectToElement(const MInt elementId, const MInt noVars, const MFloat *data, const MFloat *defaultValues, MFloat *target)
Project the given data fields onto a single element.
MFloat m_sourceFactor
Factor by which the source terms are multiplied.
std::vector< MInt > m_activeMeanVars
List of active mean variables for all active source terms.
virtual void performUnitConversion(const MString &, const MInt, const MInt, MFloat *)
std::vector< MFloat > m_filter
Local storage for source filter values.
MBool loadCouplingData(const MString &filename, const MString &name_, const MInt stride, MFloat *data)
Auxiliary method to load coupling data (i.e. anything coming from the LES) from a file.
std::vector< MFloatTensor > m_vdmLowPass
Vandermonde matrix/matrices for the low-pass filter.
static constexpr MInt noVelocities()
Return number of velocity variables.
std::vector< MFloat > m_sourceTerms
Local storage for source terms.
void getCouplingTimings(std::vector< std::pair< MString, MFloat > > &timings, const MBool allTimings) override
std::vector< MInt > m_calcSourceElements
List of all element ids for which source terms need to be computed.
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.
virtual void calcSourceLambLinearized(const MFloat *const velocity, const MFloat *const vorticity, MFloat *sourceTerms)=0
void saveSourceTermsDonorGrid(const MInt timeStep, const MFloat *const data)
Store the source terms on the donor grid.
MBool m_projectionFilter
Use spatial projection filter (i.e. exclude elements from the projection)
void initSourceFilter()
Calculate source filter values for all elements and store element ids on which source terms need to b...
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::vector< std::vector< MInt > > m_elementDonorLevels
Donor cell levels relative to element.
std::vector< MFloat > m_filterDonor
Local storage for source filter values on donor cells.
MInt m_previousTimeStep
Previous time step (to determine whether new sources need to be calculated)
void saveSourceTermsTargetGrid(const MInt timeStep)
Store the source terms on the target grid, i.e. after interpolation.
Filter< nDim > m_sourceTermFilter
Auxiliary object that handles source filtering.
void initData()
Initialize the data (initial conditions or for a restart) of the coupling condition.
virtual void calcSourceQmIII(const MFloat *const velocity, MFloat *sourceTerms)=0
void loadMeanQuantities(const MBool skipNodeVars=false)
Load mean velocities from file and store them to the node variables.
void saveFilterValues()
Save filter values to file.
std::array< MInt, Timers::_count > m_timers
virtual void calcSourceQe(const MFloat *const velocity, const MFloat time, MFloat *const sourceTerms)=0
void initProjection()
Initialize the projection information for spatial coupling.
void saveFilterValuesDonor()
Save the filter values on the donor cells.
static constexpr MInt noVorticities()
Return number of vorticity variables.
MBool m_calcProjectionError
Calculate the L2 error of the Galerkin projection.
virtual void calcSourceQc(const MFloat *const velocity, MFloat *const sourceTerms, const MFloat time, const MInt timeStep)=0
CouplingDgApe(const MInt couplingId, DgCartesianSolverType *dg, DonorSolverType *ds)
Initialize timers and read properties in c'tor.
virtual DonorSolverType & donorSolver(const MInt solverId=0) const =0
MString m_meanDataFileName
File name for mean quantities.
void applyStoredSources(const MFloat time)
Apply the stored source terms to the time derivative.
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.
MBool m_saveSourceTermFilter
Store whether filter values should be written to a file at initialization.
MBool m_applySourceFilterDonor
Apply source filter on donor cells or on DG elements after projection.
void initRestart(const MFloat time, const MFloat dt)
Perform initializations for a restart.
std::vector< ProjectionType > m_projection
Galerkin projection (access by polynomial degree)
MInt m_noDonorCells
Total number of donor cells on this domain.
MInt m_noCutModesLowPass
Number of modes to cut using the low-pass source term.
MInt m_saveSourceTermsInterval
Interval at which source term data should be saved to disk.
virtual void getDonorVelocityAndVorticity(const std::vector< MInt > &donorCellIds, MFloatScratchSpace &p_velocity, MFloatScratchSpace &p_vorticity)=0
void checkProperties() override final
MFloat m_previousTime
Previous time for the calculation of time derivatives.
void initCoupler()
Initialize the coupling condition (data structures).
MInt m_noActiveDonorCells
MBool m_useLowPassFilter
Switch low pass on and off to allow disabling e.g. for node vars.
void getDomainDecompositionInformation(std::vector< std::pair< MString, MInt > > &domainInfo) override final
MBool m_hasDonorCartesianSolver
Store whether this domain has Cartesian donor solver cells.
void finalizeSubCoupleInit(MInt) override final
void preCouple(MInt) final
Calculate source terms and add to the external source terms of the DG solver.
virtual void calcSourceQmII(const MFloat *const velocity, MFloat *const sourceTerms)=0
MFloat m_fixedTimeStep
Fixed time step to use.
std::vector< MFloat > m_projectionFilterBox
Spatial projection filter box (excluding)
std::vector< MInt > m_activeSourceTerms
List of active source terms.
typename BaseDonor::solverType DonorSolverType
virtual ~CouplingDgApe()=default
void subCouple(MInt, MInt, std::vector< MBool > &) override final
void initTimers()
Create timers.
void neededMeanVarsForSourceTerm(const MInt sourceTerm, std::vector< MInt > &meanVars) const
Return the needed mean variables for a given source term.
MBool m_hasDgCartesianSolver
Store whether this domain has DG cells/elements.
std::vector< MInt > m_elementInsideBody
Marker if elements are inside a geometric object.
MInt noCouplingTimers(const MBool allTimings) const override
std::vector< MFloat > m_meanVars
Local storage for mean variables of the donor cells.
void cleanUp() override final
MFloat m_maxConservationError
Maximum conservation error.
void storeSources(const MFloat time, const MInt timeStep)
Load coupling data from LES, then calculate, accumulate, project and store coupling source terms.
MInt m_maxNoNodesXD
Maximum number of nodes of an element (corresponding to maxPolyDeg)
MBool m_saveSourceTermsDonorGrid
Store whether the sources on the donor grid should be saved as well.
virtual void calcSourceLambNonlinear(const MFloat *const velocity, const MFloat *const vorticity, MFloat *const sourceTerms)=0
void calcInitialCondition(const MFloat time)
Apply initial conditions for this coupling condition.
void readProperties() override final
Read properties and store in member variables.
static const MInt s_totalNoMeanVars
typename BaseDg::solverType DgCartesianSolverType
MFloat * externalSource() const
Return pointer to external source memory.
DgCartesianSolver< nDim, DgSysEqnAcousticPerturb< nDim > > solverType
MInt noElements() const
Return number of elements.
MInt minPolyDeg() const
Return the minimum polynomial degree.
DgSysEqnAcousticPerturb< nDim > & sysEqn()
Return reference to SysEqn object.
void saveNodalData(const MString &fileNameBase, const MInt noVars, const std::vector< MString > &varNames, const MFloat *const data) const
Save nodal data to file.
ElementCollector & elements()
Return reference to elements.
solverType & dgSolver() const
Return MPI communicator.
MInt solverId() const
Return solver id.
MInt maxPolyDeg() const
Return the maximum polynomial degree.
MFloat returnIdleRecord() const
void stopLoadTimer(const MString &name) const
Stop the load timer of the coupler.
void startLoadTimer(const MString &name) const
Start the load timer of the coupler.
MFloat returnLoadRecord() const
Performs the Galerkin projection for a given polynomial degree.
Class stores precalculated values for interpolation & integration on the reference interval [-1,...
void enableAllDlbTimers(const MBool *const wasEnabled=nullptr)
Enable all DLB timers (or those given by the array wasEnabled)
void disableAllDlbTimers(MBool *const wasEnabled=nullptr)
Disable all (enabled) DLB timers.
Filter object for source terms.
This class is a ScratchSpace.
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
MInt ipow(MInt base, MInt exp)
Integer exponent function for non-negative exponents.
std::basic_string< char > MString
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
void calcPolynomialInterpolationMatrix(MInt noNodesIn, const T nodesIn, MInt noNodesOut, const U nodesOut, const V wBary, W vandermonde)
Calculate the polynomial interpolation matrix (Vandermonde) to interpolate from one set of nodes to a...
DlbTimerController g_dlbTimerController
void parallelFor(MInt begin, MInt end, UnaryFunction &&f)
Wrapper function for parallel for loop.
PARALLELIO_DEFAULT_BACKEND ParallelIo
static const std::array< MString, totalNoMeanVars > names
static const std::array< MString, 6 > nodeVarNames
static const std::array< MString, 8 > nodeVarNames
static const std::array< MString, totalNoMeanVars > names