MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
DgGalerkinProjection< nDim > Class Template Reference

Performs the Galerkin projection for a given polynomial degree. More...

#include <dgcartesiangalerkinprojection.h>

Collaboration diagram for DgGalerkinProjection< nDim >:
[legend]

Public Member Functions

 DgGalerkinProjection ()=default
 
 DgGalerkinProjection (const MInt polyDeg, const MInt noLevels, const MFloat lengthLevel0, const MInt solverId)
 Constructor passes arguments to init(). More...
 
 ~DgGalerkinProjection ()
 Destructor clears all member variables. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 

Private Member Functions

void init (MInt polyDeg, const MInt noLevels, const MFloat lengthLevel0, const MInt solverId)
 Initialize the member variables and calculate the interpolation matrices. More...
 
void calcInterpolationMatrices ()
 Calculate and store the needed interpolation matrices. More...
 

Private Attributes

MInt m_polyDeg = -1
 
MInt m_noNodesXD = -1
 
MInt m_noLevels = -1
 
MFloat m_lengthLevel0 = -1.0
 
MInt m_solverId = -1
 
MFloatTensor m_wInt {}
 
std::vector< MFloatTensorm_MTD {}
 
std::vector< MFloatTensorm_polynomials {}
 
const MFloat m_tolerance = 1e-12
 
MFloatTensor m_cellCenters {}
 
MFloatTensor m_cellLengths {}
 

Detailed Description

template<MInt nDim>
class DgGalerkinProjection< nDim >
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-07-17

Definition at line 32 of file dgcartesiangalerkinprojection.h.

Constructor & Destructor Documentation

◆ DgGalerkinProjection() [1/2]

template<MInt nDim>
DgGalerkinProjection< nDim >::DgGalerkinProjection ( )
default

◆ DgGalerkinProjection() [2/2]

template<MInt nDim>
DgGalerkinProjection< nDim >::DgGalerkinProjection ( const MInt  polyDeg,
const MInt  noLevels,
const MFloat  lengthLevel0,
const MInt  solverId 
)
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-06-01
Parameters
[in]polyDegPolynomial degree of projection.
[in]noLevelsRelative number of refinement levels, i.e. the range between the coarsest and the finest level.
[in]lenghtLevel0Cell length on level zero.
[in]solverIdSolver id.

Definition at line 32 of file dgcartesiangalerkinprojection.cpp.

33 {
34 TRACE();
35
36 init(polyDeg, noLevels, lengthLevel0, solverId);
37}
void init(MInt polyDeg, const MInt noLevels, const MFloat lengthLevel0, const MInt solverId)
Initialize the member variables and calculate the interpolation matrices.

◆ ~DgGalerkinProjection()

Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-06-01

Definition at line 45 of file dgcartesiangalerkinprojection.cpp.

45 {
46 TRACE();
47
48 m_polyDeg = -1;
49 m_noNodesXD = -1;
50 m_noLevels = -1;
51 m_lengthLevel0 = -1.0;
52 m_solverId = -1;
53 m_wInt.clear(), m_MTD.clear();
54 m_polynomials.clear();
57}
std::vector< MFloatTensor > m_MTD
std::vector< MFloatTensor > m_polynomials
void clear()
Deletes the data (if internal storage was used) and resets dimensions to zero.
Definition: tensor.h:283

Member Function Documentation

◆ apply()

template<MInt nDim>
void DgGalerkinProjection< nDim >::apply ( const MInt  noDonorCells,
const MInt  noNonMappedCells,
const MInt donorCellIds,
const MInt donorCellLevels,
const MInt donorCellPos,
const MFloat *const  donorField,
const MFloat *const  defaultValues,
const MInt  noVars,
MFloat *const  targetField 
) const
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-06-01
Parameters
[in]noDonorCellsNumber of donor cells.
[in]noNonMappedCellsNumber of non mapped cells/volumes.
[in]donorCellIdsIds of the donor cells involved in the projection.
[in]donorCellLevelsRelative levels of the donor cells (including non-mapped cells).
[in]donorCellPosDonor cell positions (index on cell level; incl. non-mapped cells).
[in]donorFieldVariable values of all donor cells.
[in]noVarsNumber of variables.
[out]targetFieldTarget element variables.

