MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
dgcartesiangalerkinprojection.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 DGGALERKINPROJECTION_H_
8#define DGGALERKINPROJECTION_H_
9
11#include "INCLUDE/maiatypes.h"
12#include "MEMORY/scratch.h"
14#include "enums.h"
16
17// Forward declare auxiliary method
18namespace maia {
19namespace dg {
20namespace projection {
21template <MInt nDim>
22inline void indices(const MInt i, const MInt n, MInt* const ids);
23}
24} // namespace dg
25} // namespace maia
26
31template <MInt nDim>
33 // Member methods
34 public:
36 DgGalerkinProjection(const MInt polyDeg, const MInt noLevels, const MFloat lengthLevel0, const MInt solverId);
38
39 void calcProjectionInformation(const MInt noDonorCells,
40 const MInt* donorCellLvls,
41 const MFloat* donorCellCoordinates,
42 const MInt targetLvl,
43 const MFloat* targetElementCenter,
44 std::vector<MInt>& donorIds,
45 std::vector<MInt>& donorLvls) const;
46
47 void apply(const MInt noDonorCells, const MInt noNonMappedCells, const MInt* donorCellIds, const MInt* donorCellLvls,
48 const MInt* donorCellPos, const MFloat* const donorField, const MFloat* const defaultValues,
49 const MInt noVars, MFloat* const targetField) const;
50
51 void calcConservationError(const MInt noDonorCells, const MInt* donorCellIds, const MInt* donorCellLvls,
52 const MFloat* donorField, const MInt noVars, const MFloat targetLength,
53 const MFloat* targetField, MFloat* errors) const;
54
55 void calcL2Error(const MInt noDonorCells, const MInt* donorCellIds, const MInt* donorCellLvls,
56 const MInt* donorCellPos, const MFloat* donorField, const MInt noVars, const MFloat targetLength,
57 const MFloat* targetField, MFloat* errors) const;
58
59 private:
60 void init(MInt polyDeg, const MInt noLevels, const MFloat lengthLevel0, const MInt solverId);
62
63 // Member variables
64 private:
65 // Polynomial degree.
67 // Number of nodes
69 // Relative number of refinement levels (i.e. range between the coarsest and
70 // the finest level)
72 // Cell lenght at level zero
74
75 // Solver id (needed for reading properties)
77
78 // Integration weights
80
81 // Galerkin projection vectors
82 // For each level: store the mixed mass matrix entry of each donor cell on
83 // this level for each target node
84 std::vector<MFloatTensor> m_MTD{};
85
86 // Evaluated Lagrange polynomials for the projection error calculation
87 std::vector<MFloatTensor> m_polynomials{};
88 // Tolerance for conservation error calculation of the projection
89 const MFloat m_tolerance = 1e-12;
90
91 // Cell center positions for all cells on all considered levels
93 // Cell lengths for all considered levels
95};
96
97
111template <MInt nDim>
113 const MInt noNonMappedCells,
114 const MInt* donorCellIds,
115 const MInt* donorCellLevels,
116 const MInt* donorCellPos,
117 const MFloat* const donorField,
118 const MFloat* const defaultValues,
119 const MInt noVars,
120 MFloat* const targetField) const {
121 MFloatTensor target(targetField, m_noNodesXD, noVars);
122 // Set target field to zero
123 std::fill_n(&targetField[0], m_noNodesXD * noVars, 0.0);
124
125 // Compute target field
126 // Loop over all donor cells
127 for(MInt l = 0; l < noDonorCells; l++) {
128 // Weights of this donor cell on all target nodes
129 // TODO labels:DG,totest,toenhance Check at some point in the future if the very indirect access to
130 // the projection weights is too slow and should be optimized
131 const MFloat* const weight = &m_MTD[donorCellLevels[l]](donorCellPos[l], 0);
132 // Variables of donor cell
133 const MFloat* const donorVars = &donorField[donorCellIds[l] * noVars];
134
135 // Loop over all target nodes
136 for(MInt i = 0; i < m_noNodesXD; i++) {
137 // Loop over all variables
138 for(MInt v = 0; v < noVars; v++) {
139 target(i, v) += weight[i] * donorVars[v];
140 }
141 }
142 }
143
144 // Use defaul values for all non-mapped cells (i.e. cells of the mapped volume that are missing)
145 for(MInt l = noDonorCells; l < noDonorCells + noNonMappedCells; l++) {
146 const MFloat* const weight = &m_MTD[donorCellLevels[l]](donorCellPos[l], 0);
147 // Loop over all target nodes
148 for(MInt i = 0; i < m_noNodesXD; i++) {
149 // Loop over all variables
150 for(MInt v = 0; v < noVars; v++) {
151 target(i, v) += weight[i] * defaultValues[v];
152 }
153 }
154 }
155}
156
157
178template <MInt nDim>
179void DgGalerkinProjection<nDim>::calcConservationError(const MInt noDonorCells, const MInt* donorCellIds,
180 const MInt* donorCellLevels, const MFloat* donorField,
181 const MInt noVars, const MFloat targetLength,
182 const MFloat* targetField, MFloat* errors) const {
183 TRACE();
184
185 const MInt noNodes1D = m_polyDeg + 1;
186 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
187
188 const MFloatTensor target(const_cast<MFloat*>(targetField), noNodes1D, noNodes1D, noNodes1D3, noVars);
189
190 // Jacobian of the element transformation
191 const MFloat elementJacobian = (nDim == 2) ? POW2(F1B2 * targetLength) : POW3(F1B2 * targetLength);
192
193 MFloatScratchSpace donorIntegral(noVars, AT_, "donorIntegral");
194 std::fill(donorIntegral.begin(), donorIntegral.end(), 0.0);
195 MFloatScratchSpace targetIntegral(noVars, AT_, "targetIntegral");
196 std::fill(targetIntegral.begin(), targetIntegral.end(), 0.0);
197
198 // Calculate donor integral over all donor cells ...
199 for(MInt l = 0; l < noDonorCells; l++) {
200 const MInt dLevel = donorCellLevels[l];
201 const MInt nCellsOnLevel = IPOW2(dLevel);
202
203 const MFloat donorLength = targetLength / nCellsOnLevel;
204 const MFloat volume = (nDim == 2) ? POW2(donorLength) : POW3(donorLength);
205
206 const MInt donorCellOffset = donorCellIds[l] * noVars;
207 // ... for all variables
208 for(MInt varId = 0; varId < noVars; varId++) {
209 donorIntegral[varId] += volume * donorField[donorCellOffset + varId];
210 }
211 }
212
213 // Calculate target integral for all variables
214 IF_CONSTEXPR(nDim == 2) { // 2D
215 for(MInt i = 0; i < noNodes1D; i++) {
216 for(MInt j = 0; j < noNodes1D; j++) {
217 const MFloat weight = m_wInt(i) * m_wInt(j);
218 for(MInt varId = 0; varId < noVars; varId++) {
219 targetIntegral[varId] += weight * target(i, j, 0, varId);
220 }
221 }
222 }
223 }
224 else { // 3D
225 for(MInt i = 0; i < noNodes1D; i++) {
226 for(MInt j = 0; j < noNodes1D; j++) {
227 for(MInt k = 0; k < noNodes1D; k++) {
228 const MFloat weight = m_wInt(i) * m_wInt(j) * m_wInt(k);
229 for(MInt varId = 0; varId < noVars; varId++) {
230 targetIntegral[varId] += weight * target(i, j, k, varId);
231 }
232 }
233 }
234 }
235 }
236
237 // Multiply target integral with jacobian of the transformation
238 for(MInt varId = 0; varId < noVars; varId++) {
239 targetIntegral[varId] *= elementJacobian;
240 }
241
242 // Check if donor and target integrals match
243 for(MInt varId = 0; varId < noVars; varId++) {
244 errors[varId] = ABS(donorIntegral[varId] - targetIntegral[varId]);
245
246 // Exit with error if conservation error is too large
247 if(errors[varId] > m_tolerance) {
248 std::stringstream errorMsg;
249 errorMsg << "targetIntegral doesn't match donorIntegral! (donorIntegral = " << std::scientific
250 << donorIntegral[varId] << "; targetIntegral = " << targetIntegral[varId]
251 << "; error = " << errors[varId] << "; m_tolerance = " << m_tolerance << ")";
252
253 TERMM(1, errorMsg.str());
254 }
255 }
256}
257
258
279template <MInt nDim>
280void DgGalerkinProjection<nDim>::calcL2Error(const MInt noDonorCells, const MInt* donorCellIds,
281 const MInt* donorCellLevels, const MInt* donorCellPos,
282 const MFloat* donorField, const MInt noVars, const MFloat targetLength,
283 const MFloat* targetField, MFloat* errors) const {
284 TRACE();
285
286 using namespace maia::dg::projection;
287
288 const MInt noNodes1D = m_polyDeg + 1;
289 const MInt noNodes1D3 = (nDim == 3) ? noNodes1D : 1;
290
291 const MFloatTensor target(const_cast<MFloat*>(targetField), m_noNodesXD, noVars);
292 const MFloat elementJacobian = (nDim == 2) ? POW2(F1B2 * targetLength) : POW3(F1B2 * targetLength);
293
294 MInt intervals[3], index[3];
295
296 std::fill_n(&errors[0], noVars, 0.0);
297
298 // Loop over all donor cells
299 for(MInt l = 0; l < noDonorCells; l++) {
300 const MInt dLevel = donorCellLevels[l];
301 const MInt nCellsOnLevel = IPOW2(dLevel);
302
303 const MFloat donorXiLength = m_cellLengths[dLevel];
304 const MFloat donorCellJacobian = (nDim == 2) ? POW2(F1B2 * donorXiLength) : POW3(F1B2 * donorXiLength);
305
306 const MInt donorCellOffset = donorCellIds[l] * noVars;
307
308 // Compute donor cell index for all directions
309 indices<nDim>(donorCellPos[l], nCellsOnLevel, intervals);
310
311 // Loop over all integration nodes on donor cell
312 for(MInt u = 0; u < noNodes1D; u++) {
313 for(MInt k = 0; k < noNodes1D; k++) {
314 for(MInt j = 0; j < noNodes1D3; j++) {
315 std::vector<MFloat> sum(noVars, 0.0);
316
317 // Loop over all nodes of element
318 for(MInt i = 0; i < m_noNodesXD; i++) {
319 indices<nDim>(i, noNodes1D, index); // Node position
320
321 // Multiply Lagrange polynomials
322 MFloat tmp =
323 m_polynomials[dLevel](intervals[0], u, index[0]) * m_polynomials[dLevel](intervals[1], k, index[1]);
324 IF_CONSTEXPR(nDim == 3) { tmp *= m_polynomials[dLevel](intervals[2], j, index[2]); }
325
326 // Add contribution of current element node
327 for(MInt varId = 0; varId < noVars; varId++) {
328 sum[varId] += tmp * target(i, varId);
329 }
330 }
331
332 MFloat factor = m_wInt(u) * m_wInt(k) * elementJacobian * donorCellJacobian;
333 IF_CONSTEXPR(nDim == 3) { factor *= m_wInt(j); }
334
335 // Add to projection error
336 for(MInt varId = 0; varId < noVars; varId++) {
337 const MFloat square = POW2(donorField[donorCellOffset + varId] - sum[varId]);
338 errors[varId] += factor * square;
339 }
340 }
341 }
342 }
343 }
344}
345
346
347namespace maia {
348namespace dg {
349namespace projection {
350
363template <MInt nDim>
364inline void indices(const MInt i, const MInt n, MInt* const ids) {
365 const MInt f1 = i / n;
366
367 IF_CONSTEXPR(nDim == 2) {
368 ids[0] = f1;
369 ids[1] = i - f1 * n;
370 }
371 else {
372 const MInt f2 = i / (n * n);
373
374 ids[0] = f2;
375 ids[1] = f1 - f2 * n;
376 ids[2] = i - f1 * n;
377 }
378}
379
380} // namespace projection
381} // namespace dg
382} // namespace maia
383
384
385#endif /* DGGALERKINPROJECTION_H_ */
Performs the Galerkin projection for a given polynomial degree.
void calcProjectionInformation(const MInt noDonorCells, const MInt *donorCellLvls, const MFloat *donorCellCoordinates, const MInt targetLvl, const MFloat *targetElementCenter, std::vector< MInt > &donorIds, std::vector< MInt > &donorLvls) const
Compute the projection information for one target cell.
~DgGalerkinProjection()
Destructor clears all member variables.
void calcL2Error(const MInt noDonorCells, const MInt *donorCellIds, const MInt *donorCellLvls, const MInt *donorCellPos, const MFloat *donorField, const MInt noVars, const MFloat targetLength, const MFloat *targetField, MFloat *errors) const
Calculate the L2 projection error.
void apply(const MInt noDonorCells, const MInt noNonMappedCells, const MInt *donorCellIds, const MInt *donorCellLvls, const MInt *donorCellPos, const MFloat *const donorField, const MFloat *const defaultValues, const MInt noVars, MFloat *const targetField) const
Apply the Galerkin projection using the provided information.
void init(MInt polyDeg, const MInt noLevels, const MFloat lengthLevel0, const MInt solverId)
Initialize the member variables and calculate the interpolation matrices.
std::vector< MFloatTensor > m_MTD
DgGalerkinProjection()=default
void calcConservationError(const MInt noDonorCells, const MInt *donorCellIds, const MInt *donorCellLvls, const MFloat *donorField, const MInt noVars, const MFloat targetLength, const MFloat *targetField, MFloat *errors) const
Calculate the Galerkin projection conservation error and check against tolerance.
void calcInterpolationMatrices()
Calculate and store the needed interpolation matrices.
std::vector< MFloatTensor > m_polynomials
This class is a ScratchSpace.
Definition: scratch.h:758
iterator end()
Definition: scratch.h:281
iterator begin()
Definition: scratch.h:273
constexpr Real POW3(const Real x)
Definition: functions.h:123
constexpr Real POW2(const Real x)
Definition: functions.h:119
Real ABS(const Real x)
Definition: functions.h:85
constexpr MLong IPOW2(MInt x)
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52
void indices(const MInt i, const MInt n, MInt *const ids)
Calculate the 2D/3D indices for a given scalar id for accessing a field of n^nDim points.
Namespace for auxiliary functions/classes.