diff --git a/dumux/discretization/staggered/stencils.hh b/dumux/discretization/staggered/stencils.hh index f8a0f42a3bb8c381e2d4efba28684b3294e31b6b..0cc0b8aaf7d20d0c12468c5c57cf4c9caa068fc8 100644 --- a/dumux/discretization/staggered/stencils.hh +++ b/dumux/discretization/staggered/stencils.hh @@ -50,43 +50,50 @@ public: const Element& element, const FVElementGeometry& fvGeometry) { - elementStencil_.clear(); + + const auto globalI = problem.elementMapper().index(element); + + cellCenterToCellCenterStencil_.clear(); + cellCenterToFaceStencil_.clear(); + + // the cell center dof indices + cellCenterToCellCenterStencil_.push_back(globalI); // loop over sub control faces for (auto&& scvf : scvfs(fvGeometry)) { - FluxVariables fluxVars; - const auto& centerStencil = fluxVars.computeCellCenterStencil(problem, element, fvGeometry, scvf); - elementStencil_.insert(elementStencil_.end(), centerStencil.begin(), centerStencil.end()); + if (!scvf.boundary()) + cellCenterToCellCenterStencil_.push_back(scvf.outsideScvIdx()); + + cellCenterToFaceStencil_.push_back(scvf.dofIndexSelf()); } - // make values in elementstencil unique - std::sort(elementStencil_.begin(), elementStencil_.end()); - elementStencil_.erase(std::unique(elementStencil_.begin(), elementStencil_.end()), elementStencil_.end()); - auto globalI = problem.elementMapper().index(element); - neighborStencil_ = elementStencil_; + // make values unique + std::sort(cellCenterToCellCenterStencil_.begin(), cellCenterToCellCenterStencil_.end()); + cellCenterToCellCenterStencil_.erase(std::unique(cellCenterToCellCenterStencil_.begin(), cellCenterToCellCenterStencil_.end()), cellCenterToCellCenterStencil_.end()); - // remove the element itself and possible ghost neighbors from the neighbor stencil - neighborStencil_.erase(std::remove_if(neighborStencil_.begin(), neighborStencil_.end(), - [globalI](int i){ return (i == globalI); }), - neighborStencil_.end()); + std::sort(cellCenterToFaceStencil_.begin(), cellCenterToFaceStencil_.end()); + cellCenterToFaceStencil_.erase(std::unique(cellCenterToFaceStencil_.begin(), cellCenterToFaceStencil_.end()), cellCenterToFaceStencil_.end()); } + //! The full element stencil (all element this element is interacting with) - const Stencil& elementStencil() const + const Stencil& cellCenterToCellCenterStencil() const { - return elementStencil_; + return cellCenterToCellCenterStencil_; } - //! The full element stencil without this element - const Stencil& neighborStencil() const + //! The full element stencil (all element this element is interacting with) + const Stencil& cellCenterToFaceStencil() const { - return neighborStencil_; + return cellCenterToFaceStencil_; } + + private: - Stencil elementStencil_; - Stencil neighborStencil_; + Stencil cellCenterToCellCenterStencil_; + Stencil cellCenterToFaceStencil_; }; template<class TypeTag> @@ -106,23 +113,45 @@ public: void update(const Problem& problem, const SubControlVolumeFace& scvf) { - faceStencil_.clear(); - FluxVariables fluxVars; + faceToCellCenterStencil_.clear(); + faceToFaceStencil_.clear(); + + faceToCellCenterStencil_.push_back(scvf.insideScvIdx()); - const auto& faceStencil = fluxVars.computeFaceStencil(problem, scvf); - faceStencil_.insert(faceStencil_.end(), faceStencil.begin(), faceStencil.end()); - std::sort(faceStencil_.begin(), faceStencil_.end()); - faceStencil_.erase(std::unique(faceStencil_.begin(), faceStencil_.end()), faceStencil_.end()); + faceToFaceStencil_.push_back(scvf.dofIndexSelf()); + faceToFaceStencil_.push_back(scvf.dofIndexOpposite()); + + for(const auto& data : scvf.pairData()) + { + const auto& outerParallelElementDofIdx = data.outerParallelElementDofIdx; + const auto& outerParallelFaceDofIdx = data.outerParallelFaceDofIdx; + if(outerParallelElementDofIdx >= 0) + faceToCellCenterStencil_.push_back(outerParallelElementDofIdx); + if(outerParallelFaceDofIdx >= 0) + faceToFaceStencil_.push_back(outerParallelFaceDofIdx); + + faceToFaceStencil_.push_back(data.normalPair.first); + if(!scvf.boundary()) + faceToFaceStencil_.push_back(data.normalPair.second); + } + + } + + //! The full face stencil (all dofs this face is interacting with) + const Stencil& faceToCellCenterStencil() const + { + return faceToCellCenterStencil_; } //! The full face stencil (all dofs this face is interacting with) - const Stencil& faceStencil() const + const Stencil& faceToFaceStencil() const { - return faceStencil_; + return faceToFaceStencil_; } private: - Stencil faceStencil_; + Stencil faceToCellCenterStencil_; + Stencil faceToFaceStencil_; }; @@ -150,11 +179,13 @@ public: const IndexType numElements = problem.gridView().size(0); const IndexType numFacets = problem.gridView().size(1); const IndexType numBoundaryFacets = problem.gridView().grid().numBoundarySegments(); - elementStencils_.resize(numElements); + cellCenterStencils_.resize(numElements); faceStencils_.resize(2*numFacets - numBoundaryFacets); - std::vector<Stencil> fullFaceStencils; - fullFaceStencils.resize(numFacets); + std::vector<Stencil> fullFaceToCellCenterStencils; + fullFaceToCellCenterStencils.resize(numFacets); + std::vector<Stencil> fullfaceToFaceStencils; + fullfaceToFaceStencils.resize(numFacets); for (const auto& element : elements(problem.gridView())) { @@ -162,7 +193,7 @@ public: // restrict the FvGeometry locally and bind to the element auto fvGeometry = localView(problem.model().globalFvGeometry()); fvGeometry.bindElement(element); // for TPFA bind element is enough - elementStencils_[eIdx].update(problem, element, fvGeometry); + cellCenterStencils_[eIdx].update(problem, element, fvGeometry); // loop over sub control faces for (auto&& scvf : scvfs(fvGeometry)) @@ -170,21 +201,28 @@ public: faceStencils_[scvf.index()].update(problem, scvf); const IndexType idx = scvf.dofIndexSelf() - numElements; - const auto& faceStencil = faceStencils_[scvf.index()].faceStencil(); - fullFaceStencils[idx].insert(fullFaceStencils[idx].end(), faceStencil.begin(), faceStencil.end()); - std::sort(fullFaceStencils[idx].begin(), fullFaceStencils[idx].end()); - fullFaceStencils[idx].erase(std::unique(fullFaceStencils[idx].begin(), fullFaceStencils[idx].end()), fullFaceStencils[idx].end()); + + const auto& faceToCellCenterStencil = faceStencils_[scvf.index()].faceToCellCenterStencil(); + fullFaceToCellCenterStencils[idx].insert(fullFaceToCellCenterStencils[idx].end(), faceToCellCenterStencil.begin(), faceToCellCenterStencil.end()); + std::sort(fullFaceToCellCenterStencils[idx].begin(), fullFaceToCellCenterStencils[idx].end()); + fullFaceToCellCenterStencils[idx].erase(std::unique(fullFaceToCellCenterStencils[idx].begin(), fullFaceToCellCenterStencils[idx].end()), fullFaceToCellCenterStencils[idx].end()); + + const auto& faceToFaceStencil = faceStencils_[scvf.index()].faceToFaceStencil(); + fullfaceToFaceStencils[idx].insert(fullfaceToFaceStencils[idx].end(), faceToFaceStencil.begin(), faceToFaceStencil.end()); + std::sort(fullfaceToFaceStencils[idx].begin(), fullfaceToFaceStencils[idx].end()); + fullfaceToFaceStencils[idx].erase(std::unique(fullfaceToFaceStencils[idx].begin(), fullfaceToFaceStencils[idx].end()), fullfaceToFaceStencils[idx].end()); } } // TODO: is this a good idea? - fullFaceDofStencils_ = std::make_unique<decltype(fullFaceStencils)>(fullFaceStencils); + fullFaceToCellCenterStencils_ = std::make_unique<decltype(fullFaceToCellCenterStencils)>(fullFaceToCellCenterStencils); + fullfaceToFaceStencils_ = std::make_unique<decltype(fullfaceToFaceStencils)>(fullfaceToFaceStencils); } //! overload for elements auto& get(const Element& entity) const { - return elementStencils_[problemPtr_->elementMapper().index(entity)]; + return cellCenterStencils_[problemPtr_->elementMapper().index(entity)]; } //! overload for faces @@ -197,28 +235,49 @@ public: /*! * \brief Returns the size of a complete face dof stencil */ - size_t completeFaceDofStencilSize(const int idx) const + size_t fullFaceToCellCenterStencilSize(const int idx) const + { +// const IndexType numElements = problemPtr_->gridView().size(0); + assert(fullFaceToCellCenterStencils_ && "fullFaceToCellCenterStencils_ has already been called and deleted!"); + return fullFaceToCellCenterStencils_.get()[0][idx/*-numElements*/].size(); + // TODO: why does this not work? + } + + /*! + * \brief Returns the size of a complete face dof stencil + */ + size_t fullfaceToFaceStencilSize(const int idx) const { // const IndexType numElements = problemPtr_->gridView().size(0); - assert(fullFaceDofStencils_ && "fullFaceDofStencils_ has already been called and deleted!"); - return fullFaceDofStencils_.get()[0][idx/*-numElements*/].size(); + assert(fullfaceToFaceStencils_ && "fullfaceToFaceStencils_ has already been called and deleted!"); + return fullfaceToFaceStencils_.get()[0][idx/*-numElements*/].size(); // TODO: why does this not work? } /*! * \brief Returns a unique pointer to the complete face dof stencils which is used once for setting up the global matrix and deleted afterwards */ - auto getFullFaceDofStencilsPtr() + auto getFullFaceToCellCenterStencilsPtr() + { + assert(fullFaceToCellCenterStencils_ && "fullFaceToCellCenterStencils_ has already been used and deleted!"); + return std::move(fullFaceToCellCenterStencils_); + } + + /*! + * \brief Returns a unique pointer to the complete face dof stencils which is used once for setting up the global matrix and deleted afterwards + */ + auto getFullfaceToFaceStencilsPtr() { - assert(fullFaceDofStencils_ && "fullFaceDofStencils_ has already been used and deleted!"); - return std::move(fullFaceDofStencils_); + assert(fullfaceToFaceStencils_ && "fullfaceToFaceStencils_ has already been used and deleted!"); + return std::move(fullfaceToFaceStencils_); } private: - std::vector<StaggeredCellCenterStencils<TypeTag>> elementStencils_; + std::vector<StaggeredCellCenterStencils<TypeTag>> cellCenterStencils_; std::vector<StaggeredFaceStencils<TypeTag>> faceStencils_; - std::unique_ptr<std::vector<Stencil>> fullFaceDofStencils_; + std::unique_ptr<std::vector<Stencil>> fullFaceToCellCenterStencils_; + std::unique_ptr<std::vector<Stencil>> fullfaceToFaceStencils_; const Problem* problemPtr_; diff --git a/dumux/freeflow/staggered/model.hh b/dumux/freeflow/staggered/model.hh index 179c17bab9cf254bfe0ef4b10bfb08c6e0ffbcd3..08ef270ff2b222e8f21f18f2655fbdeac3503700 100644 --- a/dumux/freeflow/staggered/model.hh +++ b/dumux/freeflow/staggered/model.hh @@ -143,17 +143,33 @@ public: /*! * \brief Returns the size of a complete face dof stencil */ - size_t completeFaceDofStencilSize(const int idx) const + size_t fullFaceToCellCenterStencilSize(const int idx) const { - return this->stencilsVector_.completeFaceDofStencilSize(idx); + return this->stencilsVector_.fullFaceToCellCenterStencilSize(idx); + } + + /*! + * \brief Returns the size of a complete face dof stencil + */ + size_t fullfaceToFaceStencilSize(const int idx) const + { + return this->stencilsVector_.fullfaceToFaceStencilSize(idx); + } + + /*! + * \brief Returns a unique pointer to the complete face dof stencils which is used once for setting up the global matrix and deleted afterwards + */ + auto getFullFaceToCellCenterStencilsPtr() + { + return this->stencilsVector_.getFullFaceToCellCenterStencilsPtr(); } /*! * \brief Returns a unique pointer to the complete face dof stencils which is used once for setting up the global matrix and deleted afterwards */ - auto getFullFaceDofStencilsPtr() + auto getFullfaceToFaceStencilsPtr() { - return this->stencilsVector_.getFullFaceDofStencilsPtr(); + return this->stencilsVector_.getFullfaceToFaceStencilsPtr(); } }; diff --git a/dumux/implicit/staggered/assembler.hh b/dumux/implicit/staggered/assembler.hh index af0a097e5f5ab0c7e7a344038dc7d290dba51154..3d9689cbcc76022a1038d15a9a0f5a8ad836086a 100644 --- a/dumux/implicit/staggered/assembler.hh +++ b/dumux/implicit/staggered/assembler.hh @@ -50,15 +50,18 @@ class StaggeredAssembler : public ImplicitAssembler<TypeTag> { // the global index of the element at hand const auto globalI = this->elementMapper_().index(element); - const auto& stencil = this->model_().stencils(element).elementStencil(); + const auto& cellCenterToCellCenterStencil = this->model_().stencils(element).cellCenterToCellCenterStencil(); + const auto& cellCenterToFaceStencil = this->model_().stencils(element).cellCenterToFaceStencil(); + const auto size = cellCenterToCellCenterStencil.size() + cellCenterToFaceStencil.size(); - this->matrix().setrowsize(globalI, stencil.size()); + this->matrix().setrowsize(globalI, size); } for(int facetIdx = 0; facetIdx < this->gridView_().size(1); ++facetIdx) { const int faceDofxIdx = facetIdx + this->gridView_().size(0); - const int size = this->model_().completeFaceDofStencilSize(facetIdx); + auto size = this->model_().fullFaceToCellCenterStencilSize(facetIdx); + size += this->model_().fullfaceToFaceStencilSize(facetIdx); this->matrix().setrowsize(faceDofxIdx, size); } this->matrix().endrowsizes(); @@ -70,22 +73,34 @@ class StaggeredAssembler : public ImplicitAssembler<TypeTag> { // the global index of the element at hand const auto globalI = this->elementMapper_().index(element); - const auto& stencil = this->model_().stencils(element).elementStencil(); + const auto& cellCenterToCellCenterStencil = this->model_().stencils(element).cellCenterToCellCenterStencil(); + const auto& cellCenterToFaceStencil = this->model_().stencils(element).cellCenterToFaceStencil(); - for (auto&& globalJ : stencil) + for (auto&& globalJ : cellCenterToCellCenterStencil) + this->matrix().addindex(globalI, globalJ); + for (auto&& globalJ : cellCenterToFaceStencil) this->matrix().addindex(globalI, globalJ); } - auto ptr = this->model_().getFullFaceDofStencilsPtr(); + auto ptr1 = this->model_().getFullFaceToCellCenterStencilsPtr(); + auto ptr2 = this->model_().getFullfaceToFaceStencilsPtr(); - if(ptr) + if(ptr1 && ptr2) std::cout << "success!!!" << std::endl; - const auto& fullFaceDofStencils = ptr.get()[0]; + const auto& fullFaceToCellCenterStencils = ptr1.get()[0]; + const auto& fullfaceToFaceStencils = ptr2.get()[0]; int globalI = this->gridView_().size(0); - for(const auto& stencil : fullFaceDofStencils) + for(const auto& stencil : fullFaceToCellCenterStencils) + { + for(auto&& globalJ : stencil) + this->matrix().addindex(globalI, globalJ); + ++globalI; + } + globalI = this->gridView_().size(0); + for(const auto& stencil : fullfaceToFaceStencils) { for(auto&& globalJ : stencil) this->matrix().addindex(globalI, globalJ); diff --git a/dumux/implicit/staggered/localjacobian.hh b/dumux/implicit/staggered/localjacobian.hh index 719964d6996d46f36c3196872245a872267bb871..0059b955c2fa60c7694d319bf26c58cb806334fe 100644 --- a/dumux/implicit/staggered/localjacobian.hh +++ b/dumux/implicit/staggered/localjacobian.hh @@ -190,157 +190,157 @@ private: const bool isGhost) { // get stencil informations - const auto& neighborStencil = this->model_().stencils(element).neighborStencil(); - const auto numNeighbors = neighborStencil.size(); +// const auto& neighborStencil = this->model_().stencils(element).neighborStencil(); +// const auto numNeighbors = neighborStencil.size(); // the localresidual class used for the flux calculations - LocalResidual localRes; - localRes.init(this->problem_()); - - // container to store the neighboring elements - std::vector<Element> neighborElements; - neighborElements.reserve(numNeighbors); - - // get the elements and calculate the flux into the element in the undeflected state - Dune::BlockVector<PrimaryVariables> origFlux(numNeighbors); - origFlux = 0.0; - - unsigned int j = 0; - for (auto globalJ : neighborStencil) - { - auto elementJ = fvGeometry.globalFvGeometry().element(globalJ); - neighborElements.push_back(elementJ); - - for (auto fluxVarIdx : assemblyMap_[globalI_][j]) - { - auto&& scvf = fvGeometry.scvf(fluxVarIdx); - origFlux[j] += localRes.evalFlux_(elementJ, fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); - } - - ++j; - } - - auto&& scv = fvGeometry.scv(globalI_); - auto& curVolVars = getCurVolVars(curElemVolVars, scv); - // save a copy of the original vol vars - VolumeVariables origVolVars(curVolVars); - - // derivatives in the neighbors with repect to the current elements - Dune::BlockVector<PrimaryVariables> neighborDeriv(numNeighbors); - for (int pvIdx = 0; pvIdx < numEq; pvIdx++) - { - // derivatives of element dof with respect to itself - PrimaryVariables partialDeriv(0.0); - - if (isGhost) - partialDeriv[pvIdx] = 1.0; - - neighborDeriv = 0.0; - PrimaryVariables priVars(this->model_().curSol()[globalI_]); - - Scalar eps = this->numericEpsilon(scv, curVolVars, pvIdx); - Scalar delta = 0; - - if (numericDifferenceMethod_ >= 0) - { - // we are not using backward differences, i.e. we need to - // calculate f(x + \epsilon) - - // deflect primary variables - priVars[pvIdx] += eps; - delta += eps; - - // update the volume variables and bind the flux var cache again - curVolVars.update(priVars, this->problem_(), element, scv); - elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars); - - if (!isGhost) - { - // calculate the residual with the deflected primary variables - this->localResidual().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, elemBcTypes, elemFluxVarsCache); - - // store the residual and the storage term - partialDeriv = this->localResidual().residual(0); - } - - // calculate the fluxes into element with the deflected primary variables - for (std::size_t k = 0; k < numNeighbors; ++k) - { - for (auto fluxVarIdx : assemblyMap_[globalI_][k]) - { - auto&& scvf = fvGeometry.scvf(fluxVarIdx); - neighborDeriv[k] += localRes.evalFlux_(neighborElements[k], fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); - } - } - } - else - { - // we are using backward differences, i.e. we don't need - // to calculate f(x + \epsilon) and we can recycle the - // (already calculated) residual f(x) - if (!isGhost) - partialDeriv = this->residual(0); - neighborDeriv = origFlux; - } - - if (numericDifferenceMethod_ <= 0) - { - // we are not using forward differences, i.e. we - // need to calculate f(x - \epsilon) - - // deflect the primary variables - priVars[pvIdx] -= delta + eps; - delta += eps; - - // update the volume variables and bind the flux var cache again - curVolVars.update(priVars, this->problem_(), element, scv); - elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars); - - if (!isGhost) - { - // calculate the residual with the deflected primary variables - this->localResidual().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, elemBcTypes, elemFluxVarsCache); - - // subtract the residual from the derivative storage - partialDeriv -= this->localResidual().residual(0); - } - - // calculate the fluxes into element with the deflected primary variables - for (std::size_t k = 0; k < numNeighbors; ++k) - { - for (auto fluxVarIdx : assemblyMap_[globalI_][k]) - { - auto&& scvf = fvGeometry.scvf(fluxVarIdx); - neighborDeriv[k] -= localRes.evalFlux_(neighborElements[k], fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); - } - } - } - else - { - // we are using forward differences, i.e. we don't need to - // calculate f(x - \epsilon) and we can recycle the - // (already calculated) residual f(x) - if (!isGhost) - partialDeriv -= this->residual(0); - neighborDeriv -= origFlux; - } - - // divide difference in residuals by the magnitude of the - // deflections between the two function evaluation - if (!isGhost) - partialDeriv /= delta; - neighborDeriv /= delta; - - // restore the original state of the scv's volume variables - curVolVars = origVolVars; - - // update the global jacobian matrix with the current partial derivatives - this->updateGlobalJacobian_(matrix, globalI_, globalI_, pvIdx, partialDeriv); - - j = 0; - for (auto globalJ : neighborStencil) - this->updateGlobalJacobian_(matrix, globalJ, globalI_, pvIdx, neighborDeriv[j++]); - } +// LocalResidual localRes; +// localRes.init(this->problem_()); +// +// // container to store the neighboring elements +// std::vector<Element> neighborElements; +// // neighborElements.reserve(numNeighbors); +// +// // get the elements and calculate the flux into the element in the undeflected state +// Dune::BlockVector<PrimaryVariables> origFlux(numNeighbors); +// origFlux = 0.0; +// +// unsigned int j = 0; +// for (auto globalJ : neighborStencil) +// { +// auto elementJ = fvGeometry.globalFvGeometry().element(globalJ); +// neighborElements.push_back(elementJ); +// +// for (auto fluxVarIdx : assemblyMap_[globalI_][j]) +// { +// auto&& scvf = fvGeometry.scvf(fluxVarIdx); +// origFlux[j] += localRes.evalFlux_(elementJ, fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); +// } +// +// ++j; +// } +// +// auto&& scv = fvGeometry.scv(globalI_); +// auto& curVolVars = getCurVolVars(curElemVolVars, scv); +// // save a copy of the original vol vars +// VolumeVariables origVolVars(curVolVars); +// +// // derivatives in the neighbors with repect to the current elements +// Dune::BlockVector<PrimaryVariables> neighborDeriv(numNeighbors); +// for (int pvIdx = 0; pvIdx < numEq; pvIdx++) +// { +// // derivatives of element dof with respect to itself +// PrimaryVariables partialDeriv(0.0); +// +// if (isGhost) +// partialDeriv[pvIdx] = 1.0; +// +// neighborDeriv = 0.0; +// PrimaryVariables priVars(this->model_().curSol()[globalI_]); +// +// Scalar eps = this->numericEpsilon(scv, curVolVars, pvIdx); +// Scalar delta = 0; +// +// if (numericDifferenceMethod_ >= 0) +// { +// // we are not using backward differences, i.e. we need to +// // calculate f(x + \epsilon) +// +// // deflect primary variables +// priVars[pvIdx] += eps; +// delta += eps; +// +// // update the volume variables and bind the flux var cache again +// curVolVars.update(priVars, this->problem_(), element, scv); +// elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars); +// +// if (!isGhost) +// { +// // calculate the residual with the deflected primary variables +// this->localResidual().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, elemBcTypes, elemFluxVarsCache); +// +// // store the residual and the storage term +// partialDeriv = this->localResidual().residual(0); +// } +// +// // calculate the fluxes into element with the deflected primary variables +// for (std::size_t k = 0; k < numNeighbors; ++k) +// { +// for (auto fluxVarIdx : assemblyMap_[globalI_][k]) +// { +// auto&& scvf = fvGeometry.scvf(fluxVarIdx); +// neighborDeriv[k] += localRes.evalFlux_(neighborElements[k], fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); +// } +// } +// } +// else +// { +// // we are using backward differences, i.e. we don't need +// // to calculate f(x + \epsilon) and we can recycle the +// // (already calculated) residual f(x) +// if (!isGhost) +// partialDeriv = this->residual(0); +// neighborDeriv = origFlux; +// } +// +// if (numericDifferenceMethod_ <= 0) +// { +// // we are not using forward differences, i.e. we +// // need to calculate f(x - \epsilon) +// +// // deflect the primary variables +// priVars[pvIdx] -= delta + eps; +// delta += eps; +// +// // update the volume variables and bind the flux var cache again +// curVolVars.update(priVars, this->problem_(), element, scv); +// elemFluxVarsCache.bind(element, fvGeometry, curElemVolVars); +// +// if (!isGhost) +// { +// // calculate the residual with the deflected primary variables +// this->localResidual().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, elemBcTypes, elemFluxVarsCache); +// +// // subtract the residual from the derivative storage +// partialDeriv -= this->localResidual().residual(0); +// } +// +// // calculate the fluxes into element with the deflected primary variables +// for (std::size_t k = 0; k < numNeighbors; ++k) +// { +// for (auto fluxVarIdx : assemblyMap_[globalI_][k]) +// { +// auto&& scvf = fvGeometry.scvf(fluxVarIdx); +// neighborDeriv[k] -= localRes.evalFlux_(neighborElements[k], fvGeometry, curElemVolVars, scvf, elemFluxVarsCache[scvf]); +// } +// } +// } +// else +// { +// // we are using forward differences, i.e. we don't need to +// // calculate f(x - \epsilon) and we can recycle the +// // (already calculated) residual f(x) +// if (!isGhost) +// partialDeriv -= this->residual(0); +// neighborDeriv -= origFlux; +// } +// +// // divide difference in residuals by the magnitude of the +// // deflections between the two function evaluation +// if (!isGhost) +// partialDeriv /= delta; +// neighborDeriv /= delta; +// +// // restore the original state of the scv's volume variables +// curVolVars = origVolVars; +// +// // update the global jacobian matrix with the current partial derivatives +// this->updateGlobalJacobian_(matrix, globalI_, globalI_, pvIdx, partialDeriv); +// +// j = 0; +// for (auto globalJ : neighborStencil) +// this->updateGlobalJacobian_(matrix, globalJ, globalI_, pvIdx, neighborDeriv[j++]); +// } } //! If the global vol vars caching is enabled we have to modify the global volvar object