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 
26 namespace 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.80.0 (May 4, 22:30, 2024)