Definition at line 112 of file dgcartesiangalerkinprojection.h.

120 {
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}
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52

◆ calcConservationError()

template<MInt nDim>
void DgGalerkinProjection< nDim >::calcConservationError ( const MInt  noDonorCells,
const MInt donorCellIds,
const MInt donorCellLevels,
const MFloat donorField,
const MInt  noVars,
const MFloat  targetLength,
const MFloat targetField,
MFloat errors 
) const
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-06-01
Parameters
[in]noDonorCellsNumber of donor cells.
[in]donorCellLevelsRelative levels of donor cells.
[in]donorFieldDonor field values.
[in]noVarsNumber of variables.
[in]targetLengthLength of the target element.
[in]targetFieldComputed target field.
[out]errorsComputed conservation errors.

The conservation error of the Galerkin projection is defined as: E_C = |\int_{Q_T} (q_D - q_T) dV| i.e. the absolute difference of the donor field and the target field integrated over the target element. If any of the computed conservation errors exceeds a tolerance of 1e-12 the simulation will abort.

Definition at line 179 of file dgcartesiangalerkinprojection.h.

182 {
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}
This class is a ScratchSpace.
Definition: scratch.h:758
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)

◆ calcInterpolationMatrices()

template<MInt nDim>
void DgGalerkinProjection< nDim >::calcInterpolationMatrices
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-06-01

The Galerkin projection can generally be written as: q_T = (M_T)^-1 * sum_{l=1}^{S} (M_TDl * q_Dl) with q_T the target field and q_Dl the piecewise constant solutions of the donor cells 1 to l. The mass matrix M_T contains the integration weights of each node on the diagonal, thus inverting it is trivial. The vector M_TDl contains the weighting of the l-th donor cell solution on each target element node. Given the Cartesian grid structure the vectors M_TDl can be precomputed for all relative refinement levels between the donor and the target grid and all cells on these levels. This method computes the vectors M_TD and premultiplies them with the inverse mass matrix. The projection then has the form: q_T[nodeId] = sum_{l=1}^{S} (MTD[donorLevel][donorPos][nodeId] * q_Dl) where donorLevel and donorPos is the relative level and position of the donor cell relative to the target cell.

Further, the polynomials are evaluated at all integration nodes on all cells on all levels (in 1D) to allow evaluation of the L2 projection error.

For more information refer to: "Conservative Galerkin projection for hybrid computational aeroacoustics on hierarchical Cartesian grids", Ansgar Marwege, Bachelor Thesis

Definition at line 148 of file dgcartesiangalerkinprojection.cpp.

