diff --git a/src/compute-disc-error.cc b/src/compute-disc-error.cc index 14b9551f3514ea19cff4a9ca4b97eb3c71b04dd4..3e18efc203859942eaf76609af0ddd8518a8ee41 100644 --- a/src/compute-disc-error.cc +++ b/src/compute-disc-error.cc @@ -152,6 +152,70 @@ void measureDiscreteEOC(const GridView gridView, << "H^1 error orientation: " << std::sqrt(orientationH1ErrorSquared) << std::endl; } + + if constexpr (std::is_same<TargetSpace,Rotation<double,3> >::value) + { + double l2ErrorSquared = 0; + double h1ErrorSquared = 0; + + for (const auto& rElement : elements(referenceGridView)) + { + const auto& quadRule = QuadratureRules<double, dim>::rule(rElement.type(), 6); + + for (const auto& qp : quadRule) + { + auto integrationElement = rElement.geometry().integrationElement(qp.position()); + + auto globalPos = rElement.geometry().global(qp.position()); + + auto element = hierarchicSearch.findEntity(globalPos); + auto localPos = element.geometry().local(globalPos); + + FieldMatrix<double,3,3> referenceValue, numericalValue; + auto refValue = referenceSolution(rElement, qp.position()); + Rotation<double,3> referenceRotation(refValue); + referenceRotation.matrix(referenceValue); + + auto numValue = numericalSolution(element, localPos); + Rotation<double,3> numericalRotation(numValue); + numericalRotation.matrix(numericalValue); + + auto diff = referenceValue - numericalValue; + + l2ErrorSquared += integrationElement * qp.weight() * diff.frobenius_norm2(); + + auto referenceDerQuat = referenceSolution.derivative(rElement, qp.position()); + auto numericalDerQuat = numericalSolution.derivative(element, localPos); + + // Transform to matrix coordinates + Tensor3<double,3,3,4> derivativeQuaternionToMatrixRef = Rotation<double,3>::derivativeOfQuaternionToMatrix(refValue); + Tensor3<double,3,3,4> derivativeQuaternionToMatrixNum = Rotation<double,3>::derivativeOfQuaternionToMatrix(numValue); + + Tensor3<double,3,3,dim> refDerivative(0); + Tensor3<double,3,3,dim> numDerivative(0); + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<dim; k++) + for (int l=0; l<4; l++) + { + refDerivative[i][j][k] = derivativeQuaternionToMatrixRef[i][j][l] * referenceDerQuat[l][k]; + numDerivative[i][j][k] = derivativeQuaternionToMatrixNum[i][j][l] * numericalDerQuat[l][k]; + } + + auto derDiff = refDerivative - numDerivative; // compute the difference + h1ErrorSquared += derDiff.frobenius_norm2() * qp.weight() * integrationElement; + + } + } + + std::cout << "levels: " << gridView.grid().maxLevel()+1 + << " " + << "L^2 error: " << std::sqrt(l2ErrorSquared) + << " " + << "h^1 error: " << std::sqrt(h1ErrorSquared) + << std::endl; + } else { double l2ErrorSquared = 0; @@ -250,22 +314,116 @@ void measureAnalyticalEOC(const GridView gridView, // QuadratureRule for the integral of the L^2 error QuadratureRuleKey quadKey(dim,6); - // Compute the embedded L^2 error - double l2Error = DiscretizationError<GridView>::computeL2Error(numericalSolution.get(), - referenceSolution.get(), - quadKey); + // Compute errors in the L2 norm and the h1 seminorm. + // SO(3)-valued maps need special treatment, because they are stored as quaternions, + // but the errors need to be computed in matrix space. + if constexpr (std::is_same<TargetSpace,Rotation<double,3> >::value) + { + constexpr int blocksize = TargetSpace::CoordinateType::dimension; - // Compute the embedded H^1 error - double h1Error = DiscretizationError<GridView>::computeH1HalfNormDifferenceSquared(gridView, - numericalSolution.get(), - referenceSolution.get(), - quadKey); + // The error to be computed + double l2ErrorSquared = 0; + double h1ErrorSquared = 0; - std::cout << "elements: " << gridView.size(0) - << " " - << "L^2 error: " << l2Error - << " "; - std::cout << "h^1 error: " << std::sqrt(h1Error) << std::endl; + for (auto&& element : elements(gridView)) + { + // Get quadrature formula + quadKey.setGeometryType(element.type()); + const auto& quad = QuadratureRuleCache<double, dim>::rule(quadKey); + + for (auto quadPoint : quad) + { + auto quadPos = quadPoint.position(); + const auto integrationElement = element.geometry().integrationElement(quadPos); + const auto weight = quadPoint.weight(); + + // Evaluate function a + FieldVector<double,blocksize> numValue; + numericalSolution.get()->evaluateLocal(element, quadPos,numValue); + + // Evaluate function b. If it is a grid function use that to speed up the evaluation + FieldVector<double,blocksize> refValue; + if (std::dynamic_pointer_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >>(referenceSolution)) + std::dynamic_pointer_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >>(referenceSolution)->evaluateLocal(element, + quadPos, + refValue + ); + else + referenceSolution->evaluate(element.geometry().global(quadPos), refValue); + + // Get error in matrix space + Rotation<double,3> numRotation(numValue); + FieldMatrix<double,3,3> numValueMatrix; + numRotation.matrix(numValueMatrix); + + Rotation<double,3> refRotation(refValue); + FieldMatrix<double,3,3> refValueMatrix; + refRotation.matrix(refValueMatrix); + + // Evaluate derivatives in quaternion space + FieldMatrix<double,blocksize,dim> num_di; + FieldMatrix<double,blocksize,dim> ref_di; + + if (dynamic_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >*>(numericalSolution.get())) + dynamic_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >*>(numericalSolution.get())->evaluateDerivativeLocal(element, + quadPos, + num_di); + else + numericalSolution->evaluateDerivative(element.geometry().global(quadPos), num_di); + + if (std::dynamic_pointer_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >>(referenceSolution)) + std::dynamic_pointer_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >>(referenceSolution)->evaluateDerivativeLocal(element, + quadPos, + ref_di); + else + referenceSolution->evaluateDerivative(element.geometry().global(quadPos), ref_di); + + // Transform into matrix space + Tensor3<double,3,3,4> derivativeQuaternionToMatrixNum = Rotation<double,3>::derivativeOfQuaternionToMatrix(numValue); + Tensor3<double,3,3,4> derivativeQuaternionToMatrixRef = Rotation<double,3>::derivativeOfQuaternionToMatrix(refValue); + + Tensor3<double,3,3,dim> numDerivative(0); + Tensor3<double,3,3,dim> refDerivative(0); + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<dim; k++) + for (int l=0; l<blocksize; l++) + { + numDerivative[i][j][k] = derivativeQuaternionToMatrixNum[i][j][l] * num_di[l][k]; + refDerivative[i][j][k] = derivativeQuaternionToMatrixRef[i][j][l] * ref_di[l][k]; + } + + // integrate error + l2ErrorSquared += (numValueMatrix - refValueMatrix).frobenius_norm2() * weight * integrationElement; + auto diff = numDerivative - refDerivative; + h1ErrorSquared += diff.frobenius_norm2() * weight * integrationElement; + } + } + + std::cout << "elements: " << gridView.size(0) + << " " + << "L^2 error: " << std::sqrt(l2ErrorSquared) + << " "; + std::cout << "h^1 error: " << std::sqrt(h1ErrorSquared) << std::endl; + } + else + { + auto l2Error = DiscretizationError<GridView>::computeL2Error(numericalSolution.get(), + referenceSolution.get(), + quadKey); + + auto h1Error = DiscretizationError<GridView>::computeH1HalfNormDifferenceSquared(gridView, + numericalSolution.get(), + referenceSolution.get(), + quadKey); + + std::cout << "elements: " << gridView.size(0) + << " " + << "L^2 error: " << l2Error + << " "; + std::cout << "h^1 error: " << std::sqrt(h1Error) << std::endl; + } } template <class GridType, class TargetSpace>