49    using Scalar = 
typename IV::Traits::MatVecTraits::FaceVector::value_type;
 
   53    using ParentType::ParentType;
 
   68    template< 
class DataHandle, 
class IV, 
class TensorFunc >
 
   69    void assembleMatrices(DataHandle& handle, IV& iv, 
const TensorFunc& getT, Scalar<IV> wijZeroThresh = 0.0)
 
   71        assembleLocalMatrices_(handle.A(), handle.AB(), handle.CA(), handle.T(), handle.omegas(), iv, getT, wijZeroThresh);
 
   74        if (iv.numUnknowns() > 0)
 
 
   86    template< 
class DataHandle, 
class IV, 
class GetU >
 
   87    void assembleU(DataHandle& handle, 
const IV& iv, 
const GetU& getU)
 
   89        auto& 
u = handle.uj();
 
   93        typename IV::Traits::IndexSet::LocalIndexType i = 0;
 
   94        for (; i < iv.numScvs(); i++)
 
   95            u[i] = getU( this->
elemVolVars()[iv.localScv(i).gridScvIndex()] );
 
   98        for (
const auto& data : iv.interiorBoundaryData())
 
  100            const auto& scvf = this->
fvGeometry().scvf(data.scvfIndex());
 
  101            const auto element = this->
fvGeometry().gridGeometry().element(scvf.insideScvIdx());
 
  102            u[i++] = getU( this->
problem().couplingManager().getLowDimVolVars(element, scvf) );
 
  106        for (
const auto& data : iv.dirichletData())
 
  107            u[i++] = getU( this->
elemVolVars()[data.volVarIndex()] );
 
 
  118    template< 
class DataHandle, 
class IV, 
class GetRho >
 
  121        using GridView = 
typename IV::Traits::GridView;
 
  122        static constexpr int dim = GridView::dimension;
 
  123        static constexpr int dimWorld = GridView::dimensionworld;
 
  124        static constexpr bool isSurfaceGrid = dim < dimWorld;
 
  127        auto& g = handle.g();
 
  128        auto& deltaG = handle.deltaG();
 
  129        auto& outsideG = handle.gOutside();
 
  139        using Scalar = 
typename IV::Traits::MatVecTraits::TMatrix::value_type;
 
  140        using LocalIndexType = 
typename IV::Traits::IndexSet::LocalIndexType;
 
  145        for (LocalIndexType faceIdx = 0; faceIdx < iv.numFaces(); ++faceIdx)
 
  148            const auto& curLocalScvf = iv.localScvf(faceIdx);
 
  149            const auto& curGlobalScvf = this->
fvGeometry().scvf(curLocalScvf.gridScvfIndex());
 
  150            const auto& gravity = this->
problem().spatialParams().gravity(curGlobalScvf.ipGlobal());
 
  151            const auto curIsInteriorBoundary = curLocalScvf.isOnInteriorBoundary();
 
  152            const Scalar curXiFactor = curIsInteriorBoundary ? (curGlobalScvf.boundary() ? 1.0 : xi) : 1.0;
 
  155            const auto& neighborScvIndices = curLocalScvf.neighboringLocalScvIndices();
 
  156            const auto& posGlobalScv = this->
fvGeometry().scv(iv.localScv(neighborScvIndices[0]).gridScvIndex());
 
  157            const auto& posVolVars = this->
elemVolVars()[posGlobalScv];
 
  158            const auto alpha_inside = posVolVars.extrusionFactor()*
