DUNE-ACFEM (unstable)

ellipticestimator.hh
1#ifndef __ELLIPTIC_ESTIMATOR_HH__
2#define __ELLIPTIC_ESTIMATOR_HH__
3
4#include <numeric>
5
6//- Dune-fem includes
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>
13
14// Local includes
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"
25
26namespace Dune {
27
28 namespace ACFem {
29
42 template<class DiscreteFunctionSpace, class Model, enum FunctionSpaceNorm Norm = H1Norm>
44 : public EntityStorage<typename DiscreteFunctionSpace::GridPartType,
45 typename DiscreteFunctionSpace::GridPartType::ctype>
46 {
48 using BaseType = EntityStorage<typename DiscreteFunctionSpace::GridPartType,
49 typename DiscreteFunctionSpace::GridPartType::ctype>;
50 public:
51 // Interface types
52 typedef DiscreteFunctionSpace DiscreteFunctionSpaceType;
53 typedef typename DiscreteFunctionSpaceType::RangeFieldType RangeFieldType; // aka double
54 typedef typename DiscreteFunctionSpaceType::GridPartType GridPartType;
55 typedef typename GridPartType::GridType GridType;
56 typedef typename GridType::template Codim<0>::Entity ElementType;
57
58 protected:
59 using ModelType = EffectiveModel<Model>;
60 using ModelTraits = EffectiveModelTraits<Model>;
62
63 typedef typename ModelType::BoundaryConditionsType BoundaryConditionsType;
64
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;
70
71 typedef typename GridPartType::IndexSetType IndexSetType;
72 typedef typename IndexSetType::IndexType IndexType;
73
74 //intersection type
75 typedef typename GridPartType::IntersectionIteratorType IntersectionIteratorType;
76 typedef typename IntersectionIteratorType::Intersection IntersectionType;
77
78 typedef typename ElementType::Geometry GeometryType;
79 static const int dimension = GridType::dimension;
80
81 typedef Dune::Fem::CachingQuadrature<GridPartType, 0> ElementQuadratureType;
82 typedef Dune::Fem::CachingQuadrature<GridPartType, 1> FaceQuadratureType;
83
84 //typedef Dune::Fem::ElementQuadrature<GridPartType, 0> ElementQuadratureType;
85 //typedef Dune::Fem::ElementQuadrature<GridPartType, 1> FaceQuadratureType;
86
87 typedef Dune::FieldMatrix<DomainFieldType,dimension,dimension> JacobianInverseType;
88
90 static constexpr bool useDG = DGSelectorType::useDG;
91 static constexpr DGFlavour dgFlavour = DGSelectorType::dgFlavour;
92 static constexpr int sFormDG = DGSelectorType::sFormDG;
93
94 protected:
95 ModelClosure model_; //< The underlying model.
96 ModelClosure modelNeighbour_;
97
98 const DiscreteFunctionSpaceType &dfSpace_;
99 GridPartType &gridPart_;
100 const IndexSetType &indexSet_;
101 GridType &grid_;
102
103 private:
104 mutable std::vector<JacobianRangeType> outsideFaceFluxCache;
105
114 enum { bulkPart, jumpPart, bdryPart, commPart, numContributions };
115 RangeFieldType errorMin[numContributions];
116 RangeFieldType errorMax[numContributions];
117
135 class IntersectionStorage
136 : public std::vector<RangeFieldType>
137 {
138 typedef std::vector<RangeFieldType> BaseType;
139 enum {
140 dimRange = RangeType::dimension
141 };
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;
146 public:
147 using typename BaseType::vector;
148 using BaseType::size;
149 IntersectionStorage(size_t numQuadraturePoints)
150 : BaseType(numQuadraturePoints*dimRange + 1)
151 {}
152
153 IntersectionStorage()
154 : BaseType()
155 {}
156
157 size_t nop() const
158 {
159 assert(dimRange == 1 || size() % dimRange == 1);
160 return size() / dimRange;
161 }
162
163 using BaseType::back;
164 RangeFieldType& hEstimate() { return back(); }
165 const RangeFieldType& hEstimate() const { return back(); }
166
167
168 RangeBlockPtrType operator()(size_t i)
169 {
170 assert(i < nop());
171 return RangeBlockPtrType(RangeBlockType(*this, MapperType(i*dimRange)));
172 }
173 ConstRangeBlockType operator()(size_t i) const
174 {
175 assert(i < nop());
176 return ConstRangeBlockType(*this, MapperType(i*dimRange));
177 }
178 };
179
180 typedef IntersectionStorage IntersectionStorageType;
181 typedef std::map<IndexType, IntersectionStorageType> CommunicationStorageType;
182 typedef typename Fem::DFCommunicationOperation::Add OperationType;
184
189 class LocalIntersectionStorage
190 {
198 typedef std::vector<RangeFieldType> WeightStorageType;
199 public:
200 LocalIntersectionStorage()
201 {}
202 LocalIntersectionStorage(IndexType bulkEntityIndex, size_t nop)
203 : bulkEntityIndex_(bulkEntityIndex), weights_(nop), h_(0)
204 {}
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_; }
212 private:
213 IndexType bulkEntityIndex_;
214 WeightStorageType weights_;
215 RangeFieldType h_;
216 };
217 typedef std::map<IndexType, LocalIntersectionStorage> LocalStorageType;
218
219 typedef std::vector<RangeType> LocalIntersectionDGStorage;
220 typedef std::map<IndexType, LocalIntersectionDGStorage> LocalDGStorageType;
221
222 // Store for every intersection the element index, h and all
223 // quad weights. This buffer is local for each computation node
224 // and is not communicated.
225 LocalStorageType localJumpStorage_;
226
227 // Store for every intersection the contribution to the DG-jump
228 // from the interior for each each quadrature point. This
229 // buffer is local for each computation node and is not
230 // commmunicated.
231 LocalDGStorageType localDGJumpStorage_;
232
233 // Store for every intersection the contribution to all jump
234 // terms (jump in the values for DG and the jumps of the flux)
235 // at all quadrature points. During communication the
236 // communicated values from the "outside" are added For the
237 // jumps of the flux this results in the jump term as the
238 // normals in the outside have the opposite direction. For the
239 // jumps in the values (DG case) the jump finally is computed by
240 // subtracting the values of localDGJumpStorage_ twice.
241 CommunicationStorageType commJumpStorage_;
242
245 public:
246 explicit EllipticEstimator(const ModelType& model, const DiscreteFunctionSpaceType& dfSpace)
247 : BaseType(dfSpace.gridPart()),
248 model_(model),
249 modelNeighbour_(model),
250 dfSpace_(dfSpace),
251 gridPart_(dfSpace_.gridPart()),
252 indexSet_(gridPart_.indexSet()),
253 grid_(gridPart_.grid())
254 {
255 }
256
258 template<class DiscreteFunctionType>
259 RangeFieldType estimate(const DiscreteFunctionType& uh)
260 {
261 // clear all local estimators
262 clear();
263
264 RangeFieldType hMax = 0.0;
265
266 // calculate local estimator
267 const auto end = dfSpace_.end();
268 for (auto it = dfSpace_.begin(); it != end; ++it) {
269 estimateLocal(*it, uh);
270 hMax = std::max(hMax, hEstimate(it->geometry()));
271 }
272
273 // do the comm-stuff at inter-process boundaries
275
276 RangeFieldType error = 0.0;
277
278 // sum up local estimators. NB: accumulate does not overwrite
279 // "error", we need the result of accumulate.
280 error = std::accumulate(this->storage_.begin(), this->storage_.end(), error);
281
282 // obtain global sum
283 error = grid_.comm().sum(error);
284
285 grid_.comm().max(errorMax, numContributions);
286 grid_.comm().min(errorMin, numContributions);
287
288 if (Dune::Fem::Parameter::verbose()) {
289 // print error estimator if on node 0
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) {
295 continue; // no contribution, just skip
296 }
297 std::cout << " " << errorNames[i] << "^2 min: " << errorMin[i] << std::endl;
298 std::cout << " " << errorNames[i] << "^2 max: " << errorMax[i] << std::endl;
299 }
300 std::cout << "hMax: " << hMax << std::endl;
301 }
302 return std::sqrt(error);
303 }
304
305 const DiscreteFunctionSpaceType& space() const
306 {
307 return dfSpace_;
308 }
309
310 protected:
311 void clear()
312 {
313 // resize and clear
314 BaseType::clear();
315
316 // the communication hack for parallel runs. Gnah.
317 localJumpStorage_.clear();
318 commJumpStorage_.clear();
319 if (useDG) {
320 localDGJumpStorage_.clear();
321 }
322
323 // debugging and stuff
324 errorMin[bulkPart] =
325 errorMin[jumpPart] =
326 errorMin[bdryPart] =
327 errorMin[commPart] = std::numeric_limits<RangeFieldType>::max();
328
329 errorMax[bulkPart] =
330 errorMax[jumpPart] =
331 errorMax[bdryPart] =
332 errorMax[commPart] = 0.0;
333 }
334
336 template<class DiscreteFunction>
337 void estimateLocal(const ElementType &entity, const DiscreteFunction& uh)
338 {
339 const auto& geometry = entity.geometry();
340 const auto h2 = h2Estimate(geometry);
341 const auto hFactor = Norm == L2Norm ? h2*h2 : h2;
342 const auto index = indexSet_.index(entity);
343 const auto uLocal = uh.localFunction(entity);
344
345 ElementQuadratureType quad(entity, 2*(dfSpace_.order() + 1));
346
347 model_.bind(entity);
348
349 RangeFieldType localEstimate = 0.0;
350 const auto numQuadraturePoints = quad.nop();
351 for (size_t qp = 0; qp < numQuadraturePoints; ++qp) {
352
353 const auto& x = quad.point(qp); //
354 const auto weight = quad.weight(qp) * geometry.integrationElement(x);
355
356 RangeType values;
357 uLocal.evaluate(x, values);
358
359 JacobianRangeType jacobian;
360 uLocal.jacobian(x, jacobian);
361
362 HessianRangeType hessian;
363 uLocal.hessian(x, hessian);
364
365 // Now compute the element residual
366 RangeType el_res(0.);
367 if (ModelTraits::template Exists<PDEModel::flux>::value) {
368 el_res += model_.fluxDivergence(quad[qp], values, jacobian, hessian);
369 }
370 if (ModelTraits::template Exists<PDEModel::source>::value) {
371 el_res += model_.source(quad[qp], values, jacobian);
372 }
373
374 localEstimate += hFactor * weight * (el_res * el_res);
375 }
376 this->storage_[index] += localEstimate;
377
378 errorMin[bulkPart] = std::min(errorMin[bulkPart], localEstimate);
379 errorMax[bulkPart] = std::max(errorMax[bulkPart], localEstimate);
380
381 // calculate face contribution
382 const auto end = gridPart_.iend(entity);
383 for (auto it = gridPart_.ibegin(entity); it != end; ++it) {
384
385 const auto& intersection = *it;
386
387 if (isProcessorBoundary(intersection)) {
388 // interior face accross a process boundary
389 estimateProcessorBoundary(intersection, entity, uLocal);
390 } else if (intersection.neighbor()) {
391 // interior face
392 estimateIntersection(intersection, entity, uh, uLocal);
393 } else if (intersection.boundary()) {
394 const auto active = model_.classifyBoundary(intersection);
395
396 assert(!active.first || active.second.all() || active.second.none());
397
398 if (!active.second.all()) {
399 estimateBoundary(intersection, entity, uLocal, active);
400 }
401 }
402 }
403
404 model_.unbind();
405 }
406
408 template<class DiscreteFunctionType>
409 void estimateIntersection(const IntersectionType &intersection,
410 const ElementType &inside,
411 const DiscreteFunctionType& uh,
412 const typename DiscreteFunctionType::LocalFunctionType &uInside)
413 {
414 if (!ModelTraits::template Exists<PDEModel::flux>::value) {
415 return; // 0 is a very smooth function ...
416 }
417
418 // get outside entity pointer
419 const auto outside = intersection.outside();
420
421 const auto insideIndex = indexSet_.index(inside);
422 const auto outsideIndex = indexSet_.index(outside);
423
424 const bool isOutsideInterior = (outside.partitionType() == Dune::InteriorEntity);
425 if (!isOutsideInterior || (insideIndex < outsideIndex)) {
426 const auto uOutside = uh.localFunction(outside);
427
428 RangeFieldType error;
429
430 if (intersection.conforming())
431 error = estimateIntersection<true>(intersection, inside, uInside, outside, uOutside);
432 else
433 error = estimateIntersection<false>(intersection, inside, uInside, outside, uOutside);
434
435 if (error > 0.0) {
436 this->storage_[insideIndex] += error;
437 if (isOutsideInterior) {
438 this->storage_[outsideIndex] += error;
439 }
440 }
441
442 errorMin[jumpPart] = std::min(errorMin[jumpPart], error);
443 errorMax[jumpPart] = std::max(errorMax[jumpPart], error);
444 }
445 }
446
448 template<bool conforming, class LocalFunctionType>
449 RangeFieldType estimateIntersection(const IntersectionType &intersection,
450 const ElementType &inside,
451 const LocalFunctionType &uInside,
452 const ElementType &outside,
453 const LocalFunctionType &uOutside)
454 {
455 // make sure correct method is called
456 assert(intersection.conforming() == conforming);
457
458 const auto h = 0.5 * (hEstimate(inside.geometry()) + hEstimate(outside.geometry()));
459
460 // use IntersectionQuadrature to create appropriate face quadratures
461 typedef Dune::Fem::IntersectionQuadrature<FaceQuadratureType, conforming> IntersectionQuadratureType;
462
463 const int quadOrder = 2 * (dfSpace_.order() - 1);
464 // create intersection quadrature
465 IntersectionQuadratureType intersectionQuad(gridPart_, intersection, quadOrder);
466
467 // get appropriate quadrature references
468 const auto& quadInside = intersectionQuad.inside();
469 const auto& quadOutside = intersectionQuad.outside();
470
471 const auto numQuadraturePoints = quadInside.nop();
472
473 modelNeighbour_.bind(outside); // go to neighbour
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();
480
481 // new stuff for dg estim
482 DomainType unitNormal = integrationNormal;
483 unitNormal/=integrationElement;
484
485 // evaluate | (d u_l * n_l) + (d u_r * n_r) | = | (d u_l - d u_r) * n_l |
486 // evaluate jacobian left and right of the interface and apply
487 // the diffusion tensor
488
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);
497
498 // Compute difference and multiply with normal
499 auto jump = contractInner(fluxInside - fluxOutside, integrationNormal);
500
501 error += quadInside.weight(qp) * (jump * jump) / integrationElement;
502
503 if (useDG) {
504 auto jump = valueInside - valueOutside;
505 dgError += quadInside.weight( qp ) * (jump * jump) * integrationElement;
506 }
507
508 }
509 modelNeighbour_.unbind();
510
511 const auto hFactor = Norm == L2Norm ? h * h * h : h;
512 error *= hFactor;
513
514 if (useDG) {
515 assert(Norm == H1Norm);
516 dgError /= h;
517 error += dgError;
518 }
519
520 return error;
521 }
522
527 {
528 if (commJumpStorage_.size() == 0) {
529 // not a parallel run.
530 return;
531 }
532
533 const bool verbose = Dune::Fem::Parameter::getValue<int>("fem.verboserank", 0) != -1;
534
535 DataHandleType dataHandle(indexSet_, commJumpStorage_);
536
537 gridPart_.communicate(dataHandle,
538 InteriorBorder_InteriorBorder_Interface,
539 ForwardCommunication);
540
541 // At this point commJumpStorage_ should contain the proper
542 // differences of the boundary flux contributions. It remains
543 // to performs the actual numerical quadrature summation.
544
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);
550
551 const auto& localData = local.second;
552 const auto& commData = remote.second;
553
554 const auto numQuadraturePoints = localData.size();
555
556 // form the square sum
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));
561 if (useDG) {
562 // comm uses "add", which is transformed into a "sub" by
563 // subtracting one the values twice.
564 RangeType jump = commData(numQuadraturePoints + qp);
565 jump.axpy(-2, localDGIt->second[qp]);
566 dgError += localData[qp] * (jump * jump);
567 }
568 }
569
570 // add the appropriate weights
571 // Storing the h-estimate in the last component of commData is a hack, PLEASE FIX ME ;)
572 // Note that after communication commData[#QP][0] already
573 // contains the sum of the h-estimate from both side.
574 const auto h = 0.5 * commData.hEstimate();
575 const auto hFactor = Norm == L2Norm ? h * h * h : h;
576
577 // add contribution to the estimator array
578 error *= hFactor;
579
580 if (useDG) {
581 assert(Norm == H1Norm);
582 dgError /= h;
583 error += dgError;
584 }
585
586 this->storage_[localData.bulkEntityIndex()] += error;
587
588 errorMin[commPart] = std::min(errorMin[commPart], error);
589 errorMax[commPart] = std::max(errorMax[commPart], error);
590
591 ++localIt;
592 if (useDG) {
593 ++localDGIt;
594 }
595 }
596
597 assert(localIt == localJumpStorage_.end());
598 assert(localDGIt == localDGJumpStorage_.end());
599
600 if (verbose) {
601 auto nFaces = commJumpStorage_.size();
602 nFaces = grid_.comm().sum(nFaces);
603
604 if (Dune::Fem::Parameter::verbose()) {
605 dwarn << "*** Processor Boundaries: "
606 << (RangeFieldType)nFaces/2.0
607 << " Faces ***" << std::endl;
608 }
609 }
610 }
611
624 template<class LocalFunctionType>
625 void estimateProcessorBoundary(const IntersectionType &intersection,
626 const ElementType &inside,
627 const LocalFunctionType &uInside)
628 {
629 if (!ModelTraits::template Exists<PDEModel::flux>::value) {
630 return; // 0 is a very smooth function ...
631 }
632
633 if (intersection.conforming()) {
634 estimateProcessorBoundary<true>(intersection, inside, uInside);
635 } else {
636 estimateProcessorBoundary<false>(intersection, inside, uInside);
637 }
638 }
639
644 template<bool conforming, class LocalFunctionType>
645 void estimateProcessorBoundary(const IntersectionType &intersection,
646 const ElementType &inside,
647 const LocalFunctionType &uInside)
648 {
649 // make sure correct method is called
650 assert(intersection.conforming() == conforming);
651
652 // use IntersectionQuadrature to create appropriate face quadratures
653 typedef Dune::Fem::IntersectionQuadrature<FaceQuadratureType, conforming> IntersectionQuadratureType;
654
655 const auto quadOrder = 2 * (dfSpace_.order() - 1);
656 // create intersection quadrature
657 IntersectionQuadratureType intersectionQuad(gridPart_, intersection, quadOrder);
658
659 // get appropriate quadrature references
660 const auto& quadInside = intersectionQuad.inside();
661 const auto numQuadraturePoints = quadInside.nop();
662
663 // FIXME: is there any easier way to get hold of the face-index?
664 const auto faceIndex = indexSet_.index(inside.template subEntity<1>(intersection.indexInInside()));
665 const auto bulkIndex = indexSet_.index(inside);
666
667 // commJumpStorage_ and localJumpStorage_ are maps, hence we
668 // first accumulate the results in the following two local
669 // variables and then add those variables to the communication
670 // arrays.
671 auto commSize = useDG ? 2*numQuadraturePoints : numQuadraturePoints;
672 IntersectionStorageType commData(commSize);
673 LocalIntersectionStorage localData(bulkIndex, numQuadraturePoints);
674 LocalIntersectionDGStorage localDGData(useDG ? numQuadraturePoints : 0);
675
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;
680
681 // evaluate | (d u_l * n_l) + (d u_r * n_r) | = | (d u_l - d u_r) * n_l |
682 // evaluate jacobian left and right of the interface and apply
683 // the diffusion tensor
684
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);
690
691 // Multiply with normal and store in the communication array.
692 *commData(qp) = contractInner(fluxInside, normal);
693 //fluxInside.mv(normal, *commData(qp));
694
695 if (useDG) {
696 localDGData[qp] = valueInside;
697 for (unsigned i = 0; i < valueInside.size(); ++i) {
698 (*commData(numQuadraturePoints + qp))[i] = valueInside[i];
699 }
700 }
701
702 // Remember weight and integration element for this point
703 localData[qp] = quadInside.weight(qp) * integrationElement;
704 }
705 localData.hEstimate() = hEstimate(inside.geometry());
706 // add for communication with the neighbour
707 commData.hEstimate() = localData.hEstimate();
708
709 commJumpStorage_[faceIndex] = commData;
710 localJumpStorage_[faceIndex] = localData;
711 if (useDG) {
712 localDGJumpStorage_[faceIndex] = localDGData;
713 }
714 }
715
723 template<class LocalFunctionType>
724 void estimateBoundary(const IntersectionType &intersection,
725 const ElementType &inside,
726 const LocalFunctionType &uLocal,
727 const BoundaryConditionsType& active)
728 {
729 if (!ModelTraits::template Exists<PDEModel::flux>::value
730 &&
731 !ModelTraits::template Exists<PDEModel::robinFlux>::value) {
732 return;
733 }
734
735 assert(intersection.conforming() == true);
736
737 typedef Dune::Fem::IntersectionQuadrature<FaceQuadratureType, true /* conforming */> IntersectionQuadratureType;
738
739 // TODO: make more realistic assumptions on the
740 // quad-order. HOWTO?
741 const auto quadOrder = 2*dfSpace_.order();
742 // create intersection quadrature
743 IntersectionQuadratureType intersectionQuad(gridPart_, intersection, quadOrder);
744 // get appropriate quadrature references
745 const auto& bndryQuad = intersectionQuad.inside();
746 const auto numQuadraturePoints = bndryQuad.nop();
747
748 const auto insideIndex = indexSet_.index(inside);
749
750 const auto h = hEstimate(inside.geometry());
751
752 RangeFieldType error = 0.0;
753
754 for (size_t qp = 0; qp < numQuadraturePoints; ++qp) {
755 const auto weight = bndryQuad.weight(qp);
756
757 // Get the outer normal and integration element
758 auto normal = intersection.integrationOuterNormal(bndryQuad.localPoint(qp));
759 const auto integrationElement = normal.two_norm();
760 normal /= integrationElement;
761
762 RangeType value;
763 uLocal.evaluate(bndryQuad[qp], value);
764
765 JacobianRangeType jacobian;
766 if (ModelTraits::template Exists<PDEModel::flux>::value
767 ||
768 ModelTraits::template Exists<PDEModel::robinFlux>::value) {
769 uLocal.jacobian(bndryQuad[qp], jacobian);
770 }
771
772 RangeType residual(0);
773
774 if (ModelTraits::template Exists<PDEModel::flux>::value) {
775 const auto flux = model_.flux(bndryQuad[qp], value, jacobian);
776 residual += contractInner(flux, normal);
777 //flux.umv(normal, residual);
778 }
779
780 if (ModelTraits::template Exists<PDEModel::robinFlux>::value) {
781 if (active.first) { // TODO: component-wise
782 residual += model_.robinFlux(bndryQuad[qp], normal, value, jacobian);
783 }
784 }
785
786 error += weight * integrationElement * (residual * residual);
787 }
788
789 if (error > 0.0) {
790 const auto hFactor = Norm == L2Norm ? h * h * h : h;
791
792 error *= hFactor;
793
794 this->storage_[insideIndex] += error;
795 }
796
797 errorMin[bdryPart] = std::min(errorMin[bdryPart], error);
798 errorMax[bdryPart] = std::max(errorMax[bdryPart], error);
799 }
800 };
801
803
805
806 } // ACFem:.
807
808} // Dune::
809
810#endif // __ELLIPTIC_ESTIMATOR_HH__
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
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)