24#ifndef DUMUX_TEST_L2_ERROR_HH
25#define DUMUX_TEST_L2_ERROR_HH
36template<
class Scalar,
class ModelTraits,
class PrimaryVariables>
49 template<
class Problem,
class SolutionVector>
52 using GridGeometry = std::decay_t<
decltype(problem.gridGeometry())>;
53 PrimaryVariables sumError(0.0), sumReference(0.0), l2NormAbs(0.0), l2NormRel(0.0);
55 const int numFaceDofs = problem.gridGeometry().numFaceDofs();
57 std::vector<Scalar> staggeredVolume(numFaceDofs);
58 std::vector<Scalar> errorVelocity(numFaceDofs);
59 std::vector<Scalar> velocityReference(numFaceDofs);
62 Scalar totalVolume = 0.0;
64 for (
const auto& element : elements(problem.gridGeometry().gridView()))
66 auto fvGeometry =
localView(problem.gridGeometry());
67 fvGeometry.bindElement(element);
69 for (
auto&& scv : scvs(fvGeometry))
72 const auto dofIdxCellCenter = scv.dofIndex();
73 const auto& posCellCenter = scv.dofPosition();
74 const auto analyticalSolutionCellCenter = problem.dirichletAtPos(posCellCenter)[Indices::pressureIdx];
75 const auto numericalSolutionCellCenter = curSol[GridGeometry::cellCenterIdx()][dofIdxCellCenter][Indices::pressureIdx - ModelTraits::dim()];
76 sumError[Indices::pressureIdx] += squaredDiff_(analyticalSolutionCellCenter, numericalSolutionCellCenter) * scv.volume();
77 sumReference[Indices::pressureIdx] += analyticalSolutionCellCenter * analyticalSolutionCellCenter * scv.volume();
78 totalVolume += scv.volume();
81 for (
auto&& scvf : scvfs(fvGeometry))
83 const int dofIdxFace = scvf.dofIndex();
84 const int dirIdx = scvf.directionIndex();
85 const auto analyticalSolutionFace = problem.dirichletAtPos(scvf.center())[Indices::velocity(dirIdx)];
86 const auto numericalSolutionFace = curSol[GridGeometry::faceIdx()][dofIdxFace][0];
88 errorVelocity[dofIdxFace] = squaredDiff_(analyticalSolutionFace, numericalSolutionFace);
89 velocityReference[dofIdxFace] = squaredDiff_(analyticalSolutionFace, 0.0);
90 const Scalar staggeredHalfVolume = 0.5 * scv.volume();
91 staggeredVolume[dofIdxFace] = staggeredVolume[dofIdxFace] + staggeredHalfVolume;
97 l2NormAbs[Indices::pressureIdx] = std::sqrt(sumError[Indices::pressureIdx] / totalVolume);
98 l2NormRel[Indices::pressureIdx] = std::sqrt(sumError[Indices::pressureIdx] / sumReference[Indices::pressureIdx]);
101 for(
int i = 0; i < numFaceDofs; ++i)
104 const auto error = errorVelocity[i];
105 const auto ref = velocityReference[i];
106 const auto volume = staggeredVolume[i];
107 sumError[Indices::velocity(dirIdx)] += error * volume;
108 sumReference[Indices::velocity(dirIdx)] += ref * volume;
111 for(
int dirIdx = 0; dirIdx < ModelTraits::dim(); ++dirIdx)
113 l2NormAbs[Indices::velocity(dirIdx)] = std::sqrt(sumError[Indices::velocity(dirIdx)] / totalVolume);
114 l2NormRel[Indices::velocity(dirIdx)] = std::sqrt(sumError[Indices::velocity(dirIdx)] / sumReference[Indices::velocity(dirIdx)]);
116 return std::make_pair(l2NormAbs, l2NormRel);
122 static T squaredDiff_(
const T& a,
const T& b)
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:38
static unsigned int directionIndex(Vector &&vector)
Returns the dirction index of the facet (0 = x, 1 = y, 2 = z)
Definition: staggeredgeometryhelper.hh:114
make the local view function available whenever we use the grid geometry
Definition: adapt.hh:29
Property tag Indices
Definition: porousmediumflow/sequential/properties.hh:59
Routines to calculate the discrete L2 error.
Definition: l2error.hh:38
static auto calculateL2Error(const Problem &problem, const SolutionVector &curSol)
Calculates the L2 error between the analytical solution and the numerical approximation.
Definition: l2error.hh:50