vtmv(curGlobalScvf.unitOuterNormal(),
 
  159                                                                        posVolVars.permeability(),
 
  162            const auto numOutsideFaces = !curGlobalScvf.boundary() ? curGlobalScvf.numOutsideScvs() : 0;
 
  163            using OutsideAlphaStorage = std::conditional_t< isSurfaceGrid,
 
  165                                                            Dune::ReservedVector<Scalar, 1> >;
 
  166            OutsideAlphaStorage alpha_outside; alpha_outside.resize(numOutsideFaces);
 
  167            std::fill(alpha_outside.begin(), alpha_outside.end(), 0.0);
 
  170            if (isSurfaceGrid && !curIsInteriorBoundary)
 
  173            if (!curLocalScvf.isDirichlet())
 
  175                const auto localDofIdx = curLocalScvf.localDofIndex();
 
  176                const Scalar curOneMinusXi = curIsInteriorBoundary ?  -(1.0 - xi) : 1.0;
 
  178                rho = getRho(posVolVars);
 
  179                deltaG[localDofIdx] = 0.0;
 
  181                if (!curGlobalScvf.boundary())
 
  183                    for (
unsigned int idxInOutside = 0; idxInOutside < curGlobalScvf.numOutsideScvs(); ++idxInOutside)
 
  186                        const auto negLocalScvIdx = neighborScvIndices[idxInOutside+1];
 
  187                        const auto& negGlobalScv = this->
fvGeometry().scv(iv.localScv(negLocalScvIdx).gridScvIndex());
 
  188                        const auto& negVolVars = this->
elemVolVars()[negGlobalScv];
 
  189                        const auto& flipScvf = !isSurfaceGrid ? curGlobalScvf
 
  190                                                              : this->
fvGeometry().flipScvf(curGlobalScvf.index(), idxInOutside);
 
  192                        alpha_outside[idxInOutside] = negVolVars.extrusionFactor()*
vtmv(flipScvf.unitOuterNormal(),
 
  193                                                                                        negVolVars.permeability(),
 
  196                            alpha_outside[idxInOutside] *= -1.0;
 
  198                        if (!curIsInteriorBoundary)
 
  199                            rho += getRho(negVolVars);
 
  201                        deltaG[localDofIdx] += curOneMinusXi*alpha_outside[idxInOutside];
 
  205                if (curIsInteriorBoundary)
 
  207                    const auto posElement = this->
fvGeometry().gridGeometry().element(posGlobalScv.elementIndex());
 
  208                    const auto& facetVolVars = this->
problem().couplingManager().getLowDimVolVars(posElement, curGlobalScvf);
 
  209                    rho += getRho(facetVolVars);
 
  211                    const auto alphaFacet = posVolVars.extrusionFactor()*
vtmv(curGlobalScvf.unitOuterNormal(),
 
  212                                                                              facetVolVars.permeability(),
 
  214                    deltaG[localDofIdx] += alphaFacet;
 
  217                    rho /= numOutsideFaces + 1;
 
  219                deltaG[localDofIdx] -= curXiFactor*alpha_inside;
 
  220                deltaG[localDofIdx] *= rho*Extrusion::area(this->
fvGeometry(), curGlobalScvf);
 
  223            else if (curIsInteriorBoundary)
 
  225                const auto posElement = this->
fvGeometry().gridGeometry().element(posGlobalScv.elementIndex());
 
  226                const auto& facetVolVars = this->
problem().couplingManager().getLowDimVolVars(posElement, curGlobalScvf);
 
  227                rho = 0.5*(getRho(facetVolVars) + getRho(posVolVars));
 
  231                rho = getRho(this->
elemVolVars()[curGlobalScvf.outsideScvIdx()]);
 
  234            g[faceIdx] = alpha_inside*rho*Extrusion::area(this->
fvGeometry(), curGlobalScvf);
 
  236            if (isSurfaceGrid && !curIsInteriorBoundary)
 
  239                for (
const auto& alpha : alpha_outside)
 
  240                    outsideG[faceIdx][i++] = alpha*rho*Extrusion::area(this->
fvGeometry(), curGlobalScvf);
 
  245        handle.CA().umv(deltaG, g);
 
  248            using FaceVector = 
typename IV::Traits::MatVecTraits::FaceVector;
 
  251            handle.A().mv(deltaG, AG);
 
  254            for (
const auto& localFaceData : iv.localFaceData())
 
  257                if (!localFaceData.isOutsideFace())
 
  260                const auto localScvIdx = localFaceData.ivLocalInsideScvIndex();
 
  261                const auto localScvfIdx = localFaceData.ivLocalScvfIndex();
 
  262                const auto idxInOutside = localFaceData.scvfLocalOutsideScvfIndex();
 
  263                const auto& posLocalScv = iv.localScv(localScvIdx);
 
  264                const auto& wijk = handle.omegas()[localScvfIdx][idxInOutside+1];
 
  267                for (LocalIndexType localDir = 0; localDir < dim; localDir++)
 
  270                    const auto& curLocalScvf = iv.localScvf(posLocalScv.localScvfIndex(localDir));
 
  271                    if (!curLocalScvf.isDirichlet())
 
  272                        outsideG[localScvfIdx][idxInOutside] -= wijk[localDir]*AG[curLocalScvf.localDofIndex()];
 
 
  282    template< 
class IV, 
class TensorFunc >
 
  283    void assembleLocalMatrices_(
typename IV::Traits::MatVecTraits::AMatrix& A,
 
  284                                typename IV::Traits::MatVecTraits::BMatrix& B,
 
  285                                typename IV::Traits::MatVecTraits::CMatrix& C,
 
  286                                typename IV::Traits::MatVecTraits::DMatrix& D,
 
  287                                typename IV::Traits::MatVecTraits::OmegaStorage& wijk,
 
  288                                IV& iv, 
const TensorFunc& getT,
 
  289                                Scalar<IV> wijZeroThresh)
 
  291        using Scalar = 
typename IV::Traits::MatVecTraits::TMatrix::value_type;
 
  292        using LocalIndexType = 
typename IV::Traits::IndexSet::LocalIndexType;
 
  293        static constexpr int dim = IV::Traits::GridView::dimension;
 
  294        static constexpr int dimWorld = IV::Traits::GridView::dimensionworld;
 
  303            if (Dune::FloatCmp::ne(xi, 1.0, 1e-6))
 
  304                DUNE_THROW(Dune::InvalidStateException, 
"Xi != 1.0 cannot be used on surface grids");
 
  306        std::vector< std::pair<LocalIndexType, LocalIndexType> > faceMarkers;
 
  311        if (iv.numUnknowns() == 0)
 
  317            for (LocalIndexType faceIdx = 0; faceIdx < iv.numFaces(); ++faceIdx)
 
  319                const auto& curLocalScvf = iv.localScvf(faceIdx);
 
  320                const auto& curGlobalScvf = this->
fvGeometry().scvf(curLocalScvf.gridScvfIndex());
 
  321                const auto& neighborScvIndices = curLocalScvf.neighboringLocalScvIndices();
 
  324                const auto& posLocalScv = iv.localScv(neighborScvIndices[0]);
 
  325                const auto& posGlobalScv = this->
fvGeometry().scv(posLocalScv.gridScvIndex());
 
  326                const auto& posVolVars = this->
elemVolVars()[posGlobalScv];
 
  327                const auto tensor = getT(posVolVars);
 
  333                const auto posScvLocalDofIdx = posLocalScv.localDofIndex();
 
  334                for (LocalIndexType localDir = 0; localDir < dim; localDir++)
 
  336                    const auto& otherLocalScvf = iv.localScvf( posLocalScv.localScvfIndex(localDir) );
 
  337                    const auto otherLocalDofIdx = otherLocalScvf.localDofIndex();
 
  338                    D[faceIdx][otherLocalDofIdx] -= wijk[faceIdx][0][localDir];
 
  339                    D[faceIdx][posScvLocalDofIdx] += wijk[faceIdx][0][localDir];
 
  351            for (LocalIndexType faceIdx = 0; faceIdx < iv.numFaces(); ++faceIdx)
 
  353                const auto& curLocalScvf = iv.localScvf(faceIdx);
 
  354                const auto& curGlobalScvf = this->
fvGeometry().scvf(curLocalScvf.gridScvfIndex());
 
  355                const auto curIsDirichlet = curLocalScvf.isDirichlet();
 
  356                const auto curLocalDofIdx = curLocalScvf.localDofIndex();
 
  357                const auto curIsInteriorBoundary = curLocalScvf.isOnInteriorBoundary();
 
  358                const Scalar curXiFactor = curIsInteriorBoundary ? (curGlobalScvf.boundary() ? 1.0 : xi) : 1.0;
 
  361                const auto& neighborScvIndices = curLocalScvf.neighboringLocalScvIndices();
 
  362                const auto& posLocalScv = iv.localScv(neighborScvIndices[0]);
 
  363                const auto& posGlobalScv = this->
fvGeometry().scv(posLocalScv.gridScvIndex());
 
  364                const auto& posVolVars = this->
elemVolVars()[posGlobalScv];
 
  365                const auto& posElement = iv.element(neighborScvIndices[0]);
 
  366                const auto tensor = getT(posVolVars);
 
  373                bool isZeroWij = 
false;
 
  376                for (
unsigned int localDir = 0; localDir < dim; localDir++)
 
  378                    const auto& otherLocalScvf = iv.localScvf( posLocalScv.localScvfIndex(localDir) );
 
  379                    const auto otherLocalDofIdx = otherLocalScvf.localDofIndex();
 
  381                    if (otherLocalDofIdx == curLocalDofIdx)
 
  383                        if (abs(wijk[faceIdx][0][localDir]) <= wijZeroThresh)
 
  388                                faceMarkers.emplace_back( std::make_pair(curLocalDofIdx, faceIdx) );
 
  395                    if (!otherLocalScvf.isDirichlet())
 
  397                        C[faceIdx][otherLocalDofIdx] -= wijk[faceIdx][0][localDir];
 
  399                            A[curLocalDofIdx][otherLocalDofIdx] -= curXiFactor*wijk[faceIdx][0][localDir];
 
  404                        D[faceIdx][otherLocalDofIdx] -= wijk[faceIdx][0][localDir];
 
  406                            B[curLocalDofIdx][otherLocalDofIdx] += curXiFactor*wijk[faceIdx][0][localDir];
 
  410                    const auto posScvLocalDofIdx = posLocalScv.localDofIndex();
 
  411                    D[faceIdx][posScvLocalDofIdx] += wijk[faceIdx][0][localDir];
 
  414                        B[curLocalDofIdx][posScvLocalDofIdx] -= curXiFactor*wijk[faceIdx][0][localDir];
 
  418                if (curIsInteriorBoundary && !curIsDirichlet)
 
  420                    const auto facetVolVars = this->
problem().couplingManager().getLowDimVolVars(posElement, curGlobalScvf);
 
  421                    const auto facetTensor = getT(facetVolVars);
 
  425                    const auto wFacet = 2.0*Extrusion::area(this->
fvGeometry(), curGlobalScvf)*posVolVars.extrusionFactor()
 
  426                                           *
vtmv(curGlobalScvf.unitOuterNormal(), facetTensor, curGlobalScvf.unitOuterNormal())
 
  427                                           / (dim < dimWorld ? sqrt(facetVolVars.extrusionFactor()) : facetVolVars.extrusionFactor());
 
  429                    A[curLocalDofIdx][curLocalDofIdx] -= wFacet;
 
  430                    B[curLocalDofIdx][curLocalScvf.coupledFacetLocalDofIndex()] -= wFacet;
 
  433                    if (!isZeroWij && abs(wFacet) <= wijZeroThresh)
 
  436                        faceMarkers.emplace_back( std::make_pair(curLocalDofIdx, faceIdx) );
 
  441                if (!curGlobalScvf.boundary() && !curIsDirichlet)
 
  444                    const Scalar curOneMinusXi = curIsInteriorBoundary ?  -(1.0 - xi) : 1.0;
 
  447                    for (
unsigned int idxInOutside = 0; idxInOutside < curGlobalScvf.numOutsideScvs(); ++idxInOutside)
 
  449                        const auto idxOnScvf = idxInOutside+1;
 
  450                        const auto& negLocalScv = iv.localScv( neighborScvIndices[idxOnScvf] );
 
  451                        const auto& negGlobalScv = this->
fvGeometry().scv(negLocalScv.gridScvIndex());
 
  452                        const auto& negVolVars = this->
elemVolVars()[negGlobalScv];
 
  453                        const auto negTensor = getT(negVolVars);
 
  456                        const auto& scvf = dim < dimWorld ? this->
fvGeometry().flipScvf(curGlobalScvf.index(), idxInOutside)
 
  462                            wijk[faceIdx][idxOnScvf] *= -1.0;
 
  465                        for (
int localDir = 0; localDir < dim; localDir++)
 
  467                            const auto otherLocalScvfIdx = negLocalScv.localScvfIndex(localDir);
 
  468                            const auto& otherLocalScvf = iv.localScvf(otherLocalScvfIdx);
 
  469                            const auto otherLocalDofIdx = otherLocalScvf.localDofIndex();
 
  472                            if (otherLocalDofIdx == curLocalDofIdx && !isZeroWij)
 
  473                                if (abs(wijk[faceIdx][idxOnScvf][localDir]) <= wijZeroThresh)
 
  474                                    faceMarkers.emplace_back( std::make_pair(curLocalDofIdx, faceIdx) );
 
  476                            if (!otherLocalScvf.isDirichlet())
 
  477                                A[curLocalDofIdx][otherLocalDofIdx] += curOneMinusXi*wijk[faceIdx][idxOnScvf][localDir];
 
  479                                B[curLocalDofIdx][otherLocalDofIdx] -= curOneMinusXi*wijk[faceIdx][idxOnScvf][localDir];
 
  482                            B[curLocalDofIdx][negLocalScv.localDofIndex()] += curOneMinusXi*wijk[faceIdx][idxOnScvf][localDir];