DUNE-ACFEM (2.5.1)

ellipticoperator.hh
1 #ifndef __ELLIPTIC_OPERATOR_HH__
2 #define __ELLIPTIC_OPERATOR_HH__
3 
4 #include <dune/common/fmatrix.hh>
5 
6 #include <dune/fem/operator/common/differentiableoperator.hh>
7 #include <dune/fem/operator/common/temporarylocalmatrix.hh>
8 #include <dune/fem/operator/common/stencil.hh>
9 
11 #include "../models/operatorparts/operatorparts.hh"
12 #include "../common/quadrature.hh"
13 #include "../functions/constantfunction.hh"
14 
15 namespace Dune {
16 
17  namespace ACFem {
18 
77  template<class OperatorParts,
78  class DomainFunction,
79  class RangeFunction = DomainFunction,
80  class Constraints = EmptyBlockConstraints<RangeFunction>,
81  template<class> class QuadratureTraits = DefaultQuadratureTraits>
83  : public virtual std::conditional<OperatorParts::isLinear,
84  Fem::LinearOperator<DomainFunction, RangeFunction>,
85  Fem::Operator<DomainFunction, RangeFunction> >::type
86  {
87  public:
88  typedef DomainFunction DomainFunctionType;
89  typedef RangeFunction RangeFunctionType;
90  typedef RangeFunctionType DiscreteFunctionType;
91  static_assert(std::is_base_of<Fem::IsDiscreteFunction, DiscreteFunctionType>::value,
92  "The RangeFunctionType has to be a discrete function");
93  static_assert(std::is_base_of<Fem::HasLocalFunction, DiscreteFunctionType>::value,
94  "The DomainFunctionType has to be provide a local function");
95  typedef OperatorParts OperatorPartsType;
96  typedef Constraints ConstraintsOperatorType;
97  protected:
98  typedef typename std::conditional<
99  std::is_same<ConstraintsOperatorType, EmptyBlockConstraints<RangeFunction> >::value,
101  const ConstraintsOperatorType&>::type
102  ConstraintsOperatorStorageType;
103  protected:
104  typedef typename ConstraintsOperatorType::LocalOperatorType LocalConstraintsOperatorType;
105 
106  typedef typename DomainFunctionType::FunctionSpaceType DomainFunctionSpaceType;
107  typedef typename RangeFunctionType::FunctionSpaceType RangeFunctionSpaceType;
108 
109  static_assert(std::is_same<DomainFunctionSpaceType, RangeFunctionSpaceType>::value,
110  "Domain and range function spaces have to be the same");
111 
112  typedef typename DiscreteFunctionType::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
113  typedef typename DiscreteFunctionType::LocalFunctionType LocalFunctionType;
114  typedef typename LocalFunctionType::RangeType RangeType;
115  typedef typename LocalFunctionType::JacobianRangeType JacobianRangeType;
116 
117  typedef typename DomainFunctionType::LocalFunctionType LocalDomainFunctionType;
118 
119  typedef typename DiscreteFunctionSpaceType::IteratorType IteratorType;
120  typedef typename IteratorType::Entity EntityType;
121  typedef typename EntityType::Geometry ElementGeometryType;
122 
123  typedef typename DiscreteFunctionSpaceType::DomainType DomainType;
124 
125  typedef typename DiscreteFunctionSpaceType::GridPartType GridPartType;
126  typedef typename GridPartType::IntersectionIteratorType IntersectionIteratorType;
127  typedef typename IntersectionIteratorType::Intersection IntersectionType;
128  typedef typename IntersectionType::Geometry IntersectionGeometryType;
129 
130  // This need much more work. Autsch.
131  typedef QuadratureTraits<GridPartType> QuadratureTraitsType;
132  typedef typename QuadratureTraitsType::BulkQuadratureType QuadratureType;
133  typedef typename QuadratureTraitsType::BulkMassQuadratureType MassQuadratureType;
134  typedef typename QuadratureTraitsType::FaceQuadratureType FaceQuadratureType;
135  typedef typename QuadratureTraitsType::FaceMassQuadratureType FaceMassQuadratureType;
136 
137  // use IntersectionQuadrature to create appropriate face quadratures
138  typedef Dune::Fem::IntersectionQuadrature<FaceQuadratureType, true> IntersectionQuadratureType;
139  // In principle we know that BndryQuadratureType equals FaceQuadratureType, but stick to the redirection.
140  typedef typename IntersectionQuadratureType::FaceQuadratureType BndryQuadratureType;
141 
142  typedef Dune::Fem::IntersectionQuadrature<FaceMassQuadratureType, true> IntersectionMassQuadratureType;
143  // In principle we know that BndryQuadratureType equals FaceQuadratureType, but stick to the redirection.
144  typedef typename IntersectionMassQuadratureType::FaceQuadratureType BndryMassQuadratureType;
145 
146  public:
148  EllipticOperator(const OperatorPartsType &parts,
149  const ConstraintsOperatorType& constraints = ConstraintsOperatorType())
150  : operatorParts_(parts), constraintsOperator_(constraints)
151  {}
152 
154  virtual void operator()(const DomainFunctionType &u, RangeFunctionType &w) const;
155 
157  virtual bool symmetric() const
158  {
159  return OperatorPartsType::isSymmetric;
160  }
161 
162  virtual bool positiveDefinite() const
163  {
164  return OperatorPartsType::isSemiDefinite;
165  }
166 
167  protected:
168  const ConstraintsOperatorType& constraints() const { return constraintsOperator_; }
169  const OperatorPartsType& operatorParts() const { return operatorParts_; }
170  OperatorPartsType& operatorParts() { return operatorParts_; }
171  private:
172  OperatorPartsType operatorParts_;
173  ConstraintsOperatorStorageType constraintsOperator_;
174  };
175 
176  template<class JacobianOperator,
177  class OperatorParts,
178  class Constraints = DifferentiableEmptyBlockConstraints<JacobianOperator>,
179  template<class> class QuadratureTraits = DefaultQuadratureTraits>
180  class DifferentiableEllipticOperator
181  : public EllipticOperator<OperatorParts,
182  typename JacobianOperator::DomainFunctionType,
183  typename JacobianOperator::RangeFunctionType,
184  Constraints, QuadratureTraits>,
185  public Fem::DifferentiableOperator<JacobianOperator>,
186  public virtual std::conditional<OperatorParts::isLinear,
187  Fem::AssembledOperator<typename JacobianOperator::DomainFunctionType,
188  typename JacobianOperator::RangeFunctionType>,
189  Fem::Operator<typename JacobianOperator::DomainFunctionType,
190  typename JacobianOperator::RangeFunctionType> >::type
191  {
192  typedef
193  EllipticOperator<OperatorParts,
194  typename JacobianOperator::DomainFunctionType,
195  typename JacobianOperator::RangeFunctionType,
196  Constraints, QuadratureTraits>
197  BaseType;
198  public:
199  typedef JacobianOperator JacobianOperatorType;
200  typedef typename JacobianOperatorType::DomainFunctionType DomainFunctionType;
201  typedef typename JacobianOperatorType::RangeFunctionType RangeFunctionType;
202  typedef DomainFunctionType DiscreteFunctionType;
203  typedef typename DomainFunctionType::LocalFunctionType LocalDomainFunctionType;
204  typedef OperatorParts OperatorPartsType;
205  typedef Constraints ConstraintsOperatorType;
206  protected:
207  typedef typename ConstraintsOperatorType::LocalOperatorType LocalConstraintsOperatorType;
208  protected:
209  typedef typename DiscreteFunctionType::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
210  typedef typename DiscreteFunctionType::LocalFunctionType LocalFunctionType;
211  typedef typename LocalFunctionType::RangeType RangeType;
212  typedef typename LocalFunctionType::JacobianRangeType JacobianRangeType;
213 
214  typedef typename DiscreteFunctionSpaceType::IteratorType IteratorType;
215  typedef typename IteratorType::Entity EntityType;
216  typedef typename EntityType::Geometry ElementGeometryType;
217 
218  typedef typename DiscreteFunctionSpaceType::DomainType DomainType;
219 
220  typedef typename DiscreteFunctionSpaceType::GridPartType GridPartType;
221  typedef typename GridPartType::IntersectionIteratorType IntersectionIteratorType;
222  typedef typename IntersectionIteratorType::Intersection IntersectionType;
223  typedef typename IntersectionType::Geometry IntersectionGeometryType;
224 
225  // This need much more work. Autsch.
226  typedef QuadratureTraits<GridPartType> QuadratureTraitsType;
227  typedef typename QuadratureTraitsType::BulkQuadratureType QuadratureType;
228  typedef typename QuadratureTraitsType::BulkMassQuadratureType MassQuadratureType;
229  typedef typename QuadratureTraitsType::FaceQuadratureType FaceQuadratureType;
230  typedef typename QuadratureTraitsType::FaceMassQuadratureType FaceMassQuadratureType;
231 
232  // use IntersectionQuadrature to create appropriate face quadratures
233  typedef Dune::Fem::IntersectionQuadrature<FaceQuadratureType, true> IntersectionQuadratureType;
234  // In principle we know that BndryQuadratureType equals FaceQuadratureType, but stick to the redirection.
235  typedef typename IntersectionQuadratureType::FaceQuadratureType BndryQuadratureType;
236 
237  typedef Dune::Fem::IntersectionQuadrature<FaceMassQuadratureType, true> IntersectionMassQuadratureType;
238  // In principle we know that BndryQuadratureType equals FaceQuadratureType, but stick to the redirection.
239  typedef typename IntersectionMassQuadratureType::FaceQuadratureType BndryMassQuadratureType;
240 
241  public:
243  DifferentiableEllipticOperator(const OperatorPartsType &parts,
244  const ConstraintsOperatorType& constraints = ConstraintsOperatorType())
245  : BaseType(parts, constraints)
246  {}
247 
249  using BaseType::operator();
250  using BaseType::symmetric;
251  using BaseType::positiveDefinite;
252 
254  void jacobian(const DiscreteFunctionType &u, JacobianOperatorType &jOp) const;
255 
256  protected:
257  using BaseType::operatorParts;
258  using BaseType::constraints;
259  };
260 
261  // Implementation of Application operator
262  template<class OperatorParts,
263  class DomainFunction, class RangeFunction,
264  class Constraints,
265  template<class> class QuadratureTraits>
267  ::operator()(const DomainFunction &u, RangeFunction &w) const
268  {
269  // clear destination
270  w.clear();
271 
272  // get discrete function space
273  const DiscreteFunctionSpaceType &dfSpace = w.space();
274  const GridPartType& gridPart = dfSpace.gridPart();
275 
276  const bool hasFlux = OperatorPartsType::hasFlux;
277  const bool hasSources = OperatorPartsType::hasSources;
278  const bool hasRobin = OperatorPartsType::hasRobinFlux;
279  const bool hasMassQuadrature = !std::is_same<QuadratureType, MassQuadratureType>::value;
280 
281  // possibly update
282  constraints().rebuild();
283  const bool doConstraints = constraints().size() > 0;
284 
285  // iterate over grid
286  const IteratorType end = dfSpace.end();
287  for (IteratorType it = dfSpace.begin(); it != end; ++it) {
288 
289  // get entity (here element)
290  const EntityType &entity = *it;
291  // get elements geometry
292  const ElementGeometryType &geometry = entity.geometry();
293 
294  // get local representation of the discrete functions
295  const LocalDomainFunctionType uLocal = u.localFunction(entity);
296 
297  LocalFunctionType wLocal = w.localFunction(entity);
298 
299  // call per-element initializer for the integral contributions
300  operatorParts().setEntity(entity);
301 
302  // obtain quadrature order
303  const int quadOrder = uLocal.order() + wLocal.order();
304 
305  if (hasSources || hasFlux) { // element integral, this computes all bulk contributions
306  QuadratureType quadrature(entity, quadOrder);
307  const size_t numQuadraturePoints = quadrature.nop();
308  for (size_t pt = 0; pt < numQuadraturePoints; ++pt) {
309 
310  const typename QuadratureType::CoordinateType &x = quadrature.point(pt);
311  const double weight = quadrature.weight(pt) * geometry.integrationElement(x);
312 
313  RangeType phiKern(0);
314  JacobianRangeType dPhiKern(0);
315 
316  // compute the second order contribution
317  JacobianRangeType du;
318  uLocal.jacobian(quadrature[pt], du);
319 
320  // compute the source contribution
321  RangeType vu;
322  uLocal.evaluate(quadrature[pt], vu);
323 
324  if (hasSources && !hasMassQuadrature) {
325  RangeType avu(0);
326  operatorParts().source(entity, quadrature[pt], vu, du, avu);
327  phiKern += avu;
328  }
329 
330  if (hasFlux) {
331  JacobianRangeType adu(0);
332  // apply flux (i.e. 2nd and first order terms)
333  operatorParts().flux(entity, quadrature[pt], vu, du, adu);
334  dPhiKern += adu;
335  }
336 
337  // add to local function
338  phiKern *= weight;
339  wLocal.axpy(quadrature[pt], phiKern);
340 
341  // add to local function
342  dPhiKern *= weight;
343  wLocal.axpy(quadrature[pt], dPhiKern);
344 
345  } // end quad loop
346 
347  // Special code-path to allow e.g. for mass-lumping
348  if (hasSources && hasMassQuadrature) {
349  MassQuadratureType quadrature(entity, quadOrder);
350 
351  const size_t numQuadraturePoints = quadrature.nop();
352  for (size_t pt = 0; pt < numQuadraturePoints; ++pt) {
353 
354  const typename MassQuadratureType::CoordinateType &x = quadrature.point(pt);
355  const double weight = quadrature.weight(pt) * geometry.integrationElement(x);
356 
357  // compute the second order contribution
358  JacobianRangeType du;
359  uLocal.jacobian(quadrature[pt], du);
360 
361  // compute the source contribution
362  RangeType vu;
363  uLocal.evaluate(quadrature[pt], vu);
364 
365  RangeType phiKern;
366  operatorParts().source(entity, quadrature[pt], vu, du, phiKern);
367 
368  // add to local function
369  phiKern *= weight;
370  wLocal.axpy(quadrature[pt], phiKern);
371  }
372  }
373 
374  } // end bulk block
375 
376  if (hasRobin) { // boundary integral
377 
378  IntersectionIteratorType iend = gridPart.iend(entity);
379  for (IntersectionIteratorType it = gridPart.ibegin(entity); it != iend; ++it) {
380 
381  const IntersectionType &intersection = *it;
382 
383  assert(intersection.conforming() == true);
384 
385  if (intersection.neighbor() || !intersection.boundary()) {
386  // Although one might want to augment the operator with
387  // stabilization terms later ("edge oriented FEM"). Maybe.
388  continue;
389  }
390 
391  if (!operatorParts().setIntersection(intersection)) {
392  continue;
393  }
394 
395  if (std::is_same<FaceQuadratureType, FaceMassQuadratureType>::value) {
396  int quadOrder = 3*dfSpace.order();
397 
398  IntersectionQuadratureType intersectionQuad(gridPart, intersection, quadOrder);
399  const BndryQuadratureType &bndryQuad = intersectionQuad.inside();
400  const int numQuadraturePoints = bndryQuad.nop();
401 
402  for (int pt = 0; pt < numQuadraturePoints; ++pt) {
403 
404  // One quad-loop for all contributions
405  RangeType phiKern;
406 
407  // quadrature weight
408  const double weight = bndryQuad.weight(pt);
409 
410  // Get the un-normalized outer normal
411  DomainType integrationNormal
412  = intersection.integrationOuterNormal(bndryQuad.localPoint(pt));
413 
414  const double integrationElement = integrationNormal.two_norm();
415 
416  integrationNormal /= integrationElement;
417 
418  RangeType vu;
419  uLocal.evaluate(bndryQuad[pt], vu);
420 
421  RangeType alphau;
422  operatorParts().robinFlux(intersection, bndryQuad[pt], integrationNormal, vu, phiKern);
423  phiKern *= weight * integrationElement;
424  wLocal.axpy(bndryQuad[pt], phiKern);
425  }
426 
427  } else { // potential mass-lumping
428 
429  IntersectionMassQuadratureType intersectionQuad(gridPart, intersection, quadOrder);
430  const BndryMassQuadratureType &bndryQuad = intersectionQuad.inside();
431  const int numQuadraturePoints = bndryQuad.nop();
432 
433  for (int pt = 0; pt < numQuadraturePoints; ++pt) {
434  // One quad-loop for all contributions
435 
436  // quadrature weight
437  const double weight = bndryQuad.weight(pt);
438 
439  // Get the un-normalized outer normal
440  DomainType integrationNormal
441  = intersection.integrationOuterNormal(bndryQuad.localPoint(pt));
442 
443  const double integrationElement = integrationNormal.two_norm();
444 
445  integrationNormal /= integrationElement;
446 
447  RangeType vu;
448  uLocal.evaluate(bndryQuad[pt], vu);
449 
450  RangeType phiKern;
451  operatorParts().robinFlux(intersection, bndryQuad[pt], integrationNormal, vu, phiKern);
452  phiKern *= weight *integrationElement;
453  wLocal.axpy(bndryQuad[pt], phiKern);
454 
455  } // end boundary mass-quadrature loop
456 
457  }
458 
459  } // end Intersection loop
460 
461  } // end boundary integral block
462 
463  if (false && doConstraints) {
464  // It is probably cheaper to apply constraints globally
465  LocalConstraintsOperatorType localConstraints(constraints().localOperator(entity));
466 
467  localConstraints(uLocal, wLocal);
468  }
469 
470  } // end mesh loop
471 
472  // communicate data (in parallel runs)
473  w.communicate();
474 
475  // Apply constraints
476  if (doConstraints) {
477  constraints()(u, w);
478  }
479  }
480 
481  // implementation of Jacobian
482  template<class JacobianOperator, class OperatorParts, class Constraints, template<class> class QuadratureTraits>
483  void DifferentiableEllipticOperator<JacobianOperator, OperatorParts, Constraints, QuadratureTraits>
484  ::jacobian (const DiscreteFunctionType &u, JacobianOperator &jOp) const
485  {
486  typedef typename JacobianOperator::LocalMatrixType LocalMatrixType;
487  typedef typename DiscreteFunctionSpaceType::BasisFunctionSetType BasisFunctionSetType;
488  // Diagonal stencil for entity-entity-pairing
489  typedef Dune::Fem::DiagonalStencil<DiscreteFunctionSpaceType, DiscreteFunctionSpaceType> StencilType;
490  typedef Dune::Fem::TemporaryLocalMatrix<DiscreteFunctionSpaceType, DiscreteFunctionSpaceType> ElementMatrixType;
491 
492  const DiscreteFunctionSpaceType &dfSpace = u.space();
493  const GridPartType& gridPart = dfSpace.gridPart();
494 
495  // DiagonalStencil
496 
497  jOp.reserve(StencilType(dfSpace, dfSpace));
498  jOp.clear();
499 
500  // BIG FAT NOTE: we need maxNumDofs * blockSize many items
501  const unsigned maxNumBasisFunctions =
502  DiscreteFunctionSpaceType::localBlockSize * dfSpace.blockMapper().maxNumDofs();
503  std::vector<typename LocalFunctionType::RangeType> phi(maxNumBasisFunctions);
504  std::vector<typename LocalFunctionType::JacobianRangeType> dphi(maxNumBasisFunctions);
505 
506  const bool hasFlux = OperatorPartsType::hasFlux;
507  const bool hasSources = OperatorPartsType::hasSources;
508  const bool hasRobin = OperatorPartsType::hasRobinFlux;
509  const bool isAffineLinear = OperatorPartsType::isLinear;
510  const bool hasMassQuadrature = !std::is_same<QuadratureType, MassQuadratureType>::value;
511 
512  // possibly update
513  constraints().rebuild();
514  const bool doConstraints = constraints().size() > 0;
515 
516  RangeType u0(0);
517  JacobianRangeType Du0(0);
518 
519  LocalConstraintsOperatorType localConstraints(constraints().localOperator());
520  bool totallyConstrained = false;
521 
522  ElementMatrixType elementMatrix(dfSpace, dfSpace);
523 
524  const IteratorType end = dfSpace.end();
525  for (IteratorType it = dfSpace.begin(); it != end; ++it) {
526  const EntityType &entity = *it;
527  const ElementGeometryType &geometry = entity.geometry();
528 
529  // call per-element initializer for the operator
530  operatorParts().setEntity(entity);
531 
532  const LocalDomainFunctionType uLocal = u.localFunction(entity);
533  //auto elementMatrix = jOp.localMatrix(entity, entity);
534  elementMatrix.init(entity, entity);
535  elementMatrix.clear();
536 
537  const BasisFunctionSetType &baseSet = elementMatrix.domainBasisFunctionSet();
538  const unsigned int numBaseFunctions = baseSet.size();
539 
540  if (doConstraints) {
541  localConstraints.init(entity);
542  totallyConstrained = localConstraints.totallyConstrained();
543  }
544 
545  if (!totallyConstrained && (hasFlux || hasSources)) { // bulk integration
546 
547  QuadratureType quadrature(entity, 2*dfSpace.order());
548  const size_t numQuadraturePoints = quadrature.nop();
549 
550  for (size_t pt = 0; pt < numQuadraturePoints; ++pt) {
551 
552  const typename QuadratureType::CoordinateType &x = quadrature.point(pt);
553  const double weight = quadrature.weight(pt) * geometry.integrationElement(x);
554 
555  //const typename ElementGeometryType::Jacobian &gjit = geometry.jacobianInverseTransposed(x);
556 
557  // evaluate all basis functions at given quadrature point
558  baseSet.evaluateAll(quadrature[pt], phi);
559 
560  // evaluate jacobians of all basis functions at given quadrature point
561  baseSet.jacobianAll(quadrature[pt], /*gjit,*/ dphi);
562 
563  if (!isAffineLinear) { // get values for linearization
564  uLocal.evaluate(quadrature[pt], u0);
565  uLocal.jacobian(quadrature[pt], Du0);
566  }
567 
568  RangeType aphi(0); // Zero order
569  JacobianRangeType adphi(0); // Second order
570 
571  for (unsigned int localCol = 0; localCol < numBaseFunctions; ++localCol) {
572 
573  if (hasSources && !hasMassQuadrature) {
574  operatorParts().linearizedSource(u0, Du0, entity, quadrature[pt], phi[localCol], dphi[localCol], aphi);
575  } else {
576  aphi = 0;
577  }
578 
579  if (hasFlux) {
580  operatorParts().linearizedFlux(u0, Du0, entity, quadrature[pt], phi[localCol], dphi[localCol], adphi);
581  } else {
582  adphi = 0;
583  }
584 
585  // get column object and call axpy method
586  elementMatrix.column(localCol).axpy(phi, dphi, aphi, adphi, weight);
587  }
588 
589  }
590 
591  // Special case for e.g. mass-lumping using a "lumping"-quadrature
592  if (hasSources && hasMassQuadrature) {
593 
594  MassQuadratureType quadrature(entity, 2*dfSpace.order());
595  const size_t numQuadraturePoints = quadrature.nop();
596 
597  for (size_t pt = 0; pt < numQuadraturePoints; ++pt) {
598 
599  const typename MassQuadratureType::CoordinateType &x = quadrature.point(pt);
600  const double weight = quadrature.weight(pt) * geometry.integrationElement(x);
601 
602  //const typename ElementGeometryType::Jacobian &gjit = geometry.jacobianInverseTransposed(x);
603 
604  // evaluate all basis functions at given quadrature point
605  baseSet.evaluateAll(quadrature[pt], phi);
606 
607  if (!isAffineLinear) { // get value for linearization
608  uLocal.evaluate(quadrature[pt], u0);
609  uLocal.jacobian(quadrature[pt], Du0);
610  }
611 
612  RangeType aphi(0); // Zero order
613  JacobianRangeType adphi(0); // Second order
614 
615  for (unsigned int localCol = 0; localCol < numBaseFunctions; ++localCol) {
616 
617  operatorParts().linearizedSource(u0, Du0, entity, quadrature[pt], phi[localCol], dphi[localCol], aphi);
618 
619  adphi = 0;
620 
621  // get column object and call axpy method
622  elementMatrix.column(localCol).axpy(phi, dphi, aphi, adphi, weight);
623  }
624  }
625  } // mass lumping part
626 
627  } // end bulk integration
628 
629  if (!totallyConstrained && hasRobin) { // boundary contribution
630 
631  IntersectionIteratorType iend = dfSpace.gridPart().iend(entity);
632  for (IntersectionIteratorType it = dfSpace.gridPart().ibegin(entity); it != iend; ++it) {
633 
634  const IntersectionType &intersection = *it;
635 
636  assert(intersection.conforming() == true);
637 
638  if (intersection.neighbor() || !intersection.boundary()) {
639  // Although one might want to augment the operator with
640  // stabilization terms later ("edge oriented FEM"). Maybe.
641  continue;
642  }
643 
644  if (!operatorParts().setIntersection(intersection)) {
645  continue;
646  }
647 
648 
649  // TODO: make more realistic assumptions on the
650  // quad-order. HOWTO?
651  int quadOrder = 3*dfSpace.order();
652 
653  IntersectionMassQuadratureType intersectionQuad(gridPart, intersection, quadOrder);
654  const BndryMassQuadratureType &bndryQuad = intersectionQuad.inside();
655  const int numQuadraturePoints = bndryQuad.nop();
656 
657  for (int pt = 0; pt < numQuadraturePoints; ++pt) {
658  // One quad-loop for all contributions
659 
660  // quadrature weight
661  const double weight = bndryQuad.weight(pt);
662 
663  // Get the un-normalized outer normal
664  DomainType integrationNormal
665  = intersection.integrationOuterNormal(bndryQuad.localPoint(pt));
666 
667  // Only needed for Robin
668  double integrationElement = integrationNormal.two_norm();
669 
670  integrationNormal /= integrationElement;
671 
672  // Get values of all basis functions at the
673  // quad-points. Gradients are not needed.
674  baseSet.evaluateAll(bndryQuad[pt], phi);
675 
676  if (!isAffineLinear) {
677  // get value for linearization
678  uLocal.evaluate(bndryQuad[pt], u0);
679  }
680 
681  for (unsigned int localCol = 0; localCol < numBaseFunctions; ++localCol) {
682 
683  RangeType alphaphi;
684  operatorParts().linearizedRobinFlux(u0, intersection, bndryQuad[pt], integrationNormal, phi[localCol], alphaphi);
685  alphaphi *= integrationElement;
686 
687  // get column object and call axpy method
688  elementMatrix.column(localCol).axpy(phi, alphaphi, weight);
689  } // basis function loop
690  } // quad loop
691 
692  } // intersection loop
693 
694  } // boundary contribution
695 
696  if (doConstraints) {
697  // As we can access matrix entries only via the LocalMatrix
698  // objects applying constraints globally would require yet
699  // another mesh-loop. So we do it locally.
700  localConstraints.jacobian(uLocal /* unused */, elementMatrix);
701  }
702 
703  jOp.addLocalMatrix(entity, entity, elementMatrix);
704 
705  } // end grid traversal
706 
707  jOp.communicate();
708  }
709 
711 
713 
714  } // namespace ACFem
715 
716 } // namespace Dune
717 
718 #endif // #ifndef ELLIPTIC_HH
A class defining an elliptic operator.
Definition: ellipticoperator.hh:86
EllipticOperator(const OperatorPartsType &parts, const ConstraintsOperatorType &constraints=ConstraintsOperatorType())
contructor
Definition: ellipticoperator.hh:148
virtual bool symmetric() const
linear operator interface
Definition: ellipticoperator.hh:157
A class modelling do-nothing constraints.
Definition: emptyblockconstraints.hh:40
Empty do-nothing constraints.
virtual void operator()(const DomainFunctionType &u, RangeFunctionType &w) const
application operator, works "on the fly"
Definition: ellipticoperator.hh:267
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 10, 22:30, 2024)