148 {
149 TRACE();
150
151 // Check for SBP Mode
152 const MBool defaultSbpMode = false;
153 const MBool sbpMode = Context::getSolverProperty<MBool>("sbpMode", m_solverId, AT_, &defaultSbpMode);
154
155 // Determine SBP Operator
156 const MString defaultSbpOperator = "";
157 const MString sbpOperator = Context::getSolverProperty<MString>("sbpOperator", m_solverId, AT_, &defaultSbpOperator);
158
159 MInt initNoNodes1D = -1;
160 initNoNodes1D = Context::getSolverProperty<MInt>("initNoNodes", m_solverId, AT_, &initNoNodes1D);
161
162 const MInt noNodes1D = sbpMode ? initNoNodes1D : (m_polyDeg + 1);
163 const MInt maxNoCellsOnLevel = IPOW2(m_noLevels - 1);
164
165 // Determine DG integration method (same as in dgsolver.cpp)
166 MString defaultDgIntegrationMethod = "DG_INTEGRATE_GAUSS";
167 const MInt dgIntegrationMethod = string2enum(
168 Context::getSolverProperty<MString>("dgIntegrationMethod", m_solverId, AT_, &defaultDgIntegrationMethod));
169
170 // Determine DG polynomial type (same as in dgsolver.cpp)
171 MString defaultDgPolynomialType = "DG_POLY_LEGENDRE";
172 const MInt dgPolynomialType =
173 string2enum(Context::getSolverProperty<MString>("dgPolynomialType", m_solverId, AT_, &defaultDgPolynomialType));
174
175 // Convert integers to enums
176 DgPolynomialType polyType = static_cast<DgPolynomialType>(dgPolynomialType);
177 DgIntegrationMethod intMethod = static_cast<DgIntegrationMethod>(dgIntegrationMethod);
178
179 // Create interpolation object
180 DgInterpolation interpolation(m_polyDeg, polyType, noNodes1D, intMethod, sbpMode, sbpOperator);
181
182 // Create convenience pointers
183 const MFloatVector& wInt = interpolation.m_wInt;
184 const MFloatVector& wBary = interpolation.m_wBary;
185 const MFloatVector& nodes = interpolation.m_nodes;
186
187 // Store integration weights in class for later use
188 m_wInt = wInt;
189
190 // Storage for evaluating the lagrange polynomials at a given position
191 ScratchSpace<MFloat> polynomials(m_polyDeg + 1, AT_, "polynomials");
192 // Storage for inverse mass matrix (diagonal)
193 ScratchSpace<MFloat> MT_inverse(m_noNodesXD, AT_, "MT_inverse");
194 // Storage for 1D-vectors
195 ScratchSpace<MFloat> vector1D(m_noLevels, maxNoCellsOnLevel, noNodes1D, AT_, "vector1D");
196
197 std::array<MInt, nDim> index;
198 // Calculate inverted mass matrix with the integration weights
199 IF_CONSTEXPR(nDim == 2) {
200 for(MInt i = 0; i < m_noNodesXD; i++) {
201 indices<nDim>(i, noNodes1D, &index[0]);
202 MT_inverse[i] = 1.0 / (wInt(index[0]) * wInt(index[1]));
203 }
204 }
205 else {
206 for(MInt i = 0; i < m_noNodesXD; i++) {
207 indices<nDim>(i, noNodes1D, &index[0]);
208 MT_inverse[i] = 1.0 / (wInt(index[0]) * wInt(index[1]) * wInt(index[2]));
209 }
210 }
211
212 // Compute 1D-vectors
213 // i.e. on all relative refinement levels: the weight of each donor cell on
214 // this level for each target node of the element (in one dimension)
215 // Loop over all (relative) refinement levels, start with highest level
216 for(MInt level = m_noLevels - 1; level >= 0; level--) {
217 const MInt noCellsOnLevel = IPOW2(level);
218 const MFloat lengthOnLevel = m_cellLengths[level];
219
220 // Loop over all possible donor cells on this level
221 for(MInt l = 0; l < noCellsOnLevel; l++) {
222 // Loop over all target nodes
223 for(MInt j = 0; j < noNodes1D; j++) {
224 MFloat sumXi = 0.0;
225 // On the finest level do the integration by quadrature
226 if(level == m_noLevels - 1) {
227 // Loop over quadrature points
228 for(MInt k = 0; k < noNodes1D; k++) {
229 // Node position on reference element [-1,1]
230 const MFloat xiPos = m_cellCenters(level, l) + 0.5 * lengthOnLevel * nodes[k];
231
232 // Evaluate Lagrange polynomials
233 if(sbpMode) {
234 calcLinearInterpolationBase(xiPos, noNodes1D, &nodes[0], &polynomials[0]);
235 } else {
236 calcLagrangeInterpolatingPolynomials(xiPos, m_polyDeg, &nodes[0], &wBary[0], &polynomials[0]);
237 }
238 // Calculate weight and add to integral
239 const MFloat weight = 0.5 * lengthOnLevel * wInt[k];
240 sumXi += weight * polynomials[j];
241 }
242 } else {
243 // Combine the integrals of the finer level
244 sumXi = vector1D(level + 1, 2 * l, j) + vector1D(level + 1, 2 * l + 1, j);
245 }
246
247 // Store projection information
248 vector1D(level, l, j) = sumXi;
249 }
250 }
251 }
252
253 // TODO labels:DG,toenhance use symmetry to save on memory and computations?
254 MInt cellIndex[MAX_SPACE_DIMENSIONS];
255 // Calculate projection vectors M_TD for all cells on all levels (Cartesian
256 // product of 1D-vectors)
257 for(MInt level = 0; level < m_noLevels; level++) {
258 const MInt noCells1D = IPOW2(level);
259 const MInt noCellsOnLevel = ipow(noCells1D, nDim);
260
261 // Loop over all target nodes
262 for(MInt nodeId = 0; nodeId < m_noNodesXD; nodeId++) {
263 // Compute node index in all dimensons from nodeId
264 indices<nDim>(nodeId, noNodes1D, &index[0]);
265
266 // Loop over all cells on this level
267 for(MInt i = 0; i < noCellsOnLevel; i++) {
268 // Compute cell index in all dimensions
269 indices<nDim>(i, noCells1D, cellIndex);
270
271 // Assemble projection vector M_TD
272 m_MTD[level](i, nodeId) = 1.0;
273 for(MInt d = 0; d < nDim; d++) {
274 m_MTD[level](i, nodeId) *= vector1D(level, cellIndex[d], index[d]);
275 }
276 // Premultiply with inverted mass matrix
277 m_MTD[level](i, nodeId) *= MT_inverse[nodeId];
278 }
279 }
280 }
281
282 // Evaluate polynomials for error calculation
283 for(MInt level = 0; level < m_noLevels; level++) {
284 const MInt noCellsOnLevel = IPOW2(level);
285 const MFloat lengthOnLevel = m_cellLengths[level];
286
287 // Loop over all possible donor cells on this level
288 for(MInt l = 0; l < noCellsOnLevel; l++) {
289 // Loop over quadrature points
290 for(MInt k = 0; k < noNodes1D; k++) {
291 // Node position
292 const MFloat xiPos = m_cellCenters(level, l) + 0.5 * lengthOnLevel * nodes[k];
293
294 // Evaluate Lagrange polynomials
295 calcLagrangeInterpolatingPolynomials(xiPos, m_polyDeg, &nodes[0], &wBary[0], &m_polynomials[level](l, k, 0));
296 }
297 }
298 }
299}
Class stores precalculated values for interpolation & integration on the reference interval [-1,...
MInt string2enum(MString theString)
This global function translates strings in their corresponding enum values (integer values)....
Definition: enums.cpp:20
DgPolynomialType
Definition: enums.h:310
DgIntegrationMethod
Definition: enums.h:313
MInt ipow(MInt base, MInt exp)
Integer exponent function for non-negative exponents.
Definition: functions.h:317
std::basic_string< char > MString
Definition: maiatypes.h:55
bool MBool
Definition: maiatypes.h:58
void calcLinearInterpolationBase(const MFloat x, const MInt noNodes, const MFloat *nodes, MFloat *const polynomials)
Calculates linear interpolation base for point (1D).
void calcLagrangeInterpolatingPolynomials(const MFloat x, const MInt polyDeg, const MFloat *nodes, const MFloat *wBary, MFloat *polynomials)
Calculates the values of the Lagrangian polynomials l_j for a given point x in [-1,...
IdType index(const FloatType *const x, const IdType level)
Return Hilbert index for given location and level in 2D or 3D.
Definition: hilbert.h:165

◆ calcL2Error()

template<MInt nDim>
void DgGalerkinProjection< nDim >::calcL2Error ( const MInt  noDonorCells,
const MInt donorCellIds,
const MInt donorCellLevels,
const MInt donorCellPos,
const MFloat donorField,
const MInt  noVars,
const MFloat  targetLength,
const MFloat targetField,
MFloat errors 
) const
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-06-01
Parameters
[in]noDonorCellsNumber of donor cells.
[in]donorCellLevelsRelative levels of donor cells.
[in]donorCellPosPositions of donor cells.
[in]donorFieldDonor field values.
[in]noVarsNumber of variables.
[in]targetLengthLength of the target element.
[in]targetFieldComputed target field.
[out]errorsComputed projection errors.

The L2 projection error is defined as: E_L2 = || q_D - q_T ||_2^2 = \int_{Q_T} (q_D - q_T)^2 dV with q_D and q_T the donor and target field. The target field is expanded in terms of its basis and the integration over the target element is written as the integration over all donor cells, since the donor field is piecewise constant.

Definition at line 280 of file dgcartesiangalerkinprojection.h.

283 {
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}

◆ calcProjectionInformation()

template<MInt nDim>
void DgGalerkinProjection< nDim >::calcProjectionInformation ( const MInt  noDonorCells,
const MInt donorCellLevels,
const MFloat donorCellCoordinates,
const MInt  targetLevel,
const MFloat targetCellCenter,
std::vector< MInt > &  donorIds,
std::vector< MInt > &  donorLevels 
) const
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-07-16
Parameters
[in]noDonorCellsThe number of donor cells.
[in]donorCellLevelsThe levels of the donor cells.
[in]donorCellCoordinatesCoordinates of the donor cells.
[in]targetLevelLevel of the target cell.
[in]targetCellCenterCoordinates of the target cell.
[out]donorIdsList of computed donor cell indices.
[out]donorLevelsList of donor cell levels relative to the target cell.

The projection information for one target cell consists of a list of donor cell indices and a list of donor cell levels. The donor cell level stores the relative level between the donor cell and the target cell. With the donor cell index the position of the donor cell on its level relative to the cell is described, i.e. it is a scalar index instead of nDim-indices for all dimensions. Additionally, the non-mapped volumes are identified and added to the donorIds and donorLevels lists. This means that cells that are missing in the FV-solver since they are inside some geometric object are identified such that for these volumes default values for mapping data to a DG element can be used (without implicitly assuming them all to be zero when these volumes are not handled).

Definition at line 328 of file dgcartesiangalerkinprojection.cpp.

331 {
332 TRACE();
333
334 // Calculates the position on the unit element corresponding to the cell with
335 // given center and width.
336 auto positionOnUnitElement = [](MFloat pos, MFloat center, MFloat width) { return 2 * (pos - center) / width; };
337
338 // Define epsilon according to CartesianGrid constructor
339 const MFloat eps = 1.0 / FPOW2(30) * m_lengthLevel0;
340
341 const MFloatTensor donorCellCoords(const_cast<MFloat*>(donorCellCoordinates), noDonorCells, nDim);
342 const MFloat cellLength = m_lengthLevel0 * FFPOW2(targetLevel);
343 MInt intervals[MAX_SPACE_DIMENSIONS];
344
345 IF_CONSTEXPR(nDim == 2) {
346 intervals[2] = 0; // Not set in 2D, prevent uninitialized value valgrind errors
347 }
348
349 // Determine maximum level difference between donor cells and target cell
350 const MInt maxDonorLevel =
351 *(std::max_element(&donorCellLevels[0], &donorCellLevels[0] + noDonorCells)) - targetLevel + 1;
352
353 // Initialize storage for mapped volume, i.e. consider each possible cell on all levels
354 std::vector<std::vector<MInt>> mappedVolume(maxDonorLevel);
355 for(MInt i = 0; i < maxDonorLevel; i++) {
356 const MInt noCellsOnLvl = ipow(IPOW2(i), nDim);
357 mappedVolume[i].resize(noCellsOnLvl);
358 std::fill(mappedVolume[i].begin(), mappedVolume[i].end(), 0);
359 }
360
361 // Loop over all donor cells
362 for(MInt l = 0; l < noDonorCells; l++) {
363 // Relative level of donor cell
364 const MInt donorLevel = donorCellLevels[l] - targetLevel;
365
366 const MInt noCells1D = IPOW2(donorLevel);
367 const MInt noCells1D3 = (nDim == 3) ? noCells1D : 1;
368
369 // Determine position of donor cell relative to target cell
370 for(MInt d = 0; d < nDim; d++) {
371 const MFloat posOnUnitElem = positionOnUnitElement(donorCellCoords(l, d), targetCellCenter[d], cellLength);
372
373 intervals[d] = -1;
374 // Find interval for current coordinate direction
375 for(MInt i = 0; i < noCells1D; i++) {
376 const MFloat lowerBound = m_cellCenters(donorLevel, i) - 0.5 * m_cellLengths[donorLevel];
377 const MFloat upperBound = m_cellCenters(donorLevel, i) + 0.5 * m_cellLengths[donorLevel];
378
379 // Check if the donor cell center is contained in the current cell
380 // interval and if it is 'roughly' the same as the current cell center
381 if(lowerBound < posOnUnitElem && posOnUnitElem < upperBound
382 && approx(posOnUnitElem, m_cellCenters(donorLevel, i), eps)) {
383 intervals[d] = i;
384 break;
385 }
386 }
387
388 if(intervals[d] == -1) {
389 stringstream errorMsg;
390 errorMsg << "Donor cell interval not found! (level = " << donorLevel << "; position = " << std::scientific
391 << posOnUnitElem << ")";
392 TERMM(1, errorMsg.str());
393 }
394 }
395
396 // Compute scalar donor cell index
397 const MInt donorIndex =
398 intervals[0] * noCells1D * noCells1D3 + intervals[1] * noCells1D3 + intervals[2] * (nDim == 3);
399
400 // Store donor cell information
401 donorIds[l] = donorIndex;
402 donorLevels[l] = donorLevel;
403
404 // Keep track of mapped volume, to identify non-mapped/missing cells
405 mappedVolume[donorLevel][donorIndex] = 1;
406
407 // Loop down to highest level and mark all descendent cells as mapped
408 for(MInt lvl = donorLevel + 1; lvl < maxDonorLevel; lvl++) {
409 const MInt noCellsRel1D = IPOW2(lvl - donorLevel);
410 const MInt noCellsRel1D3 = (nDim == 3) ? noCellsRel1D : 1;
411 const MInt sizeFactor = IPOW2(lvl - donorLevel);
412
413 const MInt noCells1D_ = IPOW2(lvl);
414 const MInt noCells1D3_ = (nDim == 3) ? noCells1D_ : 1;
415
416 // Loop over all child positions
417 for(MInt i = 0; i < noCellsRel1D; i++) {
418 for(MInt j = 0; j < noCellsRel1D; j++) {
419 for(MInt k = 0; k < noCellsRel1D3; k++) {
420 // Determine child 1D index on its level and mark as mapped
421 const MInt volumeIndex = (intervals[0] * sizeFactor + i) * noCells1D_ * noCells1D3_
422 + (intervals[1] * sizeFactor + j) * noCells1D3_
423 + (intervals[2] * sizeFactor + k) * (nDim == 3);
424 mappedVolume[lvl][volumeIndex] = 1;
425 }
426 }
427 }
428 }
429
430 // Loop up to relative level zero and mark coarser cells as mapped
431 for(MInt lvl = donorLevel - 1; lvl >= 0; lvl--) {
432 const MInt noCells1D_ = IPOW2(lvl);
433 const MInt noCells1D3_ = (nDim == 3) ? noCells1D_ : 1;
434 const MInt sizeFactor = IPOW2(donorLevel - lvl);
435
436 // Determine 1D index of parent on coarser level and mark as (partially) mapped
437 const MInt volumeIndex = std::floor(intervals[0] / sizeFactor) * noCells1D_ * noCells1D3_
438 + std::floor(intervals[1] / sizeFactor) * noCells1D3_
439 + std::floor(intervals[2] / sizeFactor) * (nDim == 3);
440 mappedVolume[lvl][volumeIndex] = 1;
441 }
442 }
443
444 // Append non-mapped cells/volumes to projection information
445 // Loop over all donor cell levels from coarse to fine
446 for(MInt lvl = 0; lvl < maxDonorLevel; lvl++) {
447 const MInt noCellsLvl1D = IPOW2(lvl);
448 const MInt noCellsLvl1D3 = (nDim == 3) ? noCellsLvl1D : 1;
449
450 // Loop over all cells on this level
451 for(MInt i = 0; i < noCellsLvl1D; i++) {
452 for(MInt j = 0; j < noCellsLvl1D; j++) {
453 for(MInt k = 0; k < noCellsLvl1D3; k++) {
454 // Index of current cell on this level
455 const MInt donorIndex = i * noCellsLvl1D * noCellsLvl1D3 + j * noCellsLvl1D3 + k * (nDim == 3);
456
457 // If the current cell on this level is not marked as mapped ...
458 if(!mappedVolume[lvl][donorIndex]) {
459 // ... append its position and level to the projection information
460 donorIds.push_back(donorIndex);
461 donorLevels.push_back(lvl);
462
463 std::cerr << globalDomainId() << " non-mapped " << targetCellCenter[0] << " " << lvl << " " << donorIndex
464 << std::endl;
465 TERMM(1, "TODO check if this is working correctly");
466
467 // Loop down to highest level and mark all children of this cell as mapped since the
468 // full volume of the coarse cell is already mapped
469 for(MInt childLvl = lvl + 1; childLvl < maxDonorLevel; childLvl++) {
470 const MInt noCellsRel1D = IPOW2(childLvl - lvl);
471 const MInt noCellsRel1D3 = (nDim == 3) ? noCellsRel1D : 1;
472
473 // Loop over all cells on this child level and mark as mapped
474 for(MInt i2 = 0; i2 < noCellsRel1D; i2++) {
475 for(MInt j2 = 0; j2 < noCellsRel1D; j2++) {
476 for(MInt k2 = 0; k2 < noCellsRel1D3; k2++) {
477 const MInt volumeIndex =
478 (i2 + i) * noCellsRel1D * noCellsRel1D3 + (j2 + j) * noCellsRel1D3 + (k2 + k) * (nDim == 3);
479 mappedVolume[childLvl][volumeIndex] = 1;
480 }
481 }
482 }
483 }
484 }
485 }
486 }
487 }
488 }
489
490 // Compute total volume of mapped cells and check (should be 1.0)
491 MFloat sumVolumes = 0.0;
492 for(MUint i = 0; i < donorLevels.size(); i++) {
493 const MFloat volume = 1.0 / (ipow(IPOW2(donorLevels[i]), nDim));
494 sumVolumes += volume;
495 }
496 if(!approx(sumVolumes, 1.0, eps)) {
497 stringstream errMsg;
498 errMsg << "calcProjectionInformation: mapped volume " << std::to_string(sumVolumes) << "(target cell coordinates:";
499 for(MInt d = 0; d < nDim; d++) {
500 errMsg << " " << targetCellCenter[d];
501 }
502 errMsg << ")";
503 TERMM(1, errMsg.str());
504 }
505}
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
MInt globalDomainId()
Return global domain id.
constexpr MFloat FPOW2(MInt x)
constexpr MFloat FFPOW2(MInt x)
uint32_t MUint
Definition: maiatypes.h:63
const MInt width
Definition: logtable.h:21

◆ init()

template<MInt nDim>
void DgGalerkinProjection< nDim >::init ( MInt  polyDeg,
const MInt  noLevels,
const MFloat  lengthLevel0,
const MInt  solverId 
)
private
Author
Ansgar Niemoeller (ansgar) a.nie.nosp@m.moel.nosp@m.ler@a.nosp@m.ia.r.nosp@m.wth-a.nosp@m.ache.nosp@m.n.de
Date
2016-06-01
Parameters
[in]polyDegPolynomial degree. \parma[in] noLevels Maximum difference in refinement levels between donor and target mesh + 1.
[in]lenghtLevel0Cell length on level zero.
[in]solverIdSolver id.

Definition at line 72 of file dgcartesiangalerkinprojection.cpp.

75 {
76 TRACE();
77
78 // Set member variables
79 m_polyDeg = polyDeg;
80 m_noLevels = noLevels;
81 m_lengthLevel0 = lengthLevel0;
82 m_noNodesXD = ipow(polyDeg + 1, nDim);
83 m_solverId = solverId;
84
85 const MInt noNodes1D = polyDeg + 1;
86 const MInt maxNoCellsOnLevel = IPOW2(noLevels - 1);
87
88 // Allocate space for member variables
89 m_MTD.resize(m_noLevels);
91 for(MInt level = 0; level < m_noLevels; level++) {
92 const MInt noCells1D = IPOW2(level);
93 const MInt noCellsOnLevel = ipow(noCells1D, nDim);
94
95 m_MTD[level].resize(noCellsOnLevel, m_noNodesXD);
96 m_polynomials[level].resize(noCells1D, noNodes1D, noNodes1D);
97 }
98
99 m_cellCenters.resize(noLevels, maxNoCellsOnLevel);
100 m_cellLengths.resize(noLevels);
101
102 // Calculate cell center positions and cell lengths for all levels
103 for(MInt l = 0; l < noLevels; l++) {
104 // Store cell length for this level
105 const MInt noCellsOnLevel = IPOW2(l);
106 const MFloat cellLength = 2.0 / noCellsOnLevel;
107 m_cellLengths[l] = cellLength;
108
109 // Store cell center positions
110 for(MInt c = 0; c < noCellsOnLevel; c++) {
111 m_cellCenters(l, c) = -1.0 + 0.5 * cellLength + c * cellLength;
112 }
113 }
114
115 // Calculate the needed interpolation matrices
117}
void calcInterpolationMatrices()
Calculate and store the needed interpolation matrices.
size_type resize(size_type n0, size_type n1=1, size_type n2=1, size_type n3=1, size_type n4=1)
Deletes the old data structure and creates a new one with the requested dimensions.
Definition: tensor.h:230

Member Data Documentation

◆ m_cellCenters

template<MInt nDim>
MFloatTensor DgGalerkinProjection< nDim >::m_cellCenters {}
private

Definition at line 92 of file dgcartesiangalerkinprojection.h.

◆ m_cellLengths

template<MInt nDim>
MFloatTensor DgGalerkinProjection< nDim >::m_cellLengths {}
private

Definition at line 94 of file dgcartesiangalerkinprojection.h.

◆ m_lengthLevel0

template<MInt nDim>
MFloat DgGalerkinProjection< nDim >::m_lengthLevel0 = -1.0
private

Definition at line 73 of file dgcartesiangalerkinprojection.h.

◆ m_MTD

template<MInt nDim>
std::vector<MFloatTensor> DgGalerkinProjection< nDim >::m_MTD {}
private

Definition at line 84 of file dgcartesiangalerkinprojection.h.

◆ m_noLevels

template<MInt nDim>
MInt DgGalerkinProjection< nDim >::m_noLevels = -1
private

Definition at line 71 of file dgcartesiangalerkinprojection.h.

◆ m_noNodesXD

template<MInt nDim>
MInt DgGalerkinProjection< nDim >::m_noNodesXD = -1
private

Definition at line 68 of file dgcartesiangalerkinprojection.h.

◆ m_polyDeg

template<MInt nDim>
MInt DgGalerkinProjection< nDim >::m_polyDeg = -1
private

Definition at line 66 of file dgcartesiangalerkinprojection.h.

◆ m_polynomials

template<MInt nDim>
std::vector<MFloatTensor> DgGalerkinProjection< nDim >::m_polynomials {}
private

Definition at line 87 of file dgcartesiangalerkinprojection.h.

◆ m_solverId

template<MInt nDim>
MInt DgGalerkinProjection< nDim >::m_solverId = -1
private

Definition at line 76 of file dgcartesiangalerkinprojection.h.

◆ m_tolerance

template<MInt nDim>
const MFloat DgGalerkinProjection< nDim >::m_tolerance = 1e-12
private

Definition at line 89 of file dgcartesiangalerkinprojection.h.

◆ m_wInt

template<MInt nDim>
MFloatTensor DgGalerkinProjection< nDim >::m_wInt {}
private

Definition at line 79 of file dgcartesiangalerkinprojection.h.


The documentation for this class was generated from the following files: