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
15namespace 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();
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.111.3 (Aug 13, 22:30, 2024)