1#ifndef __ELLIPTIC_OPERATOR_HH__
2#define __ELLIPTIC_OPERATOR_HH__
5#include <dune/common/fmatrix.hh>
7#include <dune/fem/operator/common/differentiableoperator.hh>
8#include <dune/fem/operator/common/temporarylocalmatrix.hh>
9#include <dune/fem/operator/common/stencil.hh>
12#include "../models/modelfacade.hh"
13#include "../common/quadrature.hh"
14#include "../algorithms/operatorselector.hh"
80 class RangeFunction = DomainFunction,
81 class Constraints = EmptyBlockConstraints<typename RangeFunction::DiscreteFuncionSpaceType>,
84 :
public virtual std::conditional<EffectiveModelTraits<Model>::isLinear,
85 Fem::LinearOperator<DomainFunction, RangeFunction>,
86 Fem::Operator<DomainFunction, RangeFunction> >::type
88 typedef typename std::conditional<
89 EffectiveModelTraits<Model>::isLinear,
90 Fem::LinearOperator<DomainFunction, RangeFunction>,
91 Fem::Operator<DomainFunction, RangeFunction> >::type
95 using typename BaseType::DomainFunctionType;
100 using typename BaseType::RangeFunctionType;
103 using typename BaseType::DomainFieldType;
106 using typename BaseType::RangeFieldType;
115 static_assert(std::is_base_of<Fem::IsDiscreteFunction, RangeFunctionType>::value,
116 "The RangeFunctionType has to be a discrete function");
118 static_assert(std::is_base_of<Fem::HasLocalFunction, DomainFunctionType>::value,
119 "The DomainFunctionType has to be provide a local function");
121 using ModelTraits = EffectiveModelTraits<Model>;
122 using ModelType = EffectiveModel<Model>;
124 using ConstraintsOperatorType = std::decay_t<Constraints>;
126 typedef typename DomainFunctionType::FunctionSpaceType DomainFunctionSpaceType;
127 typedef typename RangeFunctionType::FunctionSpaceType RangeFunctionSpaceType;
129 dimRange = RangeFunctionSpaceType::dimRange,
130 dimDomain = RangeFunctionSpaceType::dimDomain
132 typedef typename RangeFunctionSpaceType::DomainType DomainType;
133 typedef typename RangeFunctionSpaceType::RangeType RangeType;
134 typedef typename RangeFunctionSpaceType::JacobianRangeType JacobianRangeType;
137 static_assert(std::is_same<DomainType, typename DomainFunctionSpaceType::DomainType>::value,
138 "Domain and range functions need to live on the same domain");
141 static_assert(std::is_same<DomainFunctionSpaceType, RangeFunctionSpaceType>::value,
142 "Domain and range function spaces have to be the same");
144 typedef typename RangeFunctionType::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
145 typedef typename RangeFunctionType::LocalFunctionType LocalFunctionType;
147 typedef typename Fem::ConstLocalFunction<DomainFunctionType> LocalDomainFunctionType;
149 typedef typename DiscreteFunctionSpaceType::GridPartType GridPartType;
150 typedef typename GridPartType::IntersectionIteratorType IntersectionIteratorType;
151 typedef typename IntersectionIteratorType::Intersection IntersectionType;
167 template<
bool conforming>
182 static constexpr bool hasFlux = ModelTraits::template Exists<PDEModel::flux>::value;
183 static constexpr bool hasSources = ModelTraits::template Exists<PDEModel::source>::value;
184 static constexpr bool hasRobin = ModelTraits::template Exists<PDEModel::robinFlux>::value;
185 static constexpr bool hasSingular = ModelTraits:: template Exists<PDEModel::singularFlux>::value;
186 static constexpr bool isAffineLinear = ModelTraits::isLinear;
191 static constexpr bool useDG = DGSelectorType::useDG;
192 static constexpr DGFlavour dgFlavour = DGSelectorType::dgFlavour;
193 static constexpr int sFormDG = DGSelectorType::sFormDG;
208 template<
class ConstraintsArg,
209 std::enable_if_t<std::is_constructible<Constraints, ConstraintsArg>::value,
int> = 0>
212 , constraintsOperator_(constraints)
231 : model_(other.model_)
232 , constraintsOperator_(
std::move(other.constraintsOperator_))
233 , penalty_(other.penalty_)
237 : model_(
std::move(other.model_))
238 , constraintsOperator_(
std::move(other.constraintsOperator_))
239 , penalty_(
std::move(other.penalty_))
243 virtual void operator() (
const DomainFunctionType &u, RangeFunctionType &w)
const;
251 virtual bool positiveDefinite()
const
257 const ConstraintsOperatorType& constraints()
const {
258 return constraintsOperator_;
260 const ModelType& model()
const {
266 const ModelClosure& closure()
const {
269 ModelClosure& closure() {
272 const double penalty()
const {
277 template<
bool conforming>
278 void computeInteriorSkeletonContributions(
279 const GridPartType& gridPart,
280 const IntersectionType& intersection,
281 const RangeFieldType& penalty,
282 const LocalDomainFunctionType& uLocal,
283 const LocalDomainFunctionType& uLocalNb,
284 const ModelClosure& model,
285 const ModelClosure& modelNb,
286 LocalFunctionType& wLocal)
const;
290 Constraints constraintsOperator_;
291 const double penalty_;
294 template<
class JacobianOperator,
296 class Constraints = EmptyBlockConstraints<typename JacobianOperator::RangeFunctionType::DiscreteFunctionSpaceType>,
298 class DifferentiableEllipticOperator
299 :
public EllipticOperator<Model,
300 typename JacobianOperator::DomainFunctionType,
301 typename JacobianOperator::RangeFunctionType,
302 Constraints, QuadratureTraits>,
303 public virtual Fem::DifferentiableOperator<JacobianOperator>,
304 public virtual std::conditional<EffectiveModelTraits<Model>::isLinear,
305 Fem::AssembledOperator<typename JacobianOperator::DomainFunctionType,
306 typename JacobianOperator::RangeFunctionType>,
307 Fem::Operator<typename JacobianOperator::DomainFunctionType,
308 typename JacobianOperator::RangeFunctionType> >::type
312 typename JacobianOperator::DomainFunctionType,
313 typename JacobianOperator::RangeFunctionType,
317 using JacobianOperatorType = JacobianOperator;
319 using typename BaseType::ModelType;
320 using typename BaseType::ModelClosure;
321 using typename BaseType::ModelTraits;
322 using typename BaseType::ConstraintsOperatorType;
324 using typename BaseType::DomainFunctionType;
325 using typename BaseType::RangeFunctionType;
327 using typename BaseType::DomainFieldType;
328 using typename BaseType::RangeFieldType;
330 static_assert(std::is_base_of<Fem::IsDiscreteFunction, DomainFunctionType>::value,
331 "For matrix assembly the DomainFunctionType has to be a discrete function");
336 using BaseType::dimDomain;
337 using BaseType::dimRange;
339 using typename BaseType::DomainFunctionSpaceType;
340 using typename BaseType::LocalDomainFunctionType;
342 using typename BaseType::DiscreteFunctionSpaceType;
343 using typename BaseType::LocalFunctionType;
345 using typename BaseType::GridPartType;
346 using typename BaseType::IntersectionType;
348 using typename BaseType::RangeType;
349 using typename BaseType::JacobianRangeType;
356 template<
bool conforming>
357 using IntersectionQuadrature =
typename BaseType::template IntersectionQuadrature<conforming>;
359 using BaseType::hasFlux;
360 using BaseType::hasSources;
361 using BaseType::hasRobin;
362 using BaseType::hasSingular;
363 using BaseType::isAffineLinear;
364 using BaseType::hasMassQuadrature;
365 using BaseType::hasFaceMassQuadrature;
366 using BaseType::useDG;
367 using BaseType::dgFlavour;
368 using BaseType::sFormDG;
371 using DiscreteDomainFunctionSpaceType =
typename DomainFunctionType::DiscreteFunctionSpaceType;
373 static_assert(std::is_same<DiscreteDomainFunctionSpaceType, DiscreteFunctionSpaceType>::value,
374 "Unfortunately the discrete function space type of domain and range need to coincide. Sorry for that.");
376 using ElementMatrixType = Fem::TemporaryLocalMatrix<DiscreteDomainFunctionSpaceType, DiscreteFunctionSpaceType>;
384 typename JacobianOperator::DomainFunctionType,
385 typename JacobianOperator::RangeFunctionType,
389 using BaseType::operator();
391 using BaseType::positiveDefinite;
394 void jacobian(
const DomainFunctionType &u, JacobianOperatorType &jOp)
const;
398 mutable std::vector<RangeType> phi_;
399 mutable std::vector<JacobianRangeType> dphi_;
401 mutable std::vector<RangeType> phiNb_;
402 mutable std::vector<JacobianRangeType> dphiNb_;
404 void reserveAssemblyStorage(
size_t maxNumBasisFunctions)
const
406 phi_.resize(maxNumBasisFunctions);
407 dphi_.resize(maxNumBasisFunctions);
409 phiNb_.resize(maxNumBasisFunctions);
410 dphiNb_.resize(maxNumBasisFunctions);
413 void releaseAssemblyStorage()
const
422 template<
bool conforming>
423 void computeInteriorSkeletonContributions(
424 const GridPartType& gridPart,
425 const IntersectionType& intersection,
426 const RangeFieldType& penalty,
427 const LocalDomainFunctionType& uLocal,
428 const LocalDomainFunctionType& uLocalNb,
429 const ModelClosure& model,
430 const ModelClosure& modelNb,
431 ElementMatrixType& elementMatrix,
432 ElementMatrixType& elementMatrixNb)
const;
435 using BaseType::model_;
436 using BaseType::model;
437 using BaseType::closure;
438 using BaseType::constraints;
439 using BaseType::penalty;
443 template<
class Model,
444 class DomainFunction,
class RangeFunction,
454 const auto& dfSpace = w.space();
455 const auto& gridPart = dfSpace.gridPart();
461 constraints().update();
466 LocalDomainFunctionType uLocal(u);
467 LocalDomainFunctionType uLocalNb(u);
468 LocalFunctionType wLocal(w);
471 auto model = closure();
474 auto modelNb = closure();
477 const auto end = dfSpace.end();
478 for (
auto it = dfSpace.begin(); it != end; ++it) {
481 const auto& entity = *it;
483 const auto& geometry = entity.geometry();
494 if constexpr((hasSources && !hasMassQuadrature) || hasFlux) {
496 const int quadOrder = uLocal.order() + wLocal.order();
500 const size_t numQuadraturePoints = quadrature.nop();
501 for (
size_t pt = 0; pt < numQuadraturePoints; ++pt) {
503 const typename QuadratureType::CoordinateType &x = quadrature.point(pt);
504 const double weight = quadrature.weight(pt) * geometry.integrationElement(x);
506 RangeType phiKern(0);
507 JacobianRangeType dPhiKern(0);
510 JacobianRangeType du;
511 uLocal.jacobian(quadrature[pt], du);
515 uLocal.evaluate(quadrature[pt], vu);
517 if constexpr (hasSources && !hasMassQuadrature && hasFlux) {
518 RangeType phiKern = weight * model.source(quadrature[pt], vu, du);
519 JacobianRangeType dPhiKern = weight * model.flux(quadrature[pt], vu, du);
520 wLocal.axpy(quadrature[pt], phiKern, dPhiKern);
521 }
else if constexpr (hasFlux) {
522 JacobianRangeType dPhiKern = weight * model.flux(quadrature[pt], vu, du);
523 wLocal.axpy(quadrature[pt], dPhiKern);
525 RangeType phiKern = weight * model.source(quadrature[pt], vu, du);
526 wLocal.axpy(quadrature[pt], phiKern);
532 if constexpr (hasSources && hasMassQuadrature) {
534 const int quadOrder = uLocal.order() + wLocal.order();
538 const size_t numQuadraturePoints = quadrature.nop();
539 for (
size_t pt = 0; pt < numQuadraturePoints; ++pt) {
541 const typename MassQuadratureType::CoordinateType &x = quadrature.point(pt);
542 const double weight = quadrature.weight(pt) * geometry.integrationElement(x);
545 JacobianRangeType du;
546 uLocal.jacobian(quadrature[pt], du);
550 uLocal.evaluate(quadrature[pt], vu);
552 RangeType phiKern = weight * model.source(quadrature[pt], vu, du);
555 wLocal.axpy(quadrature[pt], phiKern);
561 if constexpr (useDG || hasRobin || hasSingular) {
563 const auto area = useDG ? entity.geometry().volume() : 0.0;
565 const auto end = gridPart.iend(entity);
566 for (
auto it = gridPart.ibegin(entity); it != end; ++it ) {
569 const auto& intersection = *it;
570 if (useDG && intersection.neighbor()) {
571 const auto neighbor = intersection.outside() ;
572 const auto& intersectionGeometry = intersection.geometry();
575 const auto intersectionArea = intersectionGeometry.volume();
577 const auto beta = penalty() * intersectionArea / std::min(area, neighbor.geometry().volume());
579 modelNb.bind(neighbor);
580 uLocalNb.bind(neighbor);
582 if (intersection.conforming()) {
583 computeInteriorSkeletonContributions<true>(
584 gridPart, intersection, beta, uLocal, uLocalNb, model, modelNb, wLocal);
586 computeInteriorSkeletonContributions<false>(
587 gridPart, intersection, beta, uLocal, uLocalNb, model, modelNb, wLocal);
594 }
else if (intersection.boundary() && (hasRobin || hasSingular)) {
596 const auto bdCond = model.classifyBoundary(intersection);
598 if (bdCond.first && !bdCond.second.all()) {
600 int quadOrder = 3*dfSpace.order();
602 const auto &bndryQuad = intersectionQuad.inside();
603 const int numQuadraturePoints = bndryQuad.nop();
605 for (
int pt = 0; pt < numQuadraturePoints; ++pt) {
607 const double weight = bndryQuad.weight(pt);
610 DomainType integrationNormal
611 = intersection.integrationOuterNormal(bndryQuad.localPoint(pt));
613 const double integrationElement = integrationNormal.two_norm();
615 integrationNormal /= integrationElement;
618 uLocal.evaluate(bndryQuad[pt], vu);
619 JacobianRangeType du;
620 uLocal.jacobian(bndryQuad[pt], du);
622 if constexpr (hasRobin && hasSingular) {
623 RangeType phiKern = weight * integrationElement * model.robinFlux(bndryQuad[pt], integrationNormal, vu, du);
624 JacobianRangeType dphiKern = weight * integrationElement * model.singularFlux(bndryQuad[pt], integrationNormal, vu, du);
625 wLocal.axpy(bndryQuad[pt], phiKern, dphiKern);
626 }
else if constexpr (hasRobin) {
627 RangeType phiKern = weight *integrationElement * model.robinFlux(bndryQuad[pt], integrationNormal, vu, du);
628 wLocal.axpy(bndryQuad[pt], phiKern);
629 }
else if constexpr (hasSingular) {
630 JacobianRangeType dphiKern = weight * integrationElement * model.singularFlux(bndryQuad[pt], integrationNormal, vu, du);
631 wLocal.axpy(bndryQuad[pt], dphiKern);
653 template<
class Model,
654 class DomainFunction,
class RangeFunction,
657 template<
bool conforming>
660 const GridPartType& gridPart,
661 const IntersectionType& intersection,
662 const RangeFieldType& penalty,
663 const LocalDomainFunctionType& uLocal,
664 const LocalDomainFunctionType& uLocalNb,
665 const ModelClosure& model,
666 const ModelClosure& modelNb,
667 LocalFunctionType& wLocal)
const
669 const int quadOrder = std::max(uLocal.order(),uLocalNb.order()) + wLocal.order();
670 IntersectionQuadrature<conforming> intersectionQuad(gridPart, intersection, quadOrder);
671 const auto& quadInside = intersectionQuad.inside();
672 const auto& quadOutside = intersectionQuad.outside();
674 const size_t numQuadraturePoints = quadInside.nop();
676 for (
size_t pt = 0; pt < numQuadraturePoints; ++pt) {
679 const auto& x = quadInside.localPoint(pt);
680 const auto integrationNormal = intersection.integrationOuterNormal(x);
681 const auto integrationElement = integrationNormal.two_norm();
682 const auto weight = quadInside.weight( pt );
685 JacobianRangeType dvalue;
687 RangeType vuIn, vuOut, jump;
688 JacobianRangeType duIn, duOut;
689 uLocal.evaluate(quadInside[pt], vuIn);
690 uLocal.jacobian(quadInside[pt], duIn);
691 auto aduIn = model.flux(quadInside[pt], vuIn, duIn);
693 uLocalNb.evaluate(quadOutside[ pt ], vuOut);
694 uLocalNb.jacobian(quadOutside[ pt ], duOut);
695 auto aduOut = modelNb.flux(quadOutside[pt], vuOut, duOut);
703 value = penalty * integrationElement * jump;
707 value +=
contractInner(-(aduIn + aduOut)/2_f, integrationNormal);
711 dvalue = -0.5 * sFormDG *
outer(jump, integrationNormal);
713 for (
int r = 0; r < dimRange; ++r) {
714 for (
int d = 0; d < dimDomain; ++d) {
715 dvalue[r][d] = -0.5 * sFormDG * integrationNormal[d] * jump[r];
720 auto adValue = model.flux(quadInside[pt], jump, dvalue);
722 wLocal.axpy(quadInside[pt], (RangeType)(weight * value), (JacobianRangeType)(weight * adValue));
728 template<
class JacobianOperator,
729 class Model,
class Constraints,
731 void DifferentiableEllipticOperator<JacobianOperator, Model, Constraints, QuadratureTraits>
732 ::jacobian (
const DomainFunctionType &u, JacobianOperator &jOp)
const
736 typedef typename std::conditional<!(useDG),
737 Dune::Fem::DiagonalStencil<DiscreteFunctionSpaceType,
738 DiscreteFunctionSpaceType>,
739 Dune::Fem::DiagonalAndNeighborStencil<DiscreteFunctionSpaceType,
740 DiscreteFunctionSpaceType>
742 typedef Dune::Fem::TemporaryLocalMatrix<DiscreteFunctionSpaceType, DiscreteFunctionSpaceType> ElementMatrixType;
744 const DiscreteFunctionSpaceType & dfSpace = u.space();
745 const GridPartType& gridPart = dfSpace.gridPart();
748 jOp.reserve(StencilType(dfSpace, dfSpace));
752 const size_t maxNumBasisFunctions =
753 DiscreteFunctionSpaceType::localBlockSize * dfSpace.blockMapper().maxNumDofs();
755 reserveAssemblyStorage(maxNumBasisFunctions);
757 ElementMatrixType elementMatrix(dfSpace, dfSpace);
758 ElementMatrixType elementMatrixNb(dfSpace, dfSpace);
762 LocalDomainFunctionType uLocal(u);
764 JacobianRangeType Du0(0);
767 LocalDomainFunctionType uLocalNb(u);
769 JacobianRangeType Du0Nb(0);
772 auto model = closure();
775 auto modelNb = closure();
779 constraints().update();
782 const auto end = dfSpace.end();
783 for (
auto it = dfSpace.begin(); it != end; ++it) {
784 const auto &entity = *it;
793 const auto& geometry = entity.geometry();
797 if constexpr (!isAffineLinear) {
802 elementMatrix.init(entity, entity);
803 elementMatrix.clear();
805 const auto& baseSet = elementMatrix.domainBasisFunctionSet();
806 const auto numBaseFunctions = baseSet.size();
808 if constexpr ((hasSources && !hasMassQuadrature) || hasFlux) {
811 QuadratureType quadrature(entity, 2*dfSpace.order());
812 const size_t numQuadraturePoints = quadrature.nop();
814 for (
size_t pt = 0; pt < numQuadraturePoints; ++pt) {
816 const auto& x = quadrature.point(pt);
817 const auto weight = quadrature.weight(pt) * geometry.integrationElement(x);
820 baseSet.evaluateAll(quadrature[pt], phi_);
823 baseSet.jacobianAll(quadrature[pt], dphi_);
825 if constexpr (!isAffineLinear) {
826 uLocal.evaluate(quadrature[pt], u0);
827 uLocal.jacobian(quadrature[pt], Du0);
830 for (
size_t localCol = 0; localCol < numBaseFunctions; ++localCol) {
831 if constexpr (hasSources && !hasMassQuadrature && hasFlux) {
832 auto aphi = model.linearizedSource(u0, Du0, quadrature[pt], phi_[localCol], dphi_[localCol]);
833 auto adphi = model.linearizedFlux(u0, Du0, quadrature[pt], phi_[localCol], dphi_[localCol]);
834 elementMatrix.column(localCol).axpy(phi_, dphi_, aphi, adphi, weight);
835 }
else if constexpr (hasFlux) {
836 auto adphi = model.linearizedFlux(u0, Du0, quadrature[pt], phi_[localCol], dphi_[localCol]);
837 elementMatrix.column(localCol).axpy(dphi_, adphi, weight);
839 auto aphi = model.linearizedSource(u0, Du0, quadrature[pt], phi_[localCol], dphi_[localCol]);
840 elementMatrix.column(localCol).axpy(phi_, aphi, weight);
847 if constexpr (hasSources && hasMassQuadrature) {
849 MassQuadratureType quadrature(entity, 2*dfSpace.order());
850 const size_t numQuadraturePoints = quadrature.nop();
852 for (
size_t pt = 0; pt < numQuadraturePoints; ++pt) {
854 const typename MassQuadratureType::CoordinateType &x = quadrature.point(pt);
855 const double weight = quadrature.weight(pt) * geometry.integrationElement(x);
860 baseSet.evaluateAll(quadrature[pt], phi_);
863 baseSet.jacobianAll(quadrature[pt], dphi_);
865 if constexpr (!isAffineLinear) {
866 uLocal.evaluate(quadrature[pt], u0);
867 uLocal.jacobian(quadrature[pt], Du0);
870 for (
size_t localCol = 0; localCol < numBaseFunctions; ++localCol) {
872 auto aphi = model.linearizedSource(u0, Du0, quadrature[pt], phi_[localCol], dphi_[localCol]);
875 elementMatrix.column(localCol).axpy(phi_, aphi, weight);
882 if constexpr (useDG || hasRobin) {
884 const auto area = useDG ? geometry.volume() : 0.0;
886 const auto end = gridPart.iend(entity);
887 for (
auto it = gridPart.ibegin(entity); it != end; ++it) {
888 const auto& intersection = *it;
890 if (useDG && intersection.neighbor()) {
891 const auto neighbor = intersection.outside();
892 const auto& intersectionGeometry = intersection.geometry();
895 const auto intersectionArea = intersectionGeometry.volume();
897 const auto beta = penalty() * intersectionArea / std::min(area, neighbor.geometry().volume());
900 modelNb.bind(neighbor);
901 if constexpr (!isAffineLinear) {
902 uLocalNb.bind(neighbor);
906 elementMatrixNb.init(neighbor, entity);
907 elementMatrixNb.clear();
909 if (intersection.conforming()) {
910 computeInteriorSkeletonContributions<true>(
911 gridPart, intersection, beta, uLocal, uLocalNb, model, modelNb,
912 elementMatrix, elementMatrixNb);
914 computeInteriorSkeletonContributions<false>(
915 gridPart, intersection, beta, uLocal, uLocalNb, model, modelNb,
916 elementMatrix, elementMatrixNb);
920 jOp.addLocalMatrix(neighbor, entity, elementMatrixNb);
922 if constexpr (!isAffineLinear) {
928 }
else if (intersection.boundary() && (hasRobin || hasSingular)) {
930 auto bdCond = model.classifyBoundary(intersection);
932 if (bdCond.first && !bdCond.second.all()) {
936 const auto quadOrder = 3*dfSpace.order();
937 BndryMassQuadratureType intersectionQuad(gridPart, intersection, quadOrder);
938 const auto& bndryQuad = intersectionQuad.inside();
939 const auto numQuadraturePoints = bndryQuad.nop();
941 for (
size_t pt = 0; pt < numQuadraturePoints; ++pt) {
945 const auto weight = bndryQuad.weight(pt);
949 auto normal = intersection.integrationOuterNormal(bndryQuad.localPoint(pt));
950 const auto integrationElement = normal.two_norm();
951 normal /= integrationElement;
955 baseSet.evaluateAll(bndryQuad[pt], phi_);
956 baseSet.jacobianAll(bndryQuad[pt], dphi_);
958 if constexpr (!isAffineLinear) {
960 uLocal.evaluate(bndryQuad[pt], u0);
961 uLocal.jacobian(bndryQuad[pt], Du0);
964 for (
size_t localCol = 0; localCol < numBaseFunctions; ++localCol) {
965 if constexpr (hasRobin && hasSingular) {
966 auto alphaphi = integrationElement * model.linearizedRobinFlux(u0, Du0, bndryQuad[pt], normal, phi_[localCol], dphi_[localCol]);
967 auto alphadphi = integrationElement * model.linearizedSingularFlux(u0, Du0, bndryQuad[pt], normal, phi_[localCol], dphi_[localCol]);
968 elementMatrix.column(localCol).axpy(phi_, dphi_, alphaphi, alphadphi, weight);
969 }
else if constexpr (hasRobin) {
970 auto alphaphi = integrationElement * model.linearizedRobinFlux(u0, Du0, bndryQuad[pt], normal, phi_[localCol], dphi_[localCol]);
971 elementMatrix.column(localCol).axpy(phi_, alphaphi, weight);
972 }
else if constexpr (hasSingular) {
973 auto alphadphi = integrationElement * model.linearizedSingularFlux(u0, Du0, bndryQuad[pt], normal, phi_[localCol], dphi_[localCol]);
974 elementMatrix.column(localCol).axpy(dphi_, alphadphi, weight);
983 jOp.addLocalMatrix(entity, entity, elementMatrix);
985 if constexpr (!isAffineLinear) {
992 releaseAssemblyStorage();
994 constraints().jacobian(u, jOp);
1003 template<
class JacobianOperator,
1004 class Model,
class Constraints,
1006 template<
bool conforming>
1007 void DifferentiableEllipticOperator<JacobianOperator, Model, Constraints, QuadratureTraits>
1008 ::computeInteriorSkeletonContributions(
1009 const GridPartType& gridPart,
1010 const IntersectionType& intersection,
1011 const RangeFieldType& penalty,
1012 const LocalDomainFunctionType& uLocal,
1013 const LocalDomainFunctionType& uLocalNb,
1014 const ModelClosure& model,
1015 const ModelClosure& modelNb,
1016 ElementMatrixType& elementMatrix,
1017 ElementMatrixType& elementMatrixNb)
const
1020 const auto quadOrder = (!isAffineLinear ? std::max(uLocal.order(), uLocalNb.order()) : 0) + elementMatrix.rangeSpace().order() + 1;
1021 IntersectionQuadrature<conforming> intersectionQuad(gridPart, intersection, quadOrder);
1022 const auto& quadInside = intersectionQuad.inside();
1023 const auto& quadOutside = intersectionQuad.outside();
1026 const auto& baseSetNb = elementMatrixNb.domainBasisFunctionSet();
1029 const auto& baseSet = elementMatrix.domainBasisFunctionSet();
1030 const auto numBaseFunctions = baseSet.size();
1034 JacobianRangeType Du0, Du0Nb;
1036 const auto numFaceQuadPoints = quadInside.nop();
1037 for (
size_t pt = 0; pt < numFaceQuadPoints; ++pt) {
1038 const auto& x = quadInside.localPoint(pt);
1039 auto normal = intersection.integrationOuterNormal(x);
1040 const auto faceVol = normal.two_norm();
1043 const auto quadWeight = quadInside.weight(pt);
1044 const auto weight = quadWeight * faceVol;
1046 if constexpr (!isAffineLinear) {
1047 uLocal.evaluate(quadInside[pt], u0);
1048 uLocal.jacobian(quadInside[pt], Du0);
1049 uLocalNb.evaluate(quadInside[pt], u0Nb);
1050 uLocalNb.jacobian(quadInside[pt], Du0Nb);
1057 baseSet.evaluateAll(quadInside[pt], phi_);
1058 baseSet.jacobianAll(quadInside[pt], dphi_);
1064 baseSetNb.evaluateAll(quadOutside[pt], phiNb_);
1065 baseSetNb.jacobianAll(quadOutside[pt], dphiNb_);
1067 for (
size_t i = 0; i < numBaseFunctions; ++i) {
1068 auto adphiEn = dphi_[i];
1069 auto adphiNb = dphiNb_[i];
1070 dphi_[i] = model.linearizedFlux(u0, Du0, quadInside[ pt ], phi_[i], adphiEn);
1071 dphiNb_[i] = modelNb.linearizedFlux(u0Nb, Du0Nb, quadOutside[ pt ], phiNb_[i], adphiNb);
1078 for (
size_t localCol = 0; localCol < numBaseFunctions; ++localCol) {
1079 RangeType valueEn(0), valueNb(0);
1080 JacobianRangeType dvalueEn(0), dvalueNb(0);
1083 dphi_[localCol].usmv(-0.5, normal, valueEn);
1086 dphiNb_[localCol].usmv(-0.5, normal, valueNb);
1089 valueEn.axpy(penalty, phi_[localCol]);
1091 valueNb.axpy(-penalty, phiNb_[localCol] );
1094 dvalueEn = -0.5 * sFormDG *
outer(phi_[localCol], normal);
1095 dvalueNb = 0.5 * sFormDG *
outer(phiNb_[localCol] , normal);
1097 for (
int r = 0; r< dimRange; ++r) {
1098 for (
int d = 0; d< dimDomain; ++d) {
1100 dvalueEn[r][d] = - 0.5 * sFormDG * phi_[localCol][r] * normal[d];
1103 dvalueNb[r][d] = 0.5 * sFormDG * phiNb_[localCol][r] * normal[d];
1108 elementMatrix.column(localCol).axpy(phi_, dphi_, valueEn, dvalueEn, weight);
1109 elementMatrixNb.column(localCol).axpy(phi_, dphi_, valueNb, dvalueNb, weight);
A class defining an elliptic operator.
Definition: ellipticoperator.hh:87
EllipticOperator(const ModelType &model, ConstraintsArg &&constraints)
Constructor including constraints.
Definition: ellipticoperator.hh:210
QuadratureTraitsType::FaceMassQuadratureType FaceMassQuadratureType
Use IntersectionQuadrature to create appropriate face quadratures.
Definition: ellipticoperator.hh:164
QuadratureTraitsType::template IntersectionMassQuadrature< true > BndryMassQuadratureType
Use IntersectionQuadrature to create appropriate face quadratures.
Definition: ellipticoperator.hh:178
QuadratureTraitsType::BulkMassQuadratureType MassQuadratureType
Use IntersectionQuadrature to create appropriate face quadratures.
Definition: ellipticoperator.hh:162
QuadratureTraitsType::FaceQuadratureType FaceQuadratureType
Use IntersectionQuadrature to create appropriate face quadratures.
Definition: ellipticoperator.hh:163
QuadratureTraitsType::BulkQuadratureType QuadratureType
Use IntersectionQuadrature to create appropriate face quadratures.
Definition: ellipticoperator.hh:161
QuadratureTraits< GridPartType > QuadratureTraitsType
Use IntersectionQuadrature to create appropriate face quadratures.
Definition: ellipticoperator.hh:160
EllipticOperator(const ModelType &model)
Constructor excluding constraints.
Definition: ellipticoperator.hh:225
typename QuadratureTraitsType::template IntersectionQuadrature< conforming > IntersectionQuadrature
Use IntersectionQuadrature to create appropriate face quadratures.
Definition: ellipticoperator.hh:168
IntersectionQuadrature< true > BndryQuadratureType
Definition: ellipticoperator.hh:177
virtual bool symmetric() const
linear operator interface
Definition: ellipticoperator.hh:246
RangeFunctionType DiscreteFunctionType
Alias for the range function type which is required to be a discrete function in order to provide sto...
Definition: ellipticoperator.hh:113
A class defining the "closure" type of all supported model-method and method-call-signatures.
Definition: modelfacade.hh:72
Empty do-nothing constraints.
DGFlavour
Definition: operatorselector.hh:24
virtual void operator()(const DomainFunctionType &u, RangeFunctionType &w) const
application operator, works "on the fly"
Definition: ellipticoperator.hh:448
auto outer(T1 &&t1, T2 &&t2)
Outer tensor product.
Definition: expressions.hh:138
constexpr auto contractInner(T1 &&t1, T2 &&t2, IndexConstant< N >=IndexConstant< N >{})
Contraction over the #N inner dimensions.
Definition: expressions.hh:118
DefaultQuadratureTraits< GridPart > QuadratureTraits
Traits class with ordinary quadratures in the bulk and on the skeleton.
Definition: quadrature.hh:132
Helper traits-class, defining likely quadrature types.
Definition: quadrature.hh:23
static const bool hasMassQuadrature
Set to true if BulkMassQuadratureType differs from BulkQuadratureType.
Definition: quadrature.hh:55
FaceQuadratureType FaceMassQuadratureType
The quadrature to use for integrating mass contributions over faces.
Definition: quadrature.hh:44
Fem::CachingQuadrature< GridPartType, 0 > BulkQuadratureType
The quadrature to use for integrating over bulk elements.
Definition: quadrature.hh:27
Fem::CachingQuadrature< GridPartType, 1 > FaceQuadratureType
The quadrature to use for integrating over faces.
Definition: quadrature.hh:30
BulkQuadratureType BulkMassQuadratureType
The quadrature to use for integrating mass contributions.
Definition: quadrature.hh:37
Default expression traits definition is a recursion in order to ease disambiguation.
Definition: expressiontraits.hh:54
Definition: operatorselector.hh:31