diff --git a/dumux/common/fvproblem.hh b/dumux/common/fvproblem.hh index 4a69f5d7e0a7afea4e82d993f82ba21c9074767e..505a44dfc650c5ced65c6060d6864da6ab8440ee 100644 --- a/dumux/common/fvproblem.hh +++ b/dumux/common/fvproblem.hh @@ -483,14 +483,9 @@ public: std::vector<PointSource> sources; asImp_().addPointSources(sources); - // if there are point sources compute the DOF to point source map + // if there are point sources calculate point source locations and save them in a map if (!sources.empty()) - { - // calculate point source locations and save them in a map - PointSourceHelper::computePointSourceMap(*gridGeometry_, - sources, - pointSourceMap_); - } + PointSourceHelper::computePointSourceMap(*gridGeometry_, sources, pointSourceMap_, paramGroup()); } /*! diff --git a/dumux/common/pointsource.hh b/dumux/common/pointsource.hh index 1bd426ad66b90f5b9a69cc02a9f5fa49be678fe2..9633fa6af742e700f707ce8d52b2b0b8d821a2bc 100644 --- a/dumux/common/pointsource.hh +++ b/dumux/common/pointsource.hh @@ -28,6 +28,7 @@ #include <functional> +#include <dune/common/reservedvector.hh> #include <dumux/common/properties.hh> #include <dumux/common/parameters.hh> #include <dumux/common/geometry/boundingboxtree.hh> @@ -278,23 +279,24 @@ public: //! calculate a DOF index to point source map from given vector of point sources template<class GridGeometry, class PointSource, class PointSourceMap> static void computePointSourceMap(const GridGeometry& gridGeometry, - std::vector<PointSource>& sources, - PointSourceMap& pointSourceMap) + const std::vector<PointSource>& sources, + PointSourceMap& pointSourceMap, + const std::string& paramGroup = "") { - constexpr bool isBox = GridGeometry::discMethod == DiscretizationMethod::box; - const auto& boundingBoxTree = gridGeometry.boundingBoxTree(); - for (auto&& source : sources) + for (const auto& s : sources) { + // make local copy of point source for the map + auto source = s; // compute in which elements the point source falls const auto entities = intersectingEntities(source.position(), boundingBoxTree); // split the source values equally among all concerned entities source.setEmbeddings(entities.size()*source.embeddings()); // loop over all concernes elements - for (unsigned int eIdx : entities) + for (const auto eIdx : entities) { - if(isBox) + if constexpr (GridGeometry::discMethod == DiscretizationMethod::box) { // check in which subcontrolvolume(s) we are const auto element = boundingBoxTree.entitySet().entity(eIdx); @@ -303,21 +305,21 @@ public: const auto globalPos = source.position(); // loop over all sub control volumes and check if the point source is inside - std::vector<unsigned int> scvIndices; - for (auto&& scv : scvs(fvGeometry)) - { + constexpr int dim = GridGeometry::GridView::dimension; + Dune::ReservedVector<std::size_t, 1<<dim> scvIndices; + for (const auto& scv : scvs(fvGeometry)) if (intersectsPointGeometry(globalPos, scv.geometry())) scvIndices.push_back(scv.indexInElement()); - } - // for all scvs that where tested positiv add the point sources + + // for all scvs that tested positive add the point sources // to the element/scv to point source map - for (auto scvIdx : scvIndices) + for (const auto scvIdx : scvIndices) { const auto key = std::make_pair(eIdx, scvIdx); if (pointSourceMap.count(key)) - pointSourceMap.at(key).push_back(source); + pointSourceMap.at(key).emplace_back(std::move(source)); else - pointSourceMap.insert({key, {source}}); + pointSourceMap.insert({key, {std::move(source)}}); // split equally on the number of matched scvs auto& s = pointSourceMap.at(key).back(); s.setEmbeddings(scvIndices.size()*s.embeddings()); @@ -328,9 +330,9 @@ public: // add the pointsource to the DOF map const auto key = std::make_pair(eIdx, /*scvIdx=*/ 0); if (pointSourceMap.count(key)) - pointSourceMap.at(key).push_back(source); + pointSourceMap.at(key).emplace_back(std::move(source)); else - pointSourceMap.insert({key, {source}}); + pointSourceMap.insert({key, {std::move(source)}}); } } } diff --git a/dumux/multidomain/embedded/couplingmanager1d3d.hh b/dumux/multidomain/embedded/couplingmanager1d3d.hh index 4f495a88cd466466c8c25ae59a549554086bbe66..0b9c09038ccae294cb8eee4ce11746cde9868b9f 100644 --- a/dumux/multidomain/embedded/couplingmanager1d3d.hh +++ b/dumux/multidomain/embedded/couplingmanager1d3d.hh @@ -32,6 +32,7 @@ #include <dune/geometry/quadraturerules.hh> #include <dumux/common/properties.hh> +#include <dumux/common/indextraits.hh> #include <dumux/multidomain/embedded/pointsourcedata.hh> #include <dumux/multidomain/embedded/integrationpointsource.hh> #include <dumux/multidomain/embedded/couplingmanagerbase.hh> @@ -103,6 +104,7 @@ class EmbeddedCouplingManager1d3d<MDTraits, EmbeddedCouplingMode::line> template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; + template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex; public: static constexpr EmbeddedCouplingMode couplingMode = EmbeddedCouplingMode::line; @@ -122,6 +124,9 @@ public: { // resize the storage vector lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0)); + // get references to the grid geometries + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); // compute the low dim volume fractions for (const auto& is : intersections(this->glue())) @@ -129,14 +134,14 @@ public: // all inside elements are identical... const auto& inside = is.targetEntity(0); const auto intersectionGeometry = is.geometry(); - const std::size_t lowDimElementIdx = this->problem(lowDimIdx).gridGeometry().elementMapper().index(inside); + const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside); // compute the volume the low-dim domain occupies in the bulk domain if it were full-dimensional const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx); - for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) + for (int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) { const auto& outside = is.domainEntity(outsideIdx); - const std::size_t bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(outside); + const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside); lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius; } } @@ -203,6 +208,7 @@ class EmbeddedCouplingManager1d3d<MDTraits, EmbeddedCouplingMode::average> template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; + template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex; using GlobalPosition = typename Element<bulkIdx>::Geometry::GlobalCoordinate; @@ -271,9 +277,11 @@ public: void computePointSourceData(std::size_t order = 1, bool verbose = false) { // Initialize the bulk bounding box tree - const auto& bulkTree = this->problem(bulkIdx).gridGeometry().boundingBoxTree(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkTree = bulkGridGeometry.boundingBoxTree(); - // initilize the maps + // initialize the maps // do some logging and profiling Dune::Timer watch; std::cout << "Initializing the point sources..." << std::endl; @@ -281,11 +289,11 @@ public: // clear all internal members like pointsource vectors and stencils // initializes the point source id counter this->clear(); - extendedSourceStencil_.stencil().clear(); + extendedSourceStencil_.clear(); // precompute the vertex indices for efficiency - this->preComputeVertexIndices(bulkIdx); - this->preComputeVertexIndices(lowDimIdx); + this->precomputeVertexIndices(bulkIdx); + this->precomputeVertexIndices(lowDimIdx); // iterate over all lowdim elements const auto& lowDimProblem = this->problem(lowDimIdx); @@ -295,7 +303,7 @@ public: const auto lowDimGeometry = lowDimElement.geometry(); const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(lowDimGeometry.type(), order); - const auto lowDimElementIdx = lowDimProblem.gridGeometry().elementMapper().index(lowDimElement); + const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(lowDimElement); // apply the Gaussian quadrature rule and define point sources at each quadrature point // note that the approximation is not optimal if @@ -323,36 +331,43 @@ public: static const auto numIp = getParam<int>("MixedDimension.NumCircleSegments"); const auto radius = lowDimProblem.spatialParams().radius(lowDimElementIdx); const auto normal = lowDimGeometry.corner(1)-lowDimGeometry.corner(0); - const auto weight = 2*M_PI*radius/numIp; + const auto circleAvgWeight = 2*M_PI*radius/numIp; const auto circlePoints = EmbeddedCoupling::circlePoints(globalPos, normal, radius, numIp); - std::vector<Scalar> circleIpWeight(circlePoints.size()); - std::vector<std::size_t> circleStencil(circlePoints.size()); + std::vector<Scalar> circleIpWeight; circleIpWeight.reserve(circlePoints.size()); + std::vector<GridIndex<bulkIdx>> circleStencil; circleStencil.reserve(circlePoints.size()); + // for box - std::unordered_map<std::size_t, std::vector<std::size_t> > circleCornerIndices; + std::vector<const std::vector<GridIndex<bulkIdx>>*> circleCornerIndices; using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >; - std::unordered_map<std::size_t, ShapeValues> circleShapeValues; + std::vector<ShapeValues> circleShapeValues; + // go over all points of the average operator + int insideCirclePoints = 0; for (int k = 0; k < circlePoints.size(); ++k) { const auto circleBulkElementIndices = intersectingEntities(circlePoints[k], bulkTree); if (circleBulkElementIndices.empty()) continue; - const auto bulkElementIdx = circleBulkElementIndices[0]; - circleStencil[k] = bulkElementIdx; - circleIpWeight[k] = weight; - - if (isBox<bulkIdx>()) + ++insideCirclePoints; + const auto localCircleAvgWeight = circleAvgWeight / circleBulkElementIndices.size(); + for (const auto bulkElementIdx : circleBulkElementIndices) { - if (!static_cast<bool>(circleCornerIndices.count(bulkElementIdx))) + circleStencil.push_back(bulkElementIdx); + circleIpWeight.push_back(localCircleAvgWeight); + + // precompute interpolation data for box scheme for each cut element + if (isBox<bulkIdx>()) { - const auto bulkElement = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx); - circleCornerIndices[bulkElementIdx] = this->vertexIndices(bulkIdx, bulkElementIdx); + const auto bulkElement = bulkGridGeometry.element(bulkElementIdx); + circleCornerIndices.push_back(&(this->vertexIndices(bulkIdx, bulkElementIdx))); // evaluate shape functions at the integration point const auto bulkGeometry = bulkElement.geometry(); - this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry, circlePoints[k], circleShapeValues[bulkElementIdx]); + ShapeValues shapeValues; + this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, circlePoints[k], shapeValues); + circleShapeValues.emplace_back(std::move(shapeValues)); } } } @@ -364,7 +379,7 @@ public: for (const auto& vertices : circleCornerIndices) { this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(), - vertices.second.begin(), vertices.second.end()); + vertices->begin(), vertices->end()); } } @@ -390,10 +405,10 @@ public: // the actual solution dependent source term PointSourceData psData; - if (isBox<lowDimIdx>()) + if constexpr (isBox<lowDimIdx>()) { ShapeValues shapeValues; - this->getShapeValues(lowDimIdx, this->problem(lowDimIdx).gridGeometry(), lowDimGeometry, globalPos, shapeValues); + this->getShapeValues(lowDimIdx, lowDimGridGeometry, lowDimGeometry, globalPos, shapeValues); psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx); } else @@ -402,13 +417,13 @@ public: } // add data needed to compute integral over the circle - if (isBox<bulkIdx>()) + if constexpr (isBox<bulkIdx>()) { psData.addCircleInterpolation(circleCornerIndices, circleShapeValues, circleIpWeight, circleStencil); - const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry(); + const auto bulkGeometry = bulkGridGeometry.element(bulkElementIdx).geometry(); ShapeValues shapeValues; - this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry, globalPos, shapeValues); + this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, globalPos, shapeValues); psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx); } else @@ -440,7 +455,7 @@ public: for (const auto& vertices : circleCornerIndices) { extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(), - vertices.second.begin(), vertices.second.end()); + vertices->begin(), vertices->end()); } } @@ -495,6 +510,9 @@ public: { // resize the storage vector lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0)); + // get references to the grid geometries + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); // compute the low dim volume fractions for (const auto& is : intersections(this->glue())) @@ -502,14 +520,14 @@ public: // all inside elements are identical... const auto& inside = is.targetEntity(0); const auto intersectionGeometry = is.geometry(); - const std::size_t lowDimElementIdx = this->problem(lowDimIdx).gridGeometry().elementMapper().index(inside); + const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside); // compute the volume the low-dim domain occupies in the bulk domain if it were full-dimensional const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx); - for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) + for (int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) { const auto& outside = is.domainEntity(outsideIdx); - const std::size_t bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(outside); + const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside); lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius; } } @@ -580,6 +598,7 @@ class EmbeddedCouplingManager1d3d<MDTraits, EmbeddedCouplingMode::cylindersource template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; + template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex; using GlobalPosition = typename Element<bulkIdx>::Geometry::GlobalCoordinate; @@ -617,9 +636,11 @@ public: void computePointSourceData(std::size_t order = 1, bool verbose = false) { // Initialize the bulk bounding box tree - const auto& bulkTree = this->problem(bulkIdx).gridGeometry().boundingBoxTree(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkTree = bulkGridGeometry.boundingBoxTree(); - // initilize the maps + // initialize the maps // do some logging and profiling Dune::Timer watch; std::cout << "Initializing the point sources..." << std::endl; @@ -629,8 +650,8 @@ public: this->clear(); // precompute the vertex indices for efficiency - this->preComputeVertexIndices(bulkIdx); - this->preComputeVertexIndices(lowDimIdx); + this->precomputeVertexIndices(bulkIdx); + this->precomputeVertexIndices(lowDimIdx); // iterate over all lowdim elements const auto& lowDimProblem = this->problem(lowDimIdx); @@ -640,7 +661,7 @@ public: const auto lowDimGeometry = lowDimElement.geometry(); const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(lowDimGeometry.type(), order); - const auto lowDimElementIdx = lowDimProblem.gridGeometry().elementMapper().index(lowDimElement); + const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(lowDimElement); // apply the Gaussian quadrature rule and define point sources at each quadrature point // note that the approximation is not optimal if @@ -693,11 +714,11 @@ public: // the actual solution dependent source term PointSourceData psData; - if (isBox<lowDimIdx>()) + if constexpr (isBox<lowDimIdx>()) { using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >; ShapeValues shapeValues; - this->getShapeValues(lowDimIdx, this->problem(lowDimIdx).gridGeometry(), lowDimGeometry, globalPos, shapeValues); + this->getShapeValues(lowDimIdx, lowDimGridGeometry, lowDimGeometry, globalPos, shapeValues); psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx); } else @@ -706,12 +727,12 @@ public: } // add data needed to compute integral over the circle - if (isBox<bulkIdx>()) + if constexpr (isBox<bulkIdx>()) { using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >; - const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry(); + const auto bulkGeometry = bulkGridGeometry.element(bulkElementIdx).geometry(); ShapeValues shapeValues; - this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry, circlePos, shapeValues); + this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, circlePos, shapeValues); psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx); } else @@ -773,6 +794,9 @@ public: { // resize the storage vector lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0)); + // get references to the grid geometries + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); // compute the low dim volume fractions for (const auto& is : intersections(this->glue())) @@ -780,14 +804,14 @@ public: // all inside elements are identical... const auto& inside = is.targetEntity(0); const auto intersectionGeometry = is.geometry(); - const std::size_t lowDimElementIdx = this->problem(lowDimIdx).gridGeometry().elementMapper().index(inside); + const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside); // compute the volume the low-dim domain occupies in the bulk domain if it were full-dimensional const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx); - for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) + for (int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) { const auto& outside = is.domainEntity(outsideIdx); - const std::size_t bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(outside); + const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside); lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius; } } @@ -856,6 +880,7 @@ class EmbeddedCouplingManager1d3d<MDTraits, EmbeddedCouplingMode::kernel> template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; + template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex; using GlobalPosition = typename Element<bulkIdx>::Geometry::GlobalCoordinate; @@ -921,7 +946,7 @@ public: */ void computePointSourceData(std::size_t order = 1, bool verbose = false) { - // initilize the maps + // initialize the maps // do some logging and profiling Dune::Timer watch; std::cout << "Initializing the point sources..." << std::endl; @@ -931,14 +956,14 @@ public: this->clear(); bulkSourceIds_.clear(); bulkSourceWeights_.clear(); - extendedSourceStencil_.stencil().clear(); + extendedSourceStencil_.clear(); // precompute the vertex indices for efficiency for the box method - this->preComputeVertexIndices(bulkIdx); - this->preComputeVertexIndices(lowDimIdx); + this->precomputeVertexIndices(bulkIdx); + this->precomputeVertexIndices(lowDimIdx); - const auto& bulkFvGridGeometry = this->problem(bulkIdx).gridGeometry(); - const auto& lowDimFvGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); bulkSourceIds_.resize(this->gridView(bulkIdx).size(0)); bulkSourceWeights_.resize(this->gridView(bulkIdx).size(0)); @@ -958,7 +983,7 @@ public: // get the Gaussian quadrature rule for the local intersection const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(intersectionGeometry.type(), order); - const std::size_t lowDimElementIdx = lowDimFvGridGeometry.elementMapper().index(inside); + const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside); // iterate over all quadrature points and place a source // for 1d: make a new point source @@ -966,10 +991,10 @@ public: for (auto&& qp : quad) { // compute the coupling stencils - for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) + for (int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) { const auto& outside = is.domainEntity(outsideIdx); - const std::size_t bulkElementIdx = bulkFvGridGeometry.elementMapper().index(outside); + const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside); // each quadrature point will be a point source for the sub problem const auto globalPos = intersectionGeometry.global(qp.position()); @@ -984,12 +1009,12 @@ public: // the actual solution dependent source term PointSourceData psData; - if (isBox<lowDimIdx>()) + if constexpr (isBox<lowDimIdx>()) { using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >; - const auto lowDimGeometry = this->problem(lowDimIdx).gridGeometry().element(lowDimElementIdx).geometry(); + const auto lowDimGeometry = lowDimGridGeometry.element(lowDimElementIdx).geometry(); ShapeValues shapeValues; - this->getShapeValues(lowDimIdx, this->problem(lowDimIdx).gridGeometry(), lowDimGeometry, globalPos, shapeValues); + this->getShapeValues(lowDimIdx, lowDimGridGeometry, lowDimGeometry, globalPos, shapeValues); psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx); } else @@ -998,12 +1023,12 @@ public: } // add data needed to compute integral over the circle - if (isBox<bulkIdx>()) + if constexpr (isBox<bulkIdx>()) { using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >; - const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry(); + const auto bulkGeometry = bulkGridGeometry.element(bulkElementIdx).geometry(); ShapeValues shapeValues; - this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry, globalPos, shapeValues); + this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, globalPos, shapeValues); psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx); } else @@ -1078,6 +1103,9 @@ public: { // resize the storage vector lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0)); + // get references to the grid geometries + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); // compute the low dim volume fractions for (const auto& is : intersections(this->glue())) @@ -1085,14 +1113,14 @@ public: // all inside elements are identical... const auto& inside = is.targetEntity(0); const auto intersectionGeometry = is.geometry(); - const std::size_t lowDimElementIdx = this->problem(lowDimIdx).gridGeometry().elementMapper().index(inside); + const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside); // compute the volume the low-dim domain occupies in the bulk domain if it were full-dimensional const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx); - for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) + for (int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) { const auto& outside = is.domainEntity(outsideIdx); - const std::size_t bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(outside); + const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside); lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius; } } @@ -1127,11 +1155,11 @@ public: } //! return all source ids for a bulk elements - const std::vector<std::size_t> bulkSourceIds(std::size_t eIdx) const + const std::vector<std::size_t> bulkSourceIds(GridIndex<bulkIdx> eIdx) const { return bulkSourceIds_[eIdx]; } //! return all source ids for a bulk elements - const std::vector<Scalar> bulkSourceWeights(std::size_t eIdx) const + const std::vector<Scalar> bulkSourceWeights(GridIndex<bulkIdx> eIdx) const { return bulkSourceWeights_[eIdx]; } // \} @@ -1139,7 +1167,7 @@ public: private: //! TODO: How to optimize this? void computeBulkSource(const GlobalPosition& globalPos, const Scalar kernelWidth, - std::size_t id, std::size_t lowDimElementIdx, std::size_t coupledBulkElementIdx, + std::size_t id, GridIndex<lowDimIdx> lowDimElementIdx, GridIndex<bulkIdx> coupledBulkElementIdx, Scalar pointSourceWeight) { // make sure it is mass conservative @@ -1162,7 +1190,8 @@ private: if (weight > 1e-13) { - const auto bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); + const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(element); bulkSourceIds_[bulkElementIdx].push_back(id); bulkSourceWeights_[bulkElementIdx].push_back(weight*pointSourceWeight); mask[bulkElementIdx] = true; @@ -1188,7 +1217,7 @@ private: } } - for (std::size_t eIdx = 0; eIdx < bulkSourceWeights_.size(); ++eIdx) + for (GridIndex<bulkIdx> eIdx = 0; eIdx < bulkSourceWeights_.size(); ++eIdx) if (mask[eIdx]) bulkSourceWeights_[eIdx].back() /= checkSum; // balance error of the quadrature rule -> TODO: what to do at boundaries diff --git a/dumux/multidomain/embedded/couplingmanagerbase.hh b/dumux/multidomain/embedded/couplingmanagerbase.hh index 678eb0ad4ce9b69dbd97a6d3f1475a0564f1f15b..b130b9edd1021e8fbe7d2675fa4e68c3b90dbafb 100644 --- a/dumux/multidomain/embedded/couplingmanagerbase.hh +++ b/dumux/multidomain/embedded/couplingmanagerbase.hh @@ -91,18 +91,17 @@ class EmbeddedCouplingManagerBase template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; template<std::size_t id> using ElementMapper = typename GridGeometry<id>::ElementMapper; template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; + template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex; + template<std::size_t id> using CouplingStencil = std::vector<GridIndex<id>>; - enum { - bulkDim = GridView<bulkIdx>::dimension, - lowDimDim = GridView<lowDimIdx>::dimension, - dimWorld = GridView<bulkIdx>::dimensionworld - }; + static constexpr int bulkDim = GridView<bulkIdx>::dimension; + static constexpr int lowDimDim = GridView<lowDimIdx>::dimension; + static constexpr int dimWorld = GridView<bulkIdx>::dimensionworld; template<std::size_t id> static constexpr bool isBox() { return GridGeometry<id>::discMethod == DiscretizationMethod::box; } - using CouplingStencil = std::vector<std::size_t>; using GlobalPosition = typename Element<bulkIdx>::Geometry::GlobalCoordinate; using GlueType = MultiDomainGlue<GridView<bulkIdx>, GridView<lowDimIdx>, ElementMapper<bulkIdx>, ElementMapper<lowDimIdx>>; @@ -112,13 +111,13 @@ public: //! export the point source traits using PointSourceTraits = PSTraits; //! export stencil types - using CouplingStencils = std::unordered_map<std::size_t, CouplingStencil>; + template<std::size_t id> using CouplingStencils = std::unordered_map<GridIndex<id>, CouplingStencil<id>>; /*! * \brief call this after grid adaption */ - void updateAfterGridAdaption(std::shared_ptr<const GridGeometry<bulkIdx>> bulkFvGridGeometry, - std::shared_ptr<const GridGeometry<lowDimIdx>> lowDimFvGridGeometry) + void updateAfterGridAdaption(std::shared_ptr<const GridGeometry<bulkIdx>> bulkGridGeometry, + std::shared_ptr<const GridGeometry<lowDimIdx>> lowDimGridGeometry) { glue_ = std::make_shared<GlueType>(); } @@ -126,10 +125,10 @@ public: /*! * \brief Constructor */ - EmbeddedCouplingManagerBase(std::shared_ptr<const GridGeometry<bulkIdx>> bulkFvGridGeometry, - std::shared_ptr<const GridGeometry<lowDimIdx>> lowDimFvGridGeometry) + EmbeddedCouplingManagerBase(std::shared_ptr<const GridGeometry<bulkIdx>> bulkGridGeometry, + std::shared_ptr<const GridGeometry<lowDimIdx>> lowDimGridGeometry) { - updateAfterGridAdaption(bulkFvGridGeometry, lowDimFvGridGeometry); + updateAfterGridAdaption(bulkGridGeometry, lowDimGridGeometry); } /*! @@ -170,9 +169,9 @@ public: * \note This function has to be implemented by all coupling managers for all combinations of i and j */ template<std::size_t i, std::size_t j> - const CouplingStencil& couplingStencil(Dune::index_constant<i> domainI, - const Element<i>& element, - Dune::index_constant<j> domainJ) const + const CouplingStencil<j>& couplingStencil(Dune::index_constant<i> domainI, + const Element<i>& element, + Dune::index_constant<j> domainJ) const { static_assert(i != j, "A domain cannot be coupled to itself!"); @@ -180,7 +179,7 @@ public: if (couplingStencils(domainI).count(eIdx)) return couplingStencils(domainI).at(eIdx); else - return emptyStencil_; + return emptyStencil(domainI); } /*! @@ -243,11 +242,11 @@ public: clear(); // precompute the vertex indices for efficiency for the box method - this->preComputeVertexIndices(bulkIdx); - this->preComputeVertexIndices(lowDimIdx); + this->precomputeVertexIndices(bulkIdx); + this->precomputeVertexIndices(lowDimIdx); - const auto& bulkFvGridGeometry = this->problem(bulkIdx).gridGeometry(); - const auto& lowDimFvGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); // intersect the bounding box trees glueGrids(); @@ -263,7 +262,7 @@ public: // get the Gaussian quadrature rule for the local intersection const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(intersectionGeometry.type(), order); - const std::size_t lowDimElementIdx = lowDimFvGridGeometry.elementMapper().index(inside); + const std::size_t lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside); // iterate over all quadrature points for (auto&& qp : quad) @@ -272,7 +271,7 @@ public: for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) { const auto& outside = is.domainEntity(outsideIdx); - const std::size_t bulkElementIdx = bulkFvGridGeometry.elementMapper().index(outside); + const std::size_t bulkElementIdx = bulkGridGeometry.elementMapper().index(outside); // each quadrature point will be a point source for the sub problem const auto globalPos = intersectionGeometry.global(qp.position()); @@ -288,7 +287,7 @@ public: // the actual solution dependent source term PointSourceData psData; - if (isBox<lowDimIdx>()) + if constexpr (isBox<lowDimIdx>()) { using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >; const auto lowDimGeometry = this->problem(lowDimIdx).gridGeometry().element(lowDimElementIdx).geometry(); @@ -302,7 +301,7 @@ public: } // add data needed to compute integral over the circle - if (isBox<bulkIdx>()) + if constexpr (isBox<bulkIdx>()) { using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >; const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry(); @@ -381,17 +380,11 @@ public: //! Return data for a bulk point source with the identifier id PrimaryVariables<bulkIdx> bulkPriVars(std::size_t id) const - { - auto& data = pointSourceData_[id]; - return data.interpolateBulk(this->curSol()[bulkIdx]); - } + { return pointSourceData_[id].interpolateBulk(this->curSol()[bulkIdx]); } //! Return data for a low dim point source with the identifier id PrimaryVariables<lowDimIdx> lowDimPriVars(std::size_t id) const - { - auto& data = pointSourceData_[id]; - return data.interpolateLowDim(this->curSol()[lowDimIdx]); - } + { return pointSourceData_[id].interpolateLowDim(this->curSol()[lowDimIdx]); } //! return the average distance to the coupled bulk cell center Scalar averageDistance(std::size_t id) const @@ -412,25 +405,26 @@ public: //! Return reference to bulk coupling stencil member of domain i template<std::size_t i> - const CouplingStencils& couplingStencils(Dune::index_constant<i> dom) const - { return (i == bulkIdx) ? bulkCouplingStencils_ : lowDimCouplingStencils_; } + const CouplingStencils<i>& couplingStencils(Dune::index_constant<i> dom) const + { return std::get<i>(couplingStencils_); } //! Return reference to point source data vector member const std::vector<PointSourceData>& pointSourceData() const { return pointSourceData_; } //! Return a reference to an empty stencil - const CouplingStencil& emptyStencil() const - { return emptyStencil_; } + template<std::size_t i> + const CouplingStencil<i>& emptyStencil(Dune::index_constant<i> dom) const + { return std::get<i>(emptyStencil_); } protected: //! computes the vertex indices per element for the box method template<std::size_t id> - void preComputeVertexIndices(Dune::index_constant<id> domainIdx) + void precomputeVertexIndices(Dune::index_constant<id> domainIdx) { // fill helper structure for box discretization - if (isBox<domainIdx>()) + if constexpr (isBox<domainIdx>()) { this->vertexIndices(domainIdx).resize(gridView(domainIdx).size(0)); for (const auto& element : elements(gridView(domainIdx))) @@ -445,19 +439,17 @@ protected: } //! compute the shape function for a given point and geometry - template<std::size_t i, class FVGG, class Geometry, class ShapeValues, typename std::enable_if_t<FVGG::discMethod == DiscretizationMethod::box, int> = 0> + template<std::size_t i, class FVGG, class Geometry, class ShapeValues> void getShapeValues(Dune::index_constant<i> domainI, const FVGG& gridGeometry, const Geometry& geo, const GlobalPosition& globalPos, ShapeValues& shapeValues) { - const auto ipLocal = geo.local(globalPos); - const auto& localBasis = this->problem(domainI).gridGeometry().feCache().get(geo.type()).localBasis(); - localBasis.evaluateFunction(ipLocal, shapeValues); - } - - //! compute the shape function for a given point and geometry - template<std::size_t i, class FVGG, class Geometry, class ShapeValues, typename std::enable_if_t<FVGG::discMethod != DiscretizationMethod::box, int> = 0> - void getShapeValues(Dune::index_constant<i> domainI, const FVGG& gridGeometry, const Geometry& geo, const GlobalPosition& globalPos, ShapeValues& shapeValues) - { - DUNE_THROW(Dune::InvalidStateException, "Shape values requested for other discretization than box!"); + if constexpr (FVGG::discMethod == DiscretizationMethod::box) + { + const auto ipLocal = geo.local(globalPos); + const auto& localBasis = this->problem(domainI).gridGeometry().feCache().get(geo.type()).localBasis(); + localBasis.evaluateFunction(ipLocal, shapeValues); + } + else + DUNE_THROW(Dune::InvalidStateException, "Shape values requested for other discretization than box!"); } //! Clear all internal data members @@ -465,11 +457,11 @@ protected: { pointSources(bulkIdx).clear(); pointSources(lowDimIdx).clear(); + couplingStencils(bulkIdx).clear(); + couplingStencils(lowDimIdx).clear(); + vertexIndices(bulkIdx).clear(); + vertexIndices(lowDimIdx).clear(); pointSourceData_.clear(); - bulkCouplingStencils_.clear(); - lowDimCouplingStencils_.clear(); - bulkVertexIndices_.clear(); - lowDimVertexIndices_.clear(); averageDistanceToBulkCell_.clear(); idCounter_ = 0; @@ -478,23 +470,20 @@ protected: //! compute the intersections between the two grids void glueGrids() { - const auto& bulkFvGridGeometry = this->problem(bulkIdx).gridGeometry(); - const auto& lowDimFvGridGeometry = this->problem(lowDimIdx).gridGeometry(); + const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); + const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); // intersect the bounding box trees - glue_->build(bulkFvGridGeometry.boundingBoxTree(), lowDimFvGridGeometry.boundingBoxTree()); + glue_->build(bulkGridGeometry.boundingBoxTree(), lowDimGridGeometry.boundingBoxTree()); } template<class Geometry, class GlobalPosition> - Scalar computeDistance(const Geometry& geometry, const GlobalPosition& p) + Scalar computeDistance(const Geometry& geometry, const GlobalPosition& p) const { Scalar avgDist = 0.0; const auto& quad = Dune::QuadratureRules<Scalar, bulkDim>::rule(geometry.type(), 5); for (auto&& qp : quad) - { - const auto globalPos = geometry.global(qp.position()); - avgDist += (globalPos-p).two_norm()*qp.weight(); - } + avgDist += (geometry.global(qp.position())-p).two_norm()*qp.weight(); return avgDist; } @@ -513,18 +502,18 @@ protected: //! Return reference to bulk coupling stencil member of domain i template<std::size_t i> - CouplingStencils& couplingStencils(Dune::index_constant<i> dom) - { return (i == 0) ? bulkCouplingStencils_ : lowDimCouplingStencils_; } + CouplingStencils<i>& couplingStencils(Dune::index_constant<i> dom) + { return std::get<i>(couplingStencils_); } //! Return a reference to the vertex indices template<std::size_t i> - std::vector<std::size_t>& vertexIndices(Dune::index_constant<i> dom, std::size_t eIdx) - { return (i == 0) ? bulkVertexIndices_[eIdx] : lowDimVertexIndices_[eIdx]; } + std::vector<GridIndex<i>>& vertexIndices(Dune::index_constant<i> dom, GridIndex<i> eIdx) + { return std::get<i>(vertexIndices_)[eIdx]; } //! Return a reference to the vertex indices container template<std::size_t i> - std::vector<std::vector<std::size_t>>& vertexIndices(Dune::index_constant<i> dom) - { return (i == 0) ? bulkVertexIndices_ : lowDimVertexIndices_; } + std::vector<std::vector<GridIndex<i>>>& vertexIndices(Dune::index_constant<i> dom) + { return std::get<i>(vertexIndices_); } const GlueType& glue() const { return *glue_; } @@ -544,15 +533,14 @@ private: //! the point source in both domains std::tuple<std::vector<PointSource<bulkIdx>>, std::vector<PointSource<lowDimIdx>>> pointSources_; - mutable std::vector<PointSourceData> pointSourceData_; + std::vector<PointSourceData> pointSourceData_; std::vector<Scalar> averageDistanceToBulkCell_; //! Stencil data - std::vector<std::vector<std::size_t>> bulkVertexIndices_; - std::vector<std::vector<std::size_t>> lowDimVertexIndices_; - CouplingStencils bulkCouplingStencils_; - CouplingStencils lowDimCouplingStencils_; - CouplingStencil emptyStencil_; + std::tuple<std::vector<std::vector<GridIndex<bulkIdx>>>, + std::vector<std::vector<GridIndex<lowDimIdx>>>> vertexIndices_; + std::tuple<CouplingStencils<bulkIdx>, CouplingStencils<lowDimIdx>> couplingStencils_; + std::tuple<CouplingStencil<bulkIdx>, CouplingStencil<lowDimIdx>> emptyStencil_; //! The glue object std::shared_ptr<GlueType> glue_; diff --git a/dumux/multidomain/embedded/extendedsourcestencil.hh b/dumux/multidomain/embedded/extendedsourcestencil.hh index 9d1baae3e6ae44e23a343dfa0f0de1f28ec924db..1e1a3afa62a244742dd4773a430d8040ad6ff87e 100644 --- a/dumux/multidomain/embedded/extendedsourcestencil.hh +++ b/dumux/multidomain/embedded/extendedsourcestencil.hh @@ -34,8 +34,7 @@ #include <dumux/common/numericdifferentiation.hh> #include <dumux/discretization/method.hh> -namespace Dumux { -namespace EmbeddedCoupling { +namespace Dumux::EmbeddedCoupling { /*! * \ingroup EmbeddedCoupling @@ -53,8 +52,10 @@ class ExtendedSourceStencil template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; - static constexpr auto bulkIdx = typename MDTraits::template SubDomain<0>::Index(); - static constexpr auto lowDimIdx = typename MDTraits::template SubDomain<1>::Index(); + template<std::size_t id> + static constexpr auto subDomainIdx = typename MDTraits::template SubDomain<id>::Index(); + static constexpr auto bulkIdx = subDomainIdx<0>; + static constexpr auto lowDimIdx = subDomainIdx<1>; template<std::size_t id> static constexpr bool isBox() @@ -73,8 +74,7 @@ public: for (const auto& element : elements(couplingManager.gridView(domainI))) { const auto& dofs = extendedSourceStencil_(couplingManager, domainI, element); - - if (isBox<domainI>()) + if constexpr (isBox<domainI>()) { for (int i = 0; i < element.subEntities(GridView<domainI>::dimension); ++i) for (const auto globalJ : dofs) @@ -104,7 +104,7 @@ public: JacobianMatrixDiagBlock& A, GridVariables& gridVariables) const { - constexpr auto numEq = std::decay_t<decltype(curSol[domainI][0])>::dimension; + constexpr auto numEq = std::decay_t<decltype(curSol[domainI][0])>::size(); const auto& elementI = localAssemblerI.element(); // only do something if we have an extended stencil @@ -141,7 +141,7 @@ public: partialDerivs, origResidual, numDiffMethod); // update the global stiffness matrix with the current partial derivatives - for (auto&& scvJ : scvs(localAssemblerI.fvGeometry())) + for (const auto& scvJ : scvs(localAssemblerI.fvGeometry())) { for (int eqIdx = 0; eqIdx < numEq; eqIdx++) { @@ -159,30 +159,32 @@ public: } } + //! clear the internal data + void clear() { sourceStencils_.clear(); } + //! return a reference to the stencil - typename CouplingManager::CouplingStencils& stencil() + typename CouplingManager::template CouplingStencils<bulkIdx>& stencil() { return sourceStencils_; } private: - //! the extended source stencil for the bulk domain due to the source average - const std::vector<std::size_t>& extendedSourceStencil_(const CouplingManager& couplingManager, Dune::index_constant<0> bulkDomain, const Element<0>& bulkElement) const + //! the extended source stencil due to the source average (always empty for lowdim, but may be filled for bulk) + template<std::size_t id> + const auto& extendedSourceStencil_(const CouplingManager& couplingManager, Dune::index_constant<id> bulkDomain, const Element<id>& bulkElement) const { - const auto bulkElementIdx = couplingManager.problem(bulkIdx).gridGeometry().elementMapper().index(bulkElement); - if (sourceStencils_.count(bulkElementIdx)) - return sourceStencils_.at(bulkElementIdx); - else - return couplingManager.emptyStencil(); - } + if constexpr (subDomainIdx<id> == bulkIdx) + { + const auto bulkElementIdx = couplingManager.problem(bulkIdx).gridGeometry().elementMapper().index(bulkElement); + if (sourceStencils_.count(bulkElementIdx)) + return sourceStencils_.at(bulkElementIdx); + } - //! the extended source stencil for the low dim domain is empty - const std::vector<std::size_t>& extendedSourceStencil_(const CouplingManager& couplingManager, Dune::index_constant<1> bulkDomain, const Element<1>& lowDimElement) const - { return couplingManager.emptyStencil(); } + return couplingManager.emptyStencil(subDomainIdx<id>); + } //! the additional stencil for the kernel evaluations / circle averages - typename CouplingManager::CouplingStencils sourceStencils_; + typename CouplingManager::template CouplingStencils<bulkIdx> sourceStencils_; }; -} // end namespace EmbeddedCoupling -} // end namespace Dumux +} // end namespace Dumux::EmbeddedCoupling #endif diff --git a/dumux/multidomain/embedded/integrationpointsource.hh b/dumux/multidomain/embedded/integrationpointsource.hh index 74ac494c9f378c6394ee78000e1155c8c14c6c60..e842481517dd8229578d6cb60fcc9b8809acdb2a 100644 --- a/dumux/multidomain/embedded/integrationpointsource.hh +++ b/dumux/multidomain/embedded/integrationpointsource.hh @@ -30,6 +30,7 @@ #include <type_traits> #include <dune/common/reservedvector.hh> #include <dumux/common/pointsource.hh> +#include <dumux/common/parameters.hh> #include <dumux/discretization/method.hh> namespace Dumux { @@ -47,37 +48,64 @@ class IntegrationPointSource : public IdPointSource<GlobalPosition, SourceValues public: //! Constructor for integration point sources + [[deprecated("Call constructor with a single element index instead! Will be removed after 3.3")]] IntegrationPointSource(GlobalPosition pos, SourceValues values, IdType id, Scalar qpweight, Scalar integrationElement, const std::vector<std::size_t>& elementIndices) : ParentType(pos, values, id), qpweight_(qpweight), integrationElement_(integrationElement), - elementIndices_(elementIndices) {} + elementIndex_(elementIndices[0]) {} //! Constructor for integration point sources, when there is no // value known at the time of initialization + [[deprecated("Call constructor with a single element index instead! Will be removed after 3.3")]] IntegrationPointSource(GlobalPosition pos, IdType id, Scalar qpweight, Scalar integrationElement, const std::vector<std::size_t>& elementIndices) : ParentType(pos, id), qpweight_(qpweight), integrationElement_(integrationElement), - elementIndices_(elementIndices) {} + elementIndex_(elementIndices[0]) {} + //! Constructor for integration point sources + IntegrationPointSource(GlobalPosition pos, SourceValues values, IdType id, + Scalar qpweight, Scalar integrationElement, + std::size_t elementIndex) + : ParentType(pos, values, id) + , qpweight_(qpweight) + , integrationElement_(integrationElement) + , elementIndex_(elementIndex) + {} + + //! Constructor for integration point sources, when there is no + //! value known at the time of initialization + IntegrationPointSource(GlobalPosition pos, IdType id, + Scalar qpweight, Scalar integrationElement, + std::size_t elementIndex) + : ParentType(pos, id) + , qpweight_(qpweight) + , integrationElement_(integrationElement) + , elementIndex_(elementIndex) + {} Scalar quadratureWeight() const - { - return qpweight_; - } + { return qpweight_; } Scalar integrationElement() const - { - return integrationElement_; - } + { return integrationElement_; } - const std::vector<std::size_t>& elementIndices() const - { - return elementIndices_; - } + void setQuadratureWeight(const Scalar qpWeight) + { return qpweight_ = qpWeight; } + + void setIntegrationElement(const Scalar ie) + { integrationElement_ = ie; } + + [[deprecated("Use elementIndex() instead. Will be removed after 3.3")]] + std::vector<std::size_t> elementIndices() const + { return std::vector<std::size_t>({elementIndex_}); } + + //! The index of the element this intergration point source is associated with + std::size_t elementIndex() const + { return elementIndex_; } //! Convenience = operator overload modifying only the values IntegrationPointSource& operator= (const SourceValues& values) @@ -96,7 +124,7 @@ public: private: Scalar qpweight_; Scalar integrationElement_; - std::vector<std::size_t> elementIndices_; + std::size_t elementIndex_; }; /*! @@ -110,29 +138,29 @@ public: //! calculate a DOF index to point source map from given vector of point sources template<class GridGeometry, class PointSource, class PointSourceMap> static void computePointSourceMap(const GridGeometry& gridGeometry, - std::vector<PointSource>& sources, - PointSourceMap& pointSourceMap) + const std::vector<PointSource>& sources, + PointSourceMap& pointSourceMap, + const std::string& paramGroup = "") { - for (auto&& source : sources) + for (const auto& source : sources) { - // compute in which elements the point source falls - const auto& entities = source.elementIndices(); - // split the source values equally among all concerned entities - source.setEmbeddings(source.embeddings()*entities.size()); - // loop over all intersected elements - for (unsigned int eIdx : entities) + // get the index of the element in which the point source falls + const auto eIdx = source.elementIndex(); + if constexpr (GridGeometry::discMethod == DiscretizationMethod::box) { - if (GridGeometry::discMethod == DiscretizationMethod::box) + // check in which subcontrolvolume(s) we are + const auto element = gridGeometry.boundingBoxTree().entitySet().entity(eIdx); + auto fvGeometry = localView(gridGeometry); + fvGeometry.bindElement(element); + const auto globalPos = source.position(); + + static const bool boxPointSourceLumping = getParamFromGroup<bool>(paramGroup, "PointSource.EnableBoxLumping", true); + if (boxPointSourceLumping) { - // check in which subcontrolvolume(s) we are - const auto element = gridGeometry.boundingBoxTree().entitySet().entity(eIdx); - auto fvGeometry = localView(gridGeometry); - fvGeometry.bindElement(element); - const auto globalPos = source.position(); // loop over all sub control volumes and check if the point source is inside constexpr int dim = GridGeometry::GridView::dimension; Dune::ReservedVector<std::size_t, 1<<dim> scvIndices; - for (auto&& scv : scvs(fvGeometry)) + for (const auto& scv : scvs(fvGeometry)) if (intersectsPointGeometry(globalPos, scv.geometry())) scvIndices.push_back(scv.indexInElement()); @@ -150,16 +178,38 @@ public: s.setEmbeddings(scvIndices.size()*s.embeddings()); } } + + // distribute the sources using the basis function weights else { - // add the pointsource to the DOF map - const auto key = std::make_pair(eIdx, /*scvIdx=*/ 0); - if (pointSourceMap.count(key)) - pointSourceMap.at(key).push_back(source); - else - pointSourceMap.insert({key, {source}}); + const auto& localBasis = fvGeometry.feLocalBasis(); + const auto ipLocal = element.geometry().local(globalPos); + using Scalar = std::decay_t<decltype(source.values()[0])>; + std::vector<typename Dune::FieldVector<Scalar, 1>> shapeValues; + localBasis.evaluateFunction(ipLocal, shapeValues); + for (const auto& scv : scvs(fvGeometry)) + { + const auto key = std::make_pair(eIdx, scv.indexInElement()); + if (pointSourceMap.count(key)) + pointSourceMap.at(key).push_back(source); + else + pointSourceMap.insert({key, {source}}); + + // adjust the integration element + auto& s = pointSourceMap.at(key).back(); + s.setIntegrationElement(shapeValues[scv.indexInElement()]*s.integrationElement()); + } } } + else + { + // add the pointsource to the DOF map + const auto key = std::make_pair(eIdx, /*scvIdx=*/ 0); + if (pointSourceMap.count(key)) + pointSourceMap.at(key).push_back(source); + else + pointSourceMap.insert({key, {source}}); + } } } }; diff --git a/dumux/multidomain/embedded/pointsourcedata.hh b/dumux/multidomain/embedded/pointsourcedata.hh index ef7689e7cf7bdf109b5f139067becc0f63b7674e..d6cbab29645e1b3d5ef5b44645309c76a9820c3f 100644 --- a/dumux/multidomain/embedded/pointsourcedata.hh +++ b/dumux/multidomain/embedded/pointsourcedata.hh @@ -22,13 +22,13 @@ * \brief Data associated with a point source */ -#ifndef DUMUX_POINTSOURCEDATA_HH -#define DUMUX_POINTSOURCEDATA_HH +#ifndef DUMUX_MULTIDOMAIN_EMBEDDED_POINTSOURCEDATA_HH +#define DUMUX_MULTIDOMAIN_EMBEDDED_POINTSOURCEDATA_HH #include <vector> -#include <unordered_map> #include <dune/common/fvector.hh> #include <dumux/common/properties.hh> +#include <dumux/common/indextraits.hh> #include <dumux/discretization/method.hh> namespace Dumux { @@ -44,59 +44,60 @@ class PointSourceData using Scalar = typename MDTraits::Scalar; using ShapeValues = typename std::vector<Dune::FieldVector<Scalar, 1> >; - // obtain the type tags of the sub problems - using BulkTypeTag = typename MDTraits::template SubDomain<0>::TypeTag; - using LowDimTypeTag = typename MDTraits::template SubDomain<1>::TypeTag; + template<std::size_t id> using SubDomainTypeTag = typename MDTraits::template SubDomain<id>::TypeTag; + template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; + template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; + template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex; + template<std::size_t id> using SolutionVector = GetPropType<SubDomainTypeTag<id>, Properties::SolutionVector>; + template<std::size_t id> using PrimaryVariables = GetPropType<SubDomainTypeTag<id>, Properties::PrimaryVariables>; - using BulkPrimaryVariables = GetPropType<BulkTypeTag, Properties::PrimaryVariables>; - using LowDimPrimaryVariables = GetPropType<LowDimTypeTag, Properties::PrimaryVariables>; + static constexpr auto bulkIdx = typename MDTraits::template SubDomain<0>::Index(); + static constexpr auto lowDimIdx = typename MDTraits::template SubDomain<1>::Index(); - using BulkSolutionVector = GetPropType<BulkTypeTag, Properties::SolutionVector>; - using LowDimSolutionVector = GetPropType<LowDimTypeTag, Properties::SolutionVector>; - - enum { - bulkIsBox = GetPropType<BulkTypeTag, Properties::GridGeometry>::discMethod == DiscretizationMethod::box, - lowDimIsBox = GetPropType<LowDimTypeTag, Properties::GridGeometry>::discMethod == DiscretizationMethod::box - }; + template<std::size_t id> + static constexpr bool isBox() + { return GridGeometry<id>::discMethod == DiscretizationMethod::box; } public: void addBulkInterpolation(const ShapeValues& shapeValues, - const std::vector<std::size_t>& cornerIndices, - std::size_t eIdx) + const std::vector<GridIndex<bulkIdx>>& cornerIndices, + GridIndex<bulkIdx> eIdx) { + static_assert(isBox<bulkIdx>(), "This interface is only available for the box method."); bulkElementIdx_ = eIdx; bulkCornerIndices_ = cornerIndices; bulkShapeValues_ = shapeValues; } void addLowDimInterpolation(const ShapeValues& shapeValues, - const std::vector<std::size_t>& cornerIndices, - std::size_t eIdx) + const std::vector<GridIndex<lowDimIdx>>& cornerIndices, + GridIndex<lowDimIdx> eIdx) { + static_assert(isBox<lowDimIdx>(), "This interface is only available for the box method."); lowDimElementIdx_ = eIdx; lowDimCornerIndices_ = cornerIndices; lowDimShapeValues_ = shapeValues; } - void addBulkInterpolation(std::size_t eIdx) + void addBulkInterpolation(GridIndex<bulkIdx> eIdx) { - assert(!bulkIsBox); + static_assert(!isBox<bulkIdx>(), "This interface is not available for the box method."); bulkElementIdx_ = eIdx; } - void addLowDimInterpolation(std::size_t eIdx) + void addLowDimInterpolation(GridIndex<lowDimIdx> eIdx) { - assert(!lowDimIsBox); + static_assert(!isBox<lowDimIdx>(), "This interface is not available for the box method."); lowDimElementIdx_ = eIdx; } - BulkPrimaryVariables interpolateBulk(const BulkSolutionVector& sol) + PrimaryVariables<bulkIdx> interpolateBulk(const SolutionVector<bulkIdx>& sol) const { - BulkPrimaryVariables bulkPriVars(0.0); - if (bulkIsBox) + PrimaryVariables<bulkIdx> bulkPriVars(0.0); + if (isBox<bulkIdx>()) { - for (std::size_t i = 0; i < bulkCornerIndices_.size(); ++i) - for (std::size_t priVarIdx = 0; priVarIdx < bulkPriVars.size(); ++priVarIdx) + for (int i = 0; i < bulkCornerIndices_.size(); ++i) + for (int priVarIdx = 0; priVarIdx < bulkPriVars.size(); ++priVarIdx) bulkPriVars[priVarIdx] += sol[bulkCornerIndices_[i]][priVarIdx]*bulkShapeValues_[i]; } else @@ -106,13 +107,13 @@ public: return bulkPriVars; } - LowDimPrimaryVariables interpolateLowDim(const LowDimSolutionVector& sol) + PrimaryVariables<lowDimIdx> interpolateLowDim(const SolutionVector<lowDimIdx>& sol) const { - LowDimPrimaryVariables lowDimPriVars(0.0); - if (lowDimIsBox) + PrimaryVariables<lowDimIdx> lowDimPriVars(0.0); + if (isBox<lowDimIdx>()) { - for (std::size_t i = 0; i < lowDimCornerIndices_.size(); ++i) - for (std::size_t priVarIdx = 0; priVarIdx < lowDimPriVars.size(); ++priVarIdx) + for (int i = 0; i < lowDimCornerIndices_.size(); ++i) + for (int priVarIdx = 0; priVarIdx < lowDimPriVars.size(); ++priVarIdx) lowDimPriVars[priVarIdx] += sol[lowDimCornerIndices_[i]][priVarIdx]*lowDimShapeValues_[i]; } else @@ -122,17 +123,18 @@ public: return lowDimPriVars; } - std::size_t lowDimElementIdx() const + GridIndex<lowDimIdx> lowDimElementIdx() const { return lowDimElementIdx_; } - std::size_t bulkElementIdx() const + GridIndex<bulkIdx> bulkElementIdx() const { return bulkElementIdx_; } private: ShapeValues bulkShapeValues_, lowDimShapeValues_; - std::vector<std::size_t> bulkCornerIndices_, lowDimCornerIndices_; - std::size_t lowDimElementIdx_; - std::size_t bulkElementIdx_; + std::vector<GridIndex<bulkIdx>> bulkCornerIndices_; + std::vector<GridIndex<lowDimIdx>> lowDimCornerIndices_; + GridIndex<bulkIdx> bulkElementIdx_; + GridIndex<lowDimIdx> lowDimElementIdx_; }; /*! @@ -151,48 +153,51 @@ class PointSourceDataCircleAverage : public PointSourceData<MDTraits> using Scalar = typename MDTraits::Scalar; using ShapeValues = typename std::vector<Dune::FieldVector<Scalar, 1> >; - // obtain the type tags of the sub problems - using BulkTypeTag = typename MDTraits::template SubDomain<0>::TypeTag; - using LowDimTypeTag = typename MDTraits::template SubDomain<1>::TypeTag; - - using BulkPrimaryVariables = GetPropType<BulkTypeTag, Properties::PrimaryVariables>; - using LowDimPrimaryVariables = GetPropType<LowDimTypeTag, Properties::PrimaryVariables>; + template<std::size_t id> using SubDomainTypeTag = typename MDTraits::template SubDomain<id>::TypeTag; + template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; + template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; + template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex; + template<std::size_t id> using SolutionVector = GetPropType<SubDomainTypeTag<id>, Properties::SolutionVector>; + template<std::size_t id> using PrimaryVariables = GetPropType<SubDomainTypeTag<id>, Properties::PrimaryVariables>; - using BulkSolutionVector = GetPropType<BulkTypeTag, Properties::SolutionVector>; - using LowDimSolutionVector = GetPropType<LowDimTypeTag, Properties::SolutionVector>; + static constexpr auto bulkIdx = typename MDTraits::template SubDomain<0>::Index(); + static constexpr auto lowDimIdx = typename MDTraits::template SubDomain<1>::Index(); - enum { - bulkIsBox = GetPropType<BulkTypeTag, Properties::GridGeometry>::discMethod == DiscretizationMethod::box, - lowDimIsBox = GetPropType<LowDimTypeTag, Properties::GridGeometry>::discMethod == DiscretizationMethod::box - }; + template<std::size_t id> + static constexpr bool isBox() + { return GridGeometry<id>::discMethod == DiscretizationMethod::box; } public: PointSourceDataCircleAverage() : enableBulkCircleInterpolation_(false) {} - BulkPrimaryVariables interpolateBulk(const BulkSolutionVector& sol) + PrimaryVariables<bulkIdx> interpolateBulk(const SolutionVector<bulkIdx>& sol) const { // bulk interpolation on the circle is only enabled for source in the // lower dimensional domain if we use a circle distributed bulk sources // (see coupling manager circle sources) - BulkPrimaryVariables bulkPriVars(sol[0]); + PrimaryVariables<bulkIdx> bulkPriVars(sol[0]); bulkPriVars = 0.0; if (enableBulkCircleInterpolation_) { // compute the average of the bulk privars over the circle around the integration point // this computes $\bar{p} = \frac{1}{2\pi R} int_0^2*\pi p R \text{d}\theta. - if (bulkIsBox) + if (isBox<bulkIdx>()) { assert(circleCornerIndices_.size() == circleShapeValues_.size()); Scalar weightSum = 0.0; for (std::size_t j = 0; j < circleStencil_.size(); ++j) { - BulkPrimaryVariables priVars(0.0); - const auto& cornerIndices = circleCornerIndices_[circleStencil_[j]]; - const auto& shapeValues = circleShapeValues_[circleStencil_[j]]; - for (std::size_t i = 0; i < cornerIndices.size(); ++i) - for (std::size_t priVarIdx = 0; priVarIdx < priVars.size(); ++priVarIdx) - priVars[priVarIdx] += sol[cornerIndices[i]][priVarIdx]*shapeValues[i]; + PrimaryVariables<bulkIdx> priVars(0.0); + const auto& cornerIndices = *(circleCornerIndices_[j]); + const auto& shapeValues = circleShapeValues_[j]; + for (int i = 0; i < cornerIndices.size(); ++i) + { + const auto& localSol = sol[cornerIndices[i]]; + const auto& shapeValue = shapeValues[i]; + for (int priVarIdx = 0; priVarIdx < PrimaryVariables<bulkIdx>::size(); ++priVarIdx) + priVars[priVarIdx] += localSol[priVarIdx]*shapeValue; + } // multiply with weight and add priVars *= circleIpWeight_[j]; weightSum += circleIpWeight_[j]; @@ -203,9 +208,9 @@ public: else { Scalar weightSum = 0.0; - for (std::size_t j = 0; j < circleStencil_.size(); ++j) + for (int j = 0; j < circleStencil_.size(); ++j) { - for (std::size_t priVarIdx = 0; priVarIdx < bulkPriVars.size(); ++priVarIdx) + for (int priVarIdx = 0; priVarIdx < bulkPriVars.size(); ++priVarIdx) bulkPriVars[priVarIdx] += sol[circleStencil_[j]][priVarIdx]*circleIpWeight_[j]; weightSum += circleIpWeight_[j]; @@ -220,10 +225,10 @@ public: } } - void addCircleInterpolation(const std::unordered_map<std::size_t, std::vector<std::size_t> >& circleCornerIndices, - const std::unordered_map<std::size_t, ShapeValues>& circleShapeValues, + void addCircleInterpolation(const std::vector<const std::vector<GridIndex<bulkIdx>>*>& circleCornerIndices, + const std::vector<ShapeValues>& circleShapeValues, const std::vector<Scalar>& circleIpWeight, - const std::vector<std::size_t>& circleStencil) + const std::vector<GridIndex<bulkIdx>>& circleStencil) { circleCornerIndices_ = circleCornerIndices; circleShapeValues_ = circleShapeValues; @@ -234,23 +239,21 @@ public: } void addCircleInterpolation(const std::vector<Scalar>& circleIpWeight, - const std::vector<std::size_t>& circleStencil) + const std::vector<GridIndex<bulkIdx>>& circleStencil) { circleIpWeight_ = circleIpWeight; circleStencil_ = circleStencil; enableBulkCircleInterpolation_ = true; } - const std::vector<std::size_t>& circleStencil() - { - return circleStencil_; - } + const std::vector<GridIndex<bulkIdx>>& circleStencil() const + { return circleStencil_; } private: - std::unordered_map<std::size_t, std::vector<std::size_t> > circleCornerIndices_; - std::unordered_map<std::size_t, ShapeValues> circleShapeValues_; + std::vector<const std::vector<GridIndex<bulkIdx>>*> circleCornerIndices_; + std::vector<ShapeValues> circleShapeValues_; std::vector<Scalar> circleIpWeight_; - std::vector<std::size_t> circleStencil_; + std::vector<GridIndex<bulkIdx>> circleStencil_; bool enableBulkCircleInterpolation_; };