diff --git a/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh b/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh index 557b70dad7da825c71ab7501130d3f6c60dec7b1..1d0a9f19c829b3a1243924fbaec1046e23561144 100644 --- a/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh +++ b/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh @@ -222,22 +222,7 @@ public: //! Note that e.g. the normals might be different in the case of surface grids const SubControlVolumeFace& flipScvf(GridIndexType scvfIdx, unsigned int outsideScvIdx = 0) const { - auto it = std::find(scvfIndices_.begin(), scvfIndices_.end(), scvfIdx); - if (it != scvfIndices_.end()) - { - const auto localScvfIdx = std::distance(scvfIndices_.begin(), it); - return neighborScvfs_[flipScvfIndices_[localScvfIdx][outsideScvIdx]]; - } - else - { - const auto neighborScvfIdxLocal = findLocalIndex(scvfIdx, neighborScvfIndices_); - const auto& scvf = neighborScvfs_[neighborScvfIdxLocal]; - - if (scvf.outsideScvIdx(outsideScvIdx) == scvIndices_[0]) - return scvfs_[neighborFlipScvfIndices_[neighborScvfIdxLocal][outsideScvIdx]]; - else - return neighborScvfs_[neighborFlipScvfIndices_[neighborScvfIdxLocal][outsideScvIdx]]; - } + return scvf( fvGridGeometry().flipScvfIdx(scvfIdx, outsideScvIdx) ); } //! iterator range for sub control volumes. Iterates over @@ -299,10 +284,6 @@ public: dataJ.scvfsJ, dataJ.additionalScvfs); - // set up the scvf flip indices for network grids - if (dim < dimWorld) - makeFlipIndexSet(); - // //! TODO Check if user added additional DOF dependencies, i.e. the residual of DOF globalI depends // //! on additional DOFs not included in the discretization schemes' occupation pattern // const auto& additionalDofDependencies = problem.getAdditionalDofDependencies(globalI); @@ -524,98 +505,6 @@ private: } } - //! find the "flip" indices for all scvfs - void makeFlipIndexSet() - { - const auto numInsideScvfs = scvfIndices_.size(); - const auto numNeighborScvfs = neighborScvfIndices_.size(); - - // first, handle the interior scvfs (flip scvf will be in outside scvfs) - flipScvfIndices_.resize(numInsideScvfs); - for (unsigned int insideFace = 0; insideFace < numInsideScvfs; ++insideFace) - { - const auto& scvf = scvfs_[insideFace]; - if (scvf.boundary()) - continue; - - const auto numOutsideScvs = scvf.numOutsideScvs(); - const auto vIdxGlobal = scvf.vertexIndex(); - const auto insideScvIdx = scvf.insideScvIdx(); - - flipScvfIndices_[insideFace].resize(numOutsideScvs); - for (unsigned int nIdx = 0; nIdx < numOutsideScvs; ++nIdx) - { - const auto outsideScvIdx = scvf.outsideScvIdx(nIdx); - for (unsigned int outsideFace = 0; outsideFace < numNeighborScvfs; ++outsideFace) - { - const auto& outsideScvf = neighborScvfs_[outsideFace]; - // check if outside face is the flip face - if (outsideScvf.insideScvIdx() == outsideScvIdx && - outsideScvf.vertexIndex() == vIdxGlobal && - MpfaHelper::vectorContainsValue(outsideScvf.outsideScvIndices(), insideScvIdx)) - { - flipScvfIndices_[insideFace][nIdx] = outsideFace; - // there is always only one flip face in an outside element - break; - } - } - } - } - - // Now we look for the flip indices of the outside faces - neighborFlipScvfIndices_.resize(numNeighborScvfs); - for (unsigned int outsideFace = 0; outsideFace < numNeighborScvfs; ++outsideFace) - { - const auto& scvf = neighborScvfs_[outsideFace]; - if (scvf.boundary()) - continue; - - const auto numOutsideScvs = scvf.numOutsideScvs(); - const auto vIdxGlobal = scvf.vertexIndex(); - const auto insideScvIdx = scvf.insideScvIdx(); - - neighborFlipScvfIndices_[outsideFace].resize(numOutsideScvs); - for (unsigned int nIdx = 0; nIdx < numOutsideScvs; ++nIdx) - { - const auto neighborScvIdx = scvf.outsideScvIdx(nIdx); - - // if the neighbor scv idx is the index of the bound element, - // then the flip scvf will be within the inside scvfs - if (neighborScvIdx == scvIndices_[0]) - { - for (unsigned int insideFace = 0; insideFace < numInsideScvfs; ++insideFace) - { - const auto& insideScvf = scvfs_[insideFace]; - // check if the face is the flip face - if (insideScvf.vertexIndex() == vIdxGlobal && - MpfaHelper::vectorContainsValue(insideScvf.outsideScvIndices(), insideScvIdx)) - { - neighborFlipScvfIndices_[outsideFace][nIdx] = insideFace; - // there is always only one flip face in an outside element - break; - } - } - } - else - { - for (unsigned int outsideFace2 = 0; outsideFace2 < numNeighborScvfs; ++outsideFace2) - { - const auto& outsideScvf = neighborScvfs_[outsideFace2]; - // check if outside face is the flip face - if (outsideScvf.insideScvIdx() == neighborScvIdx && - outsideScvf.vertexIndex() == vIdxGlobal && - MpfaHelper::vectorContainsValue(outsideScvf.outsideScvIndices(), insideScvIdx)) - { - neighborFlipScvfIndices_[outsideFace][nIdx] = outsideFace2; - // there is always only one flip face in an outside element - break; - } - } - } - } - } - } - //! map a global index to the local storage index const unsigned int findLocalIndex(const GridIndexType idx, const std::vector<GridIndexType>& indices) const @@ -635,9 +524,6 @@ private: neighborScvfIndices_.clear(); neighborScvs_.clear(); neighborScvfs_.clear(); - - flipScvfIndices_.clear(); - neighborFlipScvfIndices_.clear(); } const FVGridGeometry* fvGridGeometryPtr_; @@ -652,10 +538,6 @@ private: std::vector<GridIndexType> neighborScvfIndices_; std::vector<SubControlVolume> neighborScvs_; std::vector<SubControlVolumeFace> neighborScvfs_; - - // flip scvf index sets - std::vector< std::vector<GridIndexType> > flipScvfIndices_; - std::vector< std::vector<GridIndexType> > neighborFlipScvfIndices_; }; } // end namespace diff --git a/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh b/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh index aee1736c8868e503e56aa8c6ae4188d41118c71c..e56f3b1dd7b7c797409f57fb93ecd1b58e289c73 100644 --- a/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh +++ b/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh @@ -329,7 +329,6 @@ public: break; } } - } } } @@ -524,6 +523,13 @@ public: // instantiate the dual grid index set (to be used for construction of interaction volumes) typename GridIVIndexSets::DualGridIndexSet dualIdSet(this->gridView()); + // keep track of boundary scvfs and scvf vertex indices in order to set up flip scvf index set + const auto maxNumScvfs = numScvs_*LocalView::maxNumElementScvfs; + std::vector<bool> scvfIsOnBoundary; + std::vector<GridIndexType> scvfVertexIndex; + scvfIsOnBoundary.reserve(maxNumScvfs); + scvfVertexIndex.reserve(maxNumScvfs); + // Build the SCVs and SCV faces numScvf_ = 0; numBoundaryScvf_ = 0; @@ -614,6 +620,8 @@ public: // store information on the scv face scvfsIndexSet.push_back(numScvf_++); + scvfIsOnBoundary.push_back(boundary); + scvfVertexIndex.push_back(vIdxGlobal); neighborVolVarIndexSet.emplace_back(std::move(outsideScvIndices)); } @@ -627,6 +635,46 @@ public: neighborVolVarIndices_[eIdx] = neighborVolVarIndexSet; } + // Make the flip index set for network and surface grids + if (dim < dimWorld) + { + flipScvfIndices_.resize(numScvf_); + for (std::size_t scvIdx = 0; scvIdx < numScvs_; ++scvIdx) + { + const auto& scvfIndices = scvfIndicesOfScv_[scvIdx]; + for (unsigned int i = 0; i < scvfIndices.size(); ++i) + { + // boundary scvf have no flip scvfs + if (scvfIsOnBoundary[ scvfIndices[i] ]) + continue; + + const auto scvfIdx = scvfIndices[i]; + const auto vIdxGlobal = scvfVertexIndex[scvfIdx]; + const auto numOutsideScvs = neighborVolVarIndices_[scvIdx][i].size(); + + flipScvfIndices_[scvfIdx].resize(numOutsideScvs); + for (unsigned int j = 0; j < numOutsideScvs; ++j) + { + const auto outsideScvIdx = neighborVolVarIndices_[scvIdx][i][j]; + const auto& outsideScvfIndices = scvfIndicesOfScv_[outsideScvIdx]; + for (unsigned int k = 0; k < outsideScvfIndices.size(); ++k) + { + const auto outsideScvfIndex = outsideScvfIndices[k]; + const auto outsideScvfVertexIndex = scvfVertexIndex[outsideScvfIndex]; + const auto& outsideScvfNeighborIndices = neighborVolVarIndices_[outsideScvIdx][k]; + if (outsideScvfVertexIndex == vIdxGlobal && + MpfaHelper::vectorContainsValue(outsideScvfNeighborIndices, scvIdx)) + { + flipScvfIndices_[scvfIdx][j] = outsideScvfIndex; + // there is always only one flip face in an outside element + break; + } + } + } + } + } + } + // building the geometries has finished std::cout << "Initializing of the grid finite volume geometry took " << timer.elapsed() << " seconds." << std::endl; @@ -649,6 +697,11 @@ public: const std::vector<ScvfOutsideGridIndexStorage>& neighborVolVarIndices(GridIndexType scvIdx) const { return neighborVolVarIndices_[scvIdx]; } + //! Get the index scvf on the same face but from the other side + //! Note that e.g. the normals might be different in the case of surface grids + const GridIndexType flipScvfIdx(GridIndexType scvfIdx, unsigned int outsideScvfIdx = 0) const + { return flipScvfIndices_[scvfIdx][outsideScvfIdx]; } + //! Returns the connectivity map of which dofs //! have derivatives with respect to a given dof. const ConnectivityMap& connectivityMap() const { return connectivityMap_; } @@ -669,6 +722,9 @@ private: GridIndexType numScvf_; GridIndexType numBoundaryScvf_; + // needed for embedded surface and network grids (dim < dimWorld) + std::vector<ScvfOutsideGridIndexStorage> flipScvfIndices_; + // The grid interaction volume index set GridIVIndexSets ivIndexSets_;