1 #ifndef __ELLIPTIC_ESTIMATOR_HH__
2 #define __ELLIPTIC_ESTIMATOR_HH__
7 #include <dune/fem/quadrature/caching/twistutility.hh>
8 #include <dune/fem/quadrature/cachingquadrature.hh>
9 #include <dune/fem/quadrature/intersectionquadrature.hh>
10 #include <dune/fem/operator/common/spaceoperatorif.hh>
11 #include <dune/fem/operator/matrix/blockmatrix.hh>
12 #include <dune/fem/space/discontinuousgalerkin.hh>
15 #include "../tensors/tensor.hh"
16 #include "../common/entitystorage.hh"
17 #include "../models/modeltraits.hh"
18 #include "../common/geometry.hh"
19 #include "../common/intersectionclassification.hh"
20 #include "../common/intersectiondatahandle.hh"
21 #include "../common/functionspacenorm.hh"
22 #include "../models/expressions.hh"
23 #include "../models/modelfacade.hh"
24 #include "../algorithms/operatorselector.hh"
42 template<
class DiscreteFunctionSpace,
class Model, enum FunctionSpaceNorm Norm = H1Norm>
44 :
public EntityStorage<typename DiscreteFunctionSpace::GridPartType,
45 typename DiscreteFunctionSpace::GridPartType::ctype>
48 using BaseType = EntityStorage<
typename DiscreteFunctionSpace::GridPartType,
49 typename DiscreteFunctionSpace::GridPartType::ctype>;
52 typedef DiscreteFunctionSpace DiscreteFunctionSpaceType;
53 typedef typename DiscreteFunctionSpaceType::RangeFieldType RangeFieldType;
54 typedef typename DiscreteFunctionSpaceType::GridPartType GridPartType;
55 typedef typename GridPartType::GridType GridType;
56 typedef typename GridType::template Codim<0>::Entity ElementType;
59 using ModelType = EffectiveModel<Model>;
60 using ModelTraits = EffectiveModelTraits<Model>;
63 typedef typename ModelType::BoundaryConditionsType BoundaryConditionsType;
65 typedef typename DiscreteFunctionSpaceType::DomainFieldType DomainFieldType;
66 typedef typename DiscreteFunctionSpaceType::DomainType DomainType;
67 typedef typename DiscreteFunctionSpaceType::RangeType RangeType;
68 typedef typename DiscreteFunctionSpaceType::JacobianRangeType JacobianRangeType;
69 typedef typename DiscreteFunctionSpaceType::HessianRangeType HessianRangeType;
71 typedef typename GridPartType::IndexSetType IndexSetType;
72 typedef typename IndexSetType::IndexType IndexType;
75 typedef typename GridPartType::IntersectionIteratorType IntersectionIteratorType;
76 typedef typename IntersectionIteratorType::Intersection IntersectionType;
78 typedef typename ElementType::Geometry GeometryType;
79 static const int dimension = GridType::dimension;
81 typedef Dune::Fem::CachingQuadrature<GridPartType, 0> ElementQuadratureType;
82 typedef Dune::Fem::CachingQuadrature<GridPartType, 1> FaceQuadratureType;
87 typedef Dune::FieldMatrix<DomainFieldType,dimension,dimension> JacobianInverseType;
90 static constexpr
bool useDG = DGSelectorType::useDG;
91 static constexpr
DGFlavour dgFlavour = DGSelectorType::dgFlavour;
92 static constexpr
int sFormDG = DGSelectorType::sFormDG;
98 const DiscreteFunctionSpaceType &dfSpace_;
99 GridPartType &gridPart_;
100 const IndexSetType &indexSet_;
104 mutable std::vector<JacobianRangeType> outsideFaceFluxCache;
114 enum { bulkPart, jumpPart, bdryPart, commPart, numContributions };
115 RangeFieldType errorMin[numContributions];
116 RangeFieldType errorMax[numContributions];
135 class IntersectionStorage
136 :
public std::vector<RangeFieldType>
138 typedef std::vector<RangeFieldType> BaseType;
140 dimRange = RangeType::dimension
142 typedef Fem::StaticOffsetSubMapper<dimRange> MapperType;
143 typedef Fem::SubVector<BaseType, MapperType> RangeBlockType;
144 typedef Fem::Envelope<RangeBlockType> RangeBlockPtrType;
145 typedef Fem::SubVector<const BaseType, MapperType> ConstRangeBlockType;
147 using typename BaseType::vector;
149 IntersectionStorage(
size_t numQuadraturePoints)
150 : BaseType(numQuadraturePoints*dimRange + 1)
153 IntersectionStorage()
159 assert(dimRange == 1 ||
size() % dimRange == 1);
160 return size() / dimRange;
163 using BaseType::back;
164 RangeFieldType&
hEstimate() {
return back(); }
165 const RangeFieldType&
hEstimate()
const {
return back(); }
168 RangeBlockPtrType operator()(
size_t i)
171 return RangeBlockPtrType(RangeBlockType(*
this, MapperType(i*dimRange)));
173 ConstRangeBlockType operator()(
size_t i)
const
176 return ConstRangeBlockType(*
this, MapperType(i*dimRange));
180 typedef IntersectionStorage IntersectionStorageType;
181 typedef std::map<IndexType, IntersectionStorageType> CommunicationStorageType;
182 typedef typename Fem::DFCommunicationOperation::Add OperationType;
189 class LocalIntersectionStorage
198 typedef std::vector<RangeFieldType> WeightStorageType;
200 LocalIntersectionStorage()
202 LocalIntersectionStorage(IndexType bulkEntityIndex,
size_t nop)
203 : bulkEntityIndex_(bulkEntityIndex), weights_(nop), h_(0)
205 IndexType bulkEntityIndex()
const {
return bulkEntityIndex_; }
206 IndexType& bulkEntityIndex() {
return bulkEntityIndex_; }
207 const RangeFieldType& operator[](
size_t idx)
const {
return weights_[idx]; }
208 RangeFieldType& operator[](
size_t idx) {
return weights_[idx]; }
209 size_t size()
const {
return weights_.size(); }
210 RangeFieldType&
hEstimate() {
return h_; }
211 const RangeFieldType&
hEstimate()
const {
return h_; }
213 IndexType bulkEntityIndex_;
214 WeightStorageType weights_;
217 typedef std::map<IndexType, LocalIntersectionStorage> LocalStorageType;
219 typedef std::vector<RangeType> LocalIntersectionDGStorage;
220 typedef std::map<IndexType, LocalIntersectionDGStorage> LocalDGStorageType;
225 LocalStorageType localJumpStorage_;
231 LocalDGStorageType localDGJumpStorage_;
241 CommunicationStorageType commJumpStorage_;
246 explicit EllipticEstimator(
const ModelType& model,
const DiscreteFunctionSpaceType& dfSpace)
247 : BaseType(dfSpace.gridPart()),
249 modelNeighbour_(model),
251 gridPart_(dfSpace_.gridPart()),
252 indexSet_(gridPart_.indexSet()),
253 grid_(gridPart_.grid())
258 template<
class DiscreteFunctionType>
259 RangeFieldType
estimate(
const DiscreteFunctionType& uh)
264 RangeFieldType hMax = 0.0;
267 const auto end = dfSpace_.end();
268 for (
auto it = dfSpace_.begin(); it != end; ++it) {
270 hMax = std::max(hMax,
hEstimate(it->geometry()));
276 RangeFieldType error = 0.0;
280 error = std::accumulate(this->storage_.begin(), this->storage_.end(), error);
283 error = grid_.comm().sum(error);
285 grid_.comm().max(errorMax, numContributions);
286 grid_.comm().min(errorMin, numContributions);
288 if (Dune::Fem::Parameter::verbose()) {
290 std::cout <<
"Estimated " << (Norm == L2Norm ?
"L2" :
"H1") <<
"-Error: "
291 << std::sqrt(error) <<
" (squared: " << error <<
")" << std::endl;
292 const char *errorNames[numContributions] = {
"bulk",
"jump",
"bdry",
"comm" };
293 for (
int i = 0; i < numContributions; ++i) {
294 if (errorMax[i] == 0.0) {
297 std::cout <<
" " << errorNames[i] <<
"^2 min: " << errorMin[i] << std::endl;
298 std::cout <<
" " << errorNames[i] <<
"^2 max: " << errorMax[i] << std::endl;
300 std::cout <<
"hMax: " << hMax << std::endl;
302 return std::sqrt(error);
305 const DiscreteFunctionSpaceType& space()
const
317 localJumpStorage_.clear();
318 commJumpStorage_.clear();
320 localDGJumpStorage_.clear();
327 errorMin[commPart] = std::numeric_limits<RangeFieldType>::max();
332 errorMax[commPart] = 0.0;
336 template<
class DiscreteFunction>
339 const auto& geometry = entity.geometry();
341 const auto hFactor = Norm == L2Norm ? h2*h2 : h2;
342 const auto index = indexSet_.index(entity);
343 const auto uLocal = uh.localFunction(entity);
345 ElementQuadratureType quad(entity, 2*(dfSpace_.order() + 1));
349 RangeFieldType localEstimate = 0.0;
350 const auto numQuadraturePoints = quad.nop();
351 for (
size_t qp = 0; qp < numQuadraturePoints; ++qp) {
353 const auto& x = quad.point(qp);
354 const auto weight = quad.weight(qp) * geometry.integrationElement(x);
357 uLocal.evaluate(x, values);
359 JacobianRangeType jacobian;
360 uLocal.jacobian(x, jacobian);
362 HessianRangeType hessian;
363 uLocal.hessian(x, hessian);
366 RangeType el_res(0.);
367 if (ModelTraits::template Exists<PDEModel::flux>::value) {
368 el_res += model_.
fluxDivergence(quad[qp], values, jacobian, hessian);
370 if (ModelTraits::template Exists<PDEModel::source>::value) {
371 el_res += model_.
source(quad[qp], values, jacobian);
374 localEstimate += hFactor * weight * (el_res * el_res);
376 this->storage_[index] += localEstimate;
378 errorMin[bulkPart] = std::min(errorMin[bulkPart], localEstimate);
379 errorMax[bulkPart] = std::max(errorMax[bulkPart], localEstimate);
382 const auto end = gridPart_.iend(entity);
383 for (
auto it = gridPart_.ibegin(entity); it != end; ++it) {
385 const auto& intersection = *it;
390 }
else if (intersection.neighbor()) {
393 }
else if (intersection.boundary()) {
396 assert(!active.first || active.second.all() || active.second.none());
398 if (!active.second.all()) {
408 template<
class DiscreteFunctionType>
410 const ElementType &inside,
411 const DiscreteFunctionType& uh,
412 const typename DiscreteFunctionType::LocalFunctionType &uInside)
414 if (!ModelTraits::template Exists<PDEModel::flux>::value) {
419 const auto outside = intersection.outside();
421 const auto insideIndex = indexSet_.index(inside);
422 const auto outsideIndex = indexSet_.index(outside);
424 const bool isOutsideInterior = (outside.partitionType() == Dune::InteriorEntity);
425 if (!isOutsideInterior || (insideIndex < outsideIndex)) {
426 const auto uOutside = uh.localFunction(outside);
428 RangeFieldType error;
430 if (intersection.conforming())
431 error = estimateIntersection<true>(intersection, inside, uInside, outside, uOutside);
433 error = estimateIntersection<false>(intersection, inside, uInside, outside, uOutside);
436 this->storage_[insideIndex] += error;
437 if (isOutsideInterior) {
438 this->storage_[outsideIndex] += error;
442 errorMin[jumpPart] = std::min(errorMin[jumpPart], error);
443 errorMax[jumpPart] = std::max(errorMax[jumpPart], error);
448 template<
bool conforming,
class LocalFunctionType>
450 const ElementType &inside,
451 const LocalFunctionType &uInside,
452 const ElementType &outside,
453 const LocalFunctionType &uOutside)
456 assert(intersection.conforming() == conforming);
461 typedef Dune::Fem::IntersectionQuadrature<FaceQuadratureType, conforming> IntersectionQuadratureType;
463 const int quadOrder = 2 * (dfSpace_.order() - 1);
465 IntersectionQuadratureType intersectionQuad(gridPart_, intersection, quadOrder);
468 const auto& quadInside = intersectionQuad.inside();
469 const auto& quadOutside = intersectionQuad.outside();
471 const auto numQuadraturePoints = quadInside.nop();
473 modelNeighbour_.
bind(outside);
474 RangeFieldType error = 0;
475 RangeFieldType dgError = 0;
476 for (
size_t qp = 0; qp < numQuadraturePoints; ++qp) {
477 const auto integrationNormal
478 = intersection.integrationOuterNormal(quadInside.localPoint(qp));
479 const auto integrationElement = integrationNormal.two_norm();
482 DomainType unitNormal = integrationNormal;
483 unitNormal/=integrationElement;
489 RangeType valueInside, valueOutside;
490 JacobianRangeType jacobianInside, jacobianOutside;
491 uInside.evaluate(quadInside[qp], valueInside);
492 uInside.jacobian(quadInside[qp], jacobianInside);
493 auto fluxInside = model_.
flux(quadInside[qp], valueInside, jacobianInside);
494 uOutside.evaluate(quadOutside[qp], valueOutside);
495 uOutside.jacobian(quadOutside[qp], jacobianOutside);
496 auto fluxOutside = modelNeighbour_.
flux(quadOutside[qp], valueOutside, jacobianOutside);
499 auto jump =
contractInner(fluxInside - fluxOutside, integrationNormal);
501 error += quadInside.weight(qp) * (jump * jump) / integrationElement;
504 auto jump = valueInside - valueOutside;
505 dgError += quadInside.weight( qp ) * (jump * jump) * integrationElement;
511 const auto hFactor = Norm == L2Norm ? h * h * h : h;
515 assert(Norm == H1Norm);
528 if (commJumpStorage_.size() == 0) {
533 const bool verbose = Dune::Fem::Parameter::getValue<int>(
"fem.verboserank", 0) != -1;
537 gridPart_.communicate(dataHandle,
538 InteriorBorder_InteriorBorder_Interface,
539 ForwardCommunication);
545 auto localIt = localJumpStorage_.begin();
546 auto localDGIt = localDGJumpStorage_.begin();
547 for (
const auto& remote : commJumpStorage_) {
548 const auto& local = *localIt;
549 assert(remote.first == local.first);
551 const auto& localData = local.second;
552 const auto& commData = remote.second;
554 const auto numQuadraturePoints = localData.size();
557 RangeFieldType error = 0;
558 RangeFieldType dgError = 0;
559 for (
size_t qp = 0; qp < numQuadraturePoints; ++qp) {
560 error += localData[qp] * (commData(qp) * commData(qp));
564 RangeType jump = commData(numQuadraturePoints + qp);
565 jump.axpy(-2, localDGIt->second[qp]);
566 dgError += localData[qp] * (jump * jump);
574 const auto h = 0.5 * commData.hEstimate();
575 const auto hFactor = Norm == L2Norm ? h * h * h : h;
581 assert(Norm == H1Norm);
586 this->storage_[localData.bulkEntityIndex()] += error;
588 errorMin[commPart] = std::min(errorMin[commPart], error);
589 errorMax[commPart] = std::max(errorMax[commPart], error);
597 assert(localIt == localJumpStorage_.end());
598 assert(localDGIt == localDGJumpStorage_.end());
601 auto nFaces = commJumpStorage_.size();
602 nFaces = grid_.comm().sum(nFaces);
604 if (Dune::Fem::Parameter::verbose()) {
605 dwarn <<
"*** Processor Boundaries: "
606 << (RangeFieldType)nFaces/2.0
607 <<
" Faces ***" << std::endl;
624 template<
class LocalFunctionType>
626 const ElementType &inside,
627 const LocalFunctionType &uInside)
629 if (!ModelTraits::template Exists<PDEModel::flux>::value) {
633 if (intersection.conforming()) {
634 estimateProcessorBoundary<true>(intersection, inside, uInside);
636 estimateProcessorBoundary<false>(intersection, inside, uInside);
644 template<
bool conforming,
class LocalFunctionType>
646 const ElementType &inside,
647 const LocalFunctionType &uInside)
650 assert(intersection.conforming() == conforming);
653 typedef Dune::Fem::IntersectionQuadrature<FaceQuadratureType, conforming> IntersectionQuadratureType;
655 const auto quadOrder = 2 * (dfSpace_.order() - 1);
657 IntersectionQuadratureType intersectionQuad(gridPart_, intersection, quadOrder);
660 const auto& quadInside = intersectionQuad.inside();
661 const auto numQuadraturePoints = quadInside.nop();
664 const auto faceIndex = indexSet_.index(inside.template subEntity<1>(intersection.indexInInside()));
665 const auto bulkIndex = indexSet_.index(inside);
671 auto commSize = useDG ? 2*numQuadraturePoints : numQuadraturePoints;
672 IntersectionStorageType commData(commSize);
673 LocalIntersectionStorage localData(bulkIndex, numQuadraturePoints);
674 LocalIntersectionDGStorage localDGData(useDG ? numQuadraturePoints : 0);
676 for (
size_t qp = 0; qp < numQuadraturePoints; ++qp) {
677 auto normal = intersection.integrationOuterNormal(quadInside.localPoint(qp));
678 const RangeFieldType integrationElement = normal.two_norm();
679 normal /= integrationElement;
685 RangeType valueInside;
686 JacobianRangeType jacobianInside;
687 uInside.evaluate(quadInside[qp], valueInside);
688 uInside.jacobian(quadInside[qp], jacobianInside);
689 const auto fluxInside = model_.
flux(quadInside[qp], valueInside, jacobianInside);
696 localDGData[qp] = valueInside;
697 for (
unsigned i = 0; i < valueInside.size(); ++i) {
698 (*commData(numQuadraturePoints + qp))[i] = valueInside[i];
703 localData[qp] = quadInside.weight(qp) * integrationElement;
705 localData.hEstimate() =
hEstimate(inside.geometry());
707 commData.hEstimate() = localData.hEstimate();
709 commJumpStorage_[faceIndex] = commData;
710 localJumpStorage_[faceIndex] = localData;
712 localDGJumpStorage_[faceIndex] = localDGData;
723 template<
class LocalFunctionType>
725 const ElementType &inside,
726 const LocalFunctionType &uLocal,
727 const BoundaryConditionsType& active)
729 if (!ModelTraits::template Exists<PDEModel::flux>::value
731 !ModelTraits::template Exists<PDEModel::robinFlux>::value) {
735 assert(intersection.conforming() ==
true);
737 typedef Dune::Fem::IntersectionQuadrature<FaceQuadratureType,
true > IntersectionQuadratureType;
741 const auto quadOrder = 2*dfSpace_.order();
743 IntersectionQuadratureType intersectionQuad(gridPart_, intersection, quadOrder);
745 const auto& bndryQuad = intersectionQuad.inside();
746 const auto numQuadraturePoints = bndryQuad.nop();
748 const auto insideIndex = indexSet_.index(inside);
750 const auto h =
hEstimate(inside.geometry());
752 RangeFieldType error = 0.0;
754 for (
size_t qp = 0; qp < numQuadraturePoints; ++qp) {
755 const auto weight = bndryQuad.weight(qp);
758 auto normal = intersection.integrationOuterNormal(bndryQuad.localPoint(qp));
759 const auto integrationElement = normal.two_norm();
760 normal /= integrationElement;
763 uLocal.evaluate(bndryQuad[qp], value);
765 JacobianRangeType jacobian;
766 if (ModelTraits::template Exists<PDEModel::flux>::value
768 ModelTraits::template Exists<PDEModel::robinFlux>::value) {
769 uLocal.jacobian(bndryQuad[qp], jacobian);
772 RangeType residual(0);
774 if (ModelTraits::template Exists<PDEModel::flux>::value) {
775 const auto flux = model_.
flux(bndryQuad[qp], value, jacobian);
780 if (ModelTraits::template Exists<PDEModel::robinFlux>::value) {
782 residual += model_.
robinFlux(bndryQuad[qp], normal, value, jacobian);
786 error += weight * integrationElement * (residual * residual);
790 const auto hFactor = Norm == L2Norm ? h * h * h : h;
794 this->storage_[insideIndex] += error;
797 errorMin[bdryPart] = std::min(errorMin[bdryPart], error);
798 errorMax[bdryPart] = std::max(errorMax[bdryPart], error);
An standard residual estimator for elliptic problems.
Definition: ellipticestimator.hh:46
void estimateIntersection(const IntersectionType &intersection, const ElementType &inside, const DiscreteFunctionType &uh, const typename DiscreteFunctionType::LocalFunctionType &uInside)
caclulate error on element boundary intersections
Definition: ellipticestimator.hh:409
void estimateBoundary(const IntersectionType &intersection, const ElementType &inside, const LocalFunctionType &uLocal, const BoundaryConditionsType &active)
calculate error over a boundary segment; yields zero for Dirichlet boundary values,...
Definition: ellipticestimator.hh:724
RangeFieldType estimateIntersection(const IntersectionType &intersection, const ElementType &inside, const LocalFunctionType &uInside, const ElementType &outside, const LocalFunctionType &uOutside)
Caclulate error on element intersections.
Definition: ellipticestimator.hh:449
RangeFieldType estimate(const DiscreteFunctionType &uh)
calculate estimator
Definition: ellipticestimator.hh:259
void estimateProcessorBoundary(const IntersectionType &intersection, const ElementType &inside, const LocalFunctionType &uInside)
Compute the jump contribution to the estimator on process-boundaries.
Definition: ellipticestimator.hh:625
void estimateLocal(const ElementType &entity, const DiscreteFunction &uh)
caclulate error on element
Definition: ellipticestimator.hh:337
void communicateJumpContributions()
Helper function in order to add the jump contributions on inter-process boundaries.
Definition: ellipticestimator.hh:526
void estimateProcessorBoundary(const IntersectionType &intersection, const ElementType &inside, const LocalFunctionType &uInside)
Helper function for estimateProcessorBoundary() in order to distinguish between conforming and non-co...
Definition: ellipticestimator.hh:645
General intersection - intersection communication which communicates for each intersection a potentia...
Definition: intersectiondatahandle.hh:50
A class defining the "closure" type of all supported model-method and method-call-signatures.
Definition: modelfacade.hh:72
void unbind()
Unbind from the previously bound entity.
Definition: modelfacade.hh:164
auto flux(const QuadraturePoint< Quadrature > &x, const DomainRangeType &value, const DomainJacobianRangeType &jacobian) const
Evaluate in local coordinates.
Definition: modelfacade.hh:236
auto source(const QuadraturePoint< Quadrature > &x, const DomainRangeType &value, const DomainJacobianRangeType &jacobian) const
The zero-order term as function of local coordinates.
Definition: modelfacade.hh:287
auto robinFlux(const QuadraturePoint< Quadrature > &x, const DomainType &unitOuterNormal, const DomainRangeType &value, const DomainJacobianRangeType &jacobian) const
The non-linearized Robin-type flux term.
Definition: modelfacade.hh:344
void bind(const Entity &entity)
Bind to the given entity.
Definition: modelfacade.hh:154
BoundaryConditionsType classifyBoundary(const Intersection &intersection)
Bind to the given intersection and classify the components w.r.t.
Definition: modelfacade.hh:206
auto fluxDivergence(const QuadraturePoint< Quadrature > &x, const DomainRangeType &value, const DomainJacobianRangeType &jacobian, const DomainHessianRangeType &hessian) const
Compute the point-wise value of the flux-part of the operator, meaning the part of the differential o...
Definition: modelfacade.hh:455
DGFlavour
Definition: operatorselector.hh:24
Geometry::ctype h2Estimate(const Geometry &geometry)
Compute a rough estimate of the square of the diameter of the element's Geometry.
Definition: geometry.hh:20
Geometry::ctype hEstimate(const Geometry &geometry)
Compute a rough estimate of the diameter of the element's Geometry.
Definition: geometry.hh:41
bool isProcessorBoundary(const Intersection &intersection)
Retrun true if at the border to another computing note.
Definition: intersectionclassification.hh:35
constexpr std::size_t size()
Gives the number of elements in tuple-likes and std::integer_sequence.
Definition: size.hh:73
constexpr auto contractInner(T1 &&t1, T2 &&t2, IndexConstant< N >=IndexConstant< N >{})
Contraction over the #N inner dimensions.
Definition: expressions.hh:118
Definition: operatorselector.hh:31