Line | Branch | Exec | Source |
---|---|---|---|
1 | // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||
2 | // vi: set et ts=4 sw=4 sts=4: | ||
3 | // | ||
4 | // SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup EmbeddedCoupling | ||
10 | * \brief Coupling manager for low-dimensional domains embedded in the bulk domain. | ||
11 | */ | ||
12 | |||
13 | #ifndef DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_AVERAGE_HH | ||
14 | #define DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_AVERAGE_HH | ||
15 | |||
16 | #include <vector> | ||
17 | |||
18 | #include <dune/common/timer.hh> | ||
19 | #include <dune/geometry/quadraturerules.hh> | ||
20 | |||
21 | #include <dumux/common/tag.hh> | ||
22 | #include <dumux/common/properties.hh> | ||
23 | #include <dumux/common/indextraits.hh> | ||
24 | |||
25 | #include <dumux/geometry/distance.hh> | ||
26 | |||
27 | #include <dumux/multidomain/embedded/couplingmanagerbase.hh> | ||
28 | #include <dumux/multidomain/embedded/circlepoints.hh> | ||
29 | #include <dumux/multidomain/embedded/extendedsourcestencil.hh> | ||
30 | #include <dumux/multidomain/embedded/circleaveragepointsourcetraits.hh> | ||
31 | |||
32 | namespace Dumux { | ||
33 | |||
34 | namespace Embedded1d3dCouplingMode { | ||
35 | struct Average : public Utility::Tag<Average> { | ||
36 | static std::string name() { return "average"; } | ||
37 | }; | ||
38 | |||
39 | inline constexpr Average average{}; | ||
40 | } // end namespace Embedded1d3dCouplingMode | ||
41 | |||
42 | // forward declaration | ||
43 | template<class MDTraits, class CouplingMode> | ||
44 | class Embedded1d3dCouplingManager; | ||
45 | |||
46 | /*! | ||
47 | * \ingroup EmbeddedCoupling | ||
48 | * \brief Manages the coupling between bulk elements and lower dimensional elements | ||
49 | * Point sources on each integration point are computed by an AABB tree. | ||
50 | * \note Specialization for coupling method using line sources with 3d quantities averaged on the cylinder surface | ||
51 | */ | ||
52 | template<class MDTraits> | ||
53 | class Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Average> | ||
54 | : public EmbeddedCouplingManagerBase<MDTraits, Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Average>, | ||
55 | CircleAveragePointSourceTraits<MDTraits>> | ||
56 | { | ||
57 | using ThisType = Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Average>; | ||
58 | using ParentType = EmbeddedCouplingManagerBase<MDTraits, ThisType, CircleAveragePointSourceTraits<MDTraits>>; | ||
59 | using Scalar = typename MDTraits::Scalar; | ||
60 | using SolutionVector = typename MDTraits::SolutionVector; | ||
61 | using PointSourceData = typename ParentType::PointSourceTraits::PointSourceData; | ||
62 | |||
63 | static constexpr auto bulkIdx = typename MDTraits::template SubDomain<0>::Index(); | ||
64 | static constexpr auto lowDimIdx = typename MDTraits::template SubDomain<1>::Index(); | ||
65 | |||
66 | // the sub domain type aliases | ||
67 | template<std::size_t id> using SubDomainTypeTag = typename MDTraits::template SubDomain<id>::TypeTag; | ||
68 | template<std::size_t id> using Problem = GetPropType<SubDomainTypeTag<id>, Properties::Problem>; | ||
69 | template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>; | ||
70 | template<std::size_t id> using GridView = typename GridGeometry<id>::GridView; | ||
71 | template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity; | ||
72 | template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex; | ||
73 | |||
74 | using GlobalPosition = typename Element<bulkIdx>::Geometry::GlobalCoordinate; | ||
75 | |||
76 | template<std::size_t id> | ||
77 | static constexpr bool isBox() | ||
78 | { return GridGeometry<id>::discMethod == DiscretizationMethods::box; } | ||
79 | |||
80 | |||
81 | public: | ||
82 | enum { | ||
83 | bulkDim = GridView<bulkIdx>::dimension, | ||
84 | lowDimDim = GridView<lowDimIdx>::dimension, | ||
85 | dimWorld = GridView<bulkIdx>::dimensionworld | ||
86 | }; | ||
87 | |||
88 | static constexpr Embedded1d3dCouplingMode::Average couplingMode{}; | ||
89 | |||
90 |
4/8✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
|
12 | using ParentType::ParentType; |
91 | |||
92 | 12 | void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem, | |
93 | std::shared_ptr<Problem<lowDimIdx>> lowDimProblem, | ||
94 | const SolutionVector& curSol) | ||
95 | { | ||
96 |
3/10✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
24 | ParentType::init(bulkProblem, lowDimProblem, curSol); |
97 | 12 | computeLowDimVolumeFractions(); | |
98 | 12 | } | |
99 | |||
100 | /*! | ||
101 | * \brief extend the jacobian pattern of the diagonal block of domain i | ||
102 | * by those entries that are not already in the uncoupled pattern | ||
103 | * \note Such additional dependencies can arise from the coupling, e.g. if a coupling source | ||
104 | * term depends on a non-local average of a quantity of the same domain | ||
105 | */ | ||
106 | template<std::size_t id, class JacobianPattern> | ||
107 | ✗ | void extendJacobianPattern(Dune::index_constant<id> domainI, JacobianPattern& pattern) const | |
108 | { | ||
109 | ✗ | extendedSourceStencil_.extendJacobianPattern(*this, domainI, pattern); | |
110 | ✗ | } | |
111 | |||
112 | /*! | ||
113 | * \brief evaluate additional derivatives of the element residual of a domain with respect | ||
114 | * to dofs in the same domain that are not in the regular stencil (per default this is not the case) | ||
115 | * \note Such additional dependencies can arise from the coupling, e.g. if a coupling source | ||
116 | * term depends on a non-local average of a quantity of the same domain | ||
117 | * \note This is the same for box and cc | ||
118 | */ | ||
119 | template<std::size_t i, class LocalAssemblerI, class JacobianMatrixDiagBlock, class GridVariables> | ||
120 | ✗ | void evalAdditionalDomainDerivatives(Dune::index_constant<i> domainI, | |
121 | const LocalAssemblerI& localAssemblerI, | ||
122 | const typename LocalAssemblerI::LocalResidual::ElementResidualVector&, | ||
123 | JacobianMatrixDiagBlock& A, | ||
124 | GridVariables& gridVariables) | ||
125 | { | ||
126 | 694028 | extendedSourceStencil_.evalAdditionalDomainDerivatives(*this, domainI, localAssemblerI, A, gridVariables); | |
127 | ✗ | } | |
128 | |||
129 | /* \brief Compute integration point point sources and associated data | ||
130 | * | ||
131 | * This method uses grid glue to intersect the given grids. Over each intersection | ||
132 | * we later need to integrate a source term. This method places point sources | ||
133 | * at each quadrature point and provides the point source with the necessary | ||
134 | * information to compute integrals (quadrature weight and integration element) | ||
135 | * \param order The order of the quadrature rule for integration of sources over an intersection | ||
136 | * \param verbose If the point source computation is verbose | ||
137 | */ | ||
138 | 12 | void computePointSourceData(std::size_t order = 1, bool verbose = false) | |
139 | { | ||
140 | // Initialize the bulk bounding box tree | ||
141 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); |
142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); |
143 | 12 | const auto& bulkTree = bulkGridGeometry.boundingBoxTree(); | |
144 | |||
145 | // initialize the maps | ||
146 | // do some logging and profiling | ||
147 | 12 | Dune::Timer watch; | |
148 | 24 | std::cout << "Initializing the point sources..." << std::endl; | |
149 | |||
150 | // clear all internal members like pointsource vectors and stencils | ||
151 | // initializes the point source id counter | ||
152 | 12 | this->clear(); | |
153 | 12 | extendedSourceStencil_.clear(); | |
154 | |||
155 | // precompute the vertex indices for efficiency | ||
156 | 12 | this->precomputeVertexIndices(bulkIdx); | |
157 | 12 | this->precomputeVertexIndices(lowDimIdx); | |
158 | |||
159 | // intersect the bounding box trees | ||
160 | 12 | this->glueGrids(); | |
161 | |||
162 | // iterate over all intersection and add point sources | ||
163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | const auto& lowDimProblem = this->problem(lowDimIdx); |
164 |
4/4✓ Branch 0 taken 9429 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 9429 times.
✓ Branch 3 taken 12 times.
|
9465 | for (const auto& is : intersections(this->glue())) |
165 | { | ||
166 | // all inside elements are identical... | ||
167 | 9429 | const auto& lowDimElement = is.targetEntity(0); | |
168 | 18858 | const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(lowDimElement); | |
169 | |||
170 | // get the intersection geometry | ||
171 | 9429 | const auto intersectionGeometry = is.geometry(); | |
172 | // get the Gaussian quadrature rule for the local intersection | ||
173 | 9429 | const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(intersectionGeometry.type(), order); | |
174 | |||
175 | // apply the Gaussian quadrature rule and define point sources at each quadrature point | ||
176 | // note that the approximation is not optimal if | ||
177 | // (a) the one-dimensional elements are too large, | ||
178 | // (b) whenever a one-dimensional element is split between two or more elements, | ||
179 | // (c) when gradients of important quantities in the three-dimensional domain are large. | ||
180 | |||
181 | // iterate over all quadrature points | ||
182 |
4/4✓ Branch 0 taken 9620 times.
✓ Branch 1 taken 9429 times.
✓ Branch 2 taken 9620 times.
✓ Branch 3 taken 9429 times.
|
37907 | for (auto&& qp : quad) |
183 | { | ||
184 | // global position of the quadrature point | ||
185 | 19240 | const auto globalPos = intersectionGeometry.global(qp.position()); | |
186 | |||
187 |
1/4✓ Branch 1 taken 9620 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
19240 | const auto bulkElementIndices = intersectingEntities(globalPos, bulkTree); |
188 | |||
189 | // do not add a point source if the qp is outside of the 3d grid | ||
190 | // this is equivalent to having a source of zero for that qp | ||
191 |
2/4✓ Branch 0 taken 9620 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9620 times.
✗ Branch 3 not taken.
|
19240 | if (bulkElementIndices.empty()) |
192 | ✗ | continue; | |
193 | |||
194 | ////////////////////////////////////////////////////////// | ||
195 | // get circle average connectivity and interpolation data | ||
196 | ////////////////////////////////////////////////////////// | ||
197 | |||
198 |
4/6✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9608 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
|
9620 | static const auto numIp = getParam<int>("MixedDimension.NumCircleSegments"); |
199 | 18858 | const auto radius = lowDimProblem.spatialParams().radius(lowDimElementIdx); | |
200 | 28860 | const auto normal = intersectionGeometry.corner(1)-intersectionGeometry.corner(0); | |
201 | 9620 | const auto circleAvgWeight = 2*M_PI*radius/numIp; | |
202 |
1/2✓ Branch 1 taken 9620 times.
✗ Branch 2 not taken.
|
9620 | const auto integrationElement = intersectionGeometry.integrationElement(qp.position()); |
203 | 9620 | const auto qpweight = qp.weight(); | |
204 | |||
205 |
2/6✓ Branch 1 taken 9620 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9620 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
19240 | const auto circlePoints = EmbeddedCoupling::circlePoints(globalPos, normal, radius, numIp); |
206 |
4/10✓ Branch 1 taken 9620 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9620 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9620 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 9620 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
38480 | std::vector<Scalar> circleIpWeight; circleIpWeight.reserve(circlePoints.size()); |
207 |
4/10✓ Branch 1 taken 9620 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9620 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 9620 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 9620 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
38480 | std::vector<GridIndex<bulkIdx>> circleStencil; circleStencil.reserve(circlePoints.size()); |
208 | |||
209 | // for box | ||
210 |
1/4✓ Branch 0 taken 9620 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
19240 | std::vector<const std::vector<GridIndex<bulkIdx>>*> circleCornerIndices; |
211 | using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >; | ||
212 |
1/2✓ Branch 1 taken 9620 times.
✗ Branch 2 not taken.
|
19240 | std::vector<ShapeValues> circleShapeValues; |
213 | |||
214 | // go over all points of the average operator | ||
215 | 9620 | int insideCirclePoints = 0; | |
216 |
4/4✓ Branch 0 taken 218902 times.
✓ Branch 1 taken 9620 times.
✓ Branch 2 taken 218902 times.
✓ Branch 3 taken 9620 times.
|
228522 | for (int k = 0; k < circlePoints.size(); ++k) |
217 | { | ||
218 |
3/6✓ Branch 1 taken 218902 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 218902 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 217475 times.
✗ Branch 7 not taken.
|
872754 | const auto circleBulkElementIndices = intersectingEntities(circlePoints[k], bulkTree); |
219 |
4/4✓ Branch 0 taken 1427 times.
✓ Branch 1 taken 217475 times.
✓ Branch 2 taken 1427 times.
✓ Branch 3 taken 217475 times.
|
437804 | if (circleBulkElementIndices.empty()) |
220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1427 times.
|
1427 | continue; |
221 | |||
222 | 217475 | ++insideCirclePoints; | |
223 | 217475 | const auto localCircleAvgWeight = circleAvgWeight / circleBulkElementIndices.size(); | |
224 |
4/4✓ Branch 0 taken 217477 times.
✓ Branch 1 taken 217475 times.
✓ Branch 2 taken 217477 times.
✓ Branch 3 taken 217475 times.
|
929699 | for (const auto bulkElementIdx : circleBulkElementIndices) |
225 | { | ||
226 |
1/4✓ Branch 1 taken 217477 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
217477 | circleStencil.push_back(bulkElementIdx); |
227 |
1/2✓ Branch 1 taken 217477 times.
✗ Branch 2 not taken.
|
217477 | circleIpWeight.push_back(localCircleAvgWeight); |
228 | |||
229 | // precompute interpolation data for box scheme for each cut bulk element | ||
230 | if constexpr (isBox<bulkIdx>()) | ||
231 | { | ||
232 |
1/2✓ Branch 1 taken 59797 times.
✗ Branch 2 not taken.
|
59797 | const auto bulkElement = bulkGridGeometry.element(bulkElementIdx); |
233 |
2/6✓ Branch 1 taken 59797 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59797 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
119594 | circleCornerIndices.push_back(&(this->vertexIndices(bulkIdx, bulkElementIdx))); |
234 | |||
235 | // evaluate shape functions at the integration point | ||
236 | 59797 | const auto bulkGeometry = bulkElement.geometry(); | |
237 |
2/6✓ Branch 1 taken 59797 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 59797 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
119594 | ShapeValues shapeValues; |
238 |
2/4✓ Branch 1 taken 59797 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59797 times.
✗ Branch 5 not taken.
|
119594 | this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, circlePoints[k], shapeValues); |
239 |
1/2✓ Branch 1 taken 59797 times.
✗ Branch 2 not taken.
|
59797 | circleShapeValues.emplace_back(std::move(shapeValues)); |
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
244 | // if the circle stencil is empty (that is the circle is entirely outside the domain) | ||
245 | // we do not add a (zero) point source | ||
246 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 9620 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9620 times.
|
19240 | if (circleStencil.empty()) |
247 | ✗ | continue; | |
248 | |||
249 | // export low dim circle stencil | ||
250 | if constexpr (isBox<bulkIdx>()) | ||
251 | { | ||
252 | // we insert all vertices and make it unique later | ||
253 |
4/4✓ Branch 0 taken 59797 times.
✓ Branch 1 taken 2242 times.
✓ Branch 2 taken 59797 times.
✓ Branch 3 taken 2242 times.
|
126320 | for (const auto& vertices : circleCornerIndices) |
254 | { | ||
255 |
9/18✓ Branch 1 taken 59797 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59797 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 59797 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 59797 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 59797 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 59797 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 59797 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 59797 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 59797 times.
✗ Branch 26 not taken.
|
119594 | this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(), |
256 | vertices->begin(), vertices->end()); | ||
257 | |||
258 | } | ||
259 | } | ||
260 | else | ||
261 | { | ||
262 |
9/18✓ Branch 1 taken 7378 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7378 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7378 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 7378 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 7378 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 7378 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 7378 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 7378 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 7378 times.
✗ Branch 26 not taken.
|
14756 | this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(), |
263 | circleStencil.begin(), circleStencil.end()); | ||
264 | } | ||
265 | |||
266 | // surface fraction that is inside the domain (only different than 1.0 on the boundary) | ||
267 | 9620 | const auto surfaceFraction = Scalar(insideCirclePoints)/Scalar(circlePoints.size()); | |
268 | |||
269 | // loop over the bulk elements at the integration points (usually one except when it is on a face or edge or vertex) | ||
270 |
4/4✓ Branch 0 taken 10310 times.
✓ Branch 1 taken 9620 times.
✓ Branch 2 taken 10310 times.
✓ Branch 3 taken 9620 times.
|
39170 | for (auto bulkElementIdx : bulkElementIndices) |
271 | { | ||
272 | 10310 | const auto id = this->idCounter_++; | |
273 | |||
274 |
2/4✓ Branch 1 taken 10310 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10310 times.
✗ Branch 5 not taken.
|
20620 | this->pointSources(bulkIdx).emplace_back(globalPos, id, qpweight, integrationElement*surfaceFraction, bulkElementIdx); |
275 |
4/8✓ Branch 1 taken 10310 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10310 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10310 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10310 times.
✗ Branch 11 not taken.
|
41240 | this->pointSources(bulkIdx).back().setEmbeddings(bulkElementIndices.size()); |
276 |
2/4✓ Branch 1 taken 10310 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10310 times.
✗ Branch 5 not taken.
|
20620 | this->pointSources(lowDimIdx).emplace_back(globalPos, id, qpweight, integrationElement*surfaceFraction, lowDimElementIdx); |
277 |
4/8✓ Branch 1 taken 10310 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10310 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10310 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10310 times.
✗ Branch 11 not taken.
|
41240 | this->pointSources(lowDimIdx).back().setEmbeddings(bulkElementIndices.size()); |
278 | |||
279 | // pre compute additional data used for the evaluation of | ||
280 | // the actual solution dependent source term | ||
281 |
1/2✓ Branch 1 taken 10310 times.
✗ Branch 2 not taken.
|
12552 | PointSourceData psData; |
282 | |||
283 | if constexpr (isBox<lowDimIdx>()) | ||
284 | { | ||
285 |
1/4✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
236 | ShapeValues shapeValues; |
286 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | this->getShapeValues(lowDimIdx, lowDimGridGeometry, intersectionGeometry, globalPos, shapeValues); |
287 |
3/6✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 236 times.
✗ Branch 7 not taken.
|
708 | psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx); |
288 | } | ||
289 | else | ||
290 | { | ||
291 |
1/2✓ Branch 1 taken 10074 times.
✗ Branch 2 not taken.
|
10074 | psData.addLowDimInterpolation(lowDimElementIdx); |
292 | } | ||
293 | |||
294 | // add data needed to compute integral over the circle | ||
295 | if constexpr (isBox<bulkIdx>()) | ||
296 | { | ||
297 |
1/2✓ Branch 1 taken 2242 times.
✗ Branch 2 not taken.
|
2242 | psData.addCircleInterpolation(circleCornerIndices, circleShapeValues, circleIpWeight, circleStencil); |
298 | |||
299 |
1/2✓ Branch 1 taken 2242 times.
✗ Branch 2 not taken.
|
2242 | const auto bulkGeometry = bulkGridGeometry.element(bulkElementIdx).geometry(); |
300 |
1/4✓ Branch 1 taken 2242 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
2242 | ShapeValues shapeValues; |
301 |
1/2✓ Branch 1 taken 2242 times.
✗ Branch 2 not taken.
|
2242 | this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, globalPos, shapeValues); |
302 |
3/6✓ Branch 1 taken 2242 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2242 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2242 times.
✗ Branch 7 not taken.
|
6726 | psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx); |
303 | } | ||
304 | else | ||
305 | { | ||
306 |
1/2✓ Branch 1 taken 8068 times.
✗ Branch 2 not taken.
|
8068 | psData.addCircleInterpolation(circleIpWeight, circleStencil); |
307 |
1/2✓ Branch 1 taken 8068 times.
✗ Branch 2 not taken.
|
8068 | psData.addBulkInterpolation(bulkElementIdx); |
308 | } | ||
309 | |||
310 | // publish point source data in the global vector | ||
311 |
2/4✓ Branch 1 taken 10310 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10310 times.
✗ Branch 5 not taken.
|
20620 | this->pointSourceData().emplace_back(std::move(psData)); |
312 | |||
313 | // mean distance to outside element for source correction schemes | ||
314 |
2/4✓ Branch 1 taken 10310 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2185 times.
✗ Branch 5 not taken.
|
10310 | const auto outsideGeometry = bulkGridGeometry.element(bulkElementIdx).geometry(); |
315 |
3/6✓ Branch 1 taken 10310 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10310 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10310 times.
✗ Branch 8 not taken.
|
20620 | this->averageDistanceToBulkCell().push_back(averageDistancePointGeometry(globalPos, outsideGeometry)); |
316 | |||
317 | // export the bulk coupling stencil | ||
318 | if constexpr (isBox<lowDimIdx>()) | ||
319 | { | ||
320 |
7/14✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 236 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 236 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 236 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 236 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 236 times.
✗ Branch 20 not taken.
|
472 | this->couplingStencils(bulkIdx)[bulkElementIdx].insert(this->couplingStencils(bulkIdx)[bulkElementIdx].end(), |
321 |
2/4✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236 times.
✗ Branch 5 not taken.
|
472 | this->vertexIndices(lowDimIdx, lowDimElementIdx).begin(), |
322 |
2/4✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 236 times.
✗ Branch 5 not taken.
|
472 | this->vertexIndices(lowDimIdx, lowDimElementIdx).end()); |
323 | |||
324 | } | ||
325 | else | ||
326 | { | ||
327 |
3/6✓ Branch 1 taken 10074 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10074 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10074 times.
✗ Branch 8 not taken.
|
20148 | this->couplingStencils(bulkIdx)[bulkElementIdx].push_back(lowDimElementIdx); |
328 | } | ||
329 | |||
330 | // export bulk circle stencil | ||
331 | if constexpr (isBox<bulkIdx>()) | ||
332 | { | ||
333 | // we insert all vertices and make it unique later | ||
334 |
4/4✓ Branch 0 taken 59797 times.
✓ Branch 1 taken 2242 times.
✓ Branch 2 taken 59797 times.
✓ Branch 3 taken 2242 times.
|
126320 | for (const auto& vertices : circleCornerIndices) |
335 | { | ||
336 |
9/18✓ Branch 1 taken 59797 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 59797 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 59797 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 59797 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 59797 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 59797 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 59797 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 59797 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 59797 times.
✗ Branch 26 not taken.
|
119594 | extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(), |
337 | vertices->begin(), vertices->end()); | ||
338 | |||
339 | } | ||
340 | } | ||
341 | else | ||
342 | { | ||
343 |
9/18✓ Branch 1 taken 8068 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8068 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 8068 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 8068 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 8068 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 8068 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 8068 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 8068 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 8068 times.
✗ Branch 26 not taken.
|
16136 | extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(), |
344 | circleStencil.begin(), circleStencil.end()); | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | |||
350 | // make the circle stencil unique (for source derivatives) | ||
351 |
2/2✓ Branch 0 taken 2384 times.
✓ Branch 1 taken 12 times.
|
2432 | for (auto&& stencil : extendedSourceStencil_.stencil()) |
352 | { | ||
353 | 7152 | std::sort(stencil.second.begin(), stencil.second.end()); | |
354 | 11920 | stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end()); | |
355 | |||
356 | // remove the vertices element (box) | ||
357 | if constexpr (isBox<bulkIdx>()) | ||
358 | { | ||
359 | 283 | const auto& indices = this->vertexIndices(bulkIdx, stencil.first); | |
360 | 1415 | stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(), | |
361 | 30728 | [&](auto i){ return std::find(indices.begin(), indices.end(), i) != indices.end(); }), | |
362 | stencil.second.end()); | ||
363 | } | ||
364 | // remove the own element (cell-centered) | ||
365 | else | ||
366 | { | ||
367 | 10505 | stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(), | |
368 |
8/10✓ Branch 0 taken 146 times.
✓ Branch 1 taken 2802 times.
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 257 times.
✓ Branch 4 taken 410 times.
✓ Branch 5 taken 337 times.
✓ Branch 6 taken 478 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1968 times.
✗ Branch 9 not taken.
|
6505 | [&](auto i){ return i == stencil.first; }), |
369 | stencil.second.end()); | ||
370 | } | ||
371 | } | ||
372 | |||
373 | // make stencils unique | ||
374 | using namespace Dune::Hybrid; | ||
375 | 108 | forEach(integralRange(Dune::index_constant<2>{}), [&](const auto domainIdx) | |
376 | { | ||
377 |
4/4✓ Branch 0 taken 7104 times.
✓ Branch 1 taken 12 times.
✓ Branch 3 taken 2384 times.
✓ Branch 4 taken 12 times.
|
9584 | for (auto&& stencil : this->couplingStencils(domainIdx)) |
378 | { | ||
379 | 28464 | std::sort(stencil.second.begin(), stencil.second.end()); | |
380 | 47440 | stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end()); | |
381 | } | ||
382 | }); | ||
383 | |||
384 | 36 | std::cout << "took " << watch.elapsed() << " seconds." << std::endl; | |
385 | 12 | } | |
386 | |||
387 | //! Compute the low dim volume fraction in the bulk domain cells | ||
388 | 12 | void computeLowDimVolumeFractions() | |
389 | { | ||
390 | // resize the storage vector | ||
391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0)); |
392 | // get references to the grid geometries | ||
393 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry(); |
394 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry(); |
395 | |||
396 | // compute the low dim volume fractions | ||
397 |
4/4✓ Branch 0 taken 9429 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 9429 times.
✓ Branch 3 taken 12 times.
|
9465 | for (const auto& is : intersections(this->glue())) |
398 | { | ||
399 | // all inside elements are identical... | ||
400 | 9429 | const auto& inside = is.targetEntity(0); | |
401 | 9429 | const auto intersectionGeometry = is.geometry(); | |
402 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2873 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2873 times.
|
18858 | const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside); |
403 | |||
404 | // compute the volume the low-dim domain occupies in the bulk domain if it were full-dimensional | ||
405 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9429 times.
|
9429 | const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx); |
406 |
4/4✓ Branch 0 taken 9774 times.
✓ Branch 1 taken 9429 times.
✓ Branch 2 taken 9774 times.
✓ Branch 3 taken 9429 times.
|
28977 | for (int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx) |
407 | { | ||
408 | 9774 | const auto& outside = is.domainEntity(outsideIdx); | |
409 | 19548 | const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside); | |
410 | 29322 | lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius; | |
411 | } | ||
412 | } | ||
413 | 12 | } | |
414 | |||
415 | /*! | ||
416 | * \brief Methods to be accessed by the subproblems | ||
417 | */ | ||
418 | // \{ | ||
419 | |||
420 | //! Return a reference to the bulk problem | ||
421 | 5520620 | Scalar radius(std::size_t id) const | |
422 | { | ||
423 |
6/12✗ Branch 0 not taken.
✓ Branch 1 taken 5520620 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5520620 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 81980 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 81980 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 91576 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 91576 times.
|
11388352 | const auto& data = this->pointSourceData()[id]; |
424 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 5520620 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 81980 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 91576 times.
|
5694176 | return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx()); |
425 | } | ||
426 | |||
427 | //! The volume the lower dimensional domain occupies in the bulk domain element | ||
428 | // For one-dimensional low dim domain we assume radial tubes | ||
429 | Scalar lowDimVolume(const Element<bulkIdx>& element) const | ||
430 | { | ||
431 | const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element); | ||
432 | return lowDimVolumeInBulkElement_[eIdx]; | ||
433 | } | ||
434 | |||
435 | //! The volume fraction the lower dimensional domain occupies in the bulk domain element | ||
436 | // For one-dimensional low dim domain we assume radial tubes | ||
437 | Scalar lowDimVolumeFraction(const Element<bulkIdx>& element) const | ||
438 | { | ||
439 | const auto totalVolume = element.geometry().volume(); | ||
440 | return lowDimVolume(element) / totalVolume; | ||
441 | } | ||
442 | |||
443 | // \} | ||
444 | |||
445 | /*! | ||
446 | * \brief Extended source stencil (for the bulk domain) | ||
447 | */ | ||
448 | const typename ParentType::template CouplingStencils<bulkIdx>::mapped_type& | ||
449 | 673744 | extendedSourceStencil(std::size_t eIdx) const | |
450 | { | ||
451 | 673744 | const auto& sourceStencils = extendedSourceStencil_.stencil(); | |
452 |
4/4✓ Branch 1 taken 4768 times.
✓ Branch 2 taken 668976 times.
✓ Branch 3 taken 4768 times.
✓ Branch 4 taken 668976 times.
|
2021232 | if (auto stencil = sourceStencils.find(eIdx); stencil != sourceStencils.end()) |
453 | 9536 | return stencil->second; | |
454 | |||
455 | 1337952 | return this->emptyStencil(bulkIdx); | |
456 | } | ||
457 | |||
458 | private: | ||
459 | //! the extended source stencil object | ||
460 | EmbeddedCoupling::ExtendedSourceStencil<ThisType> extendedSourceStencil_; | ||
461 | |||
462 | //! vector for the volume fraction of the lowdim domain in the bulk domain cells | ||
463 | std::vector<Scalar> lowDimVolumeInBulkElement_; | ||
464 | }; | ||
465 | |||
466 | //! we support multithreaded assembly | ||
467 | template<class MDTraits> | ||
468 | struct CouplingManagerSupportsMultithreadedAssembly<Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Average>> | ||
469 | : public std::true_type {}; | ||
470 | |||
471 | } // end namespace Dumux | ||
472 | |||
473 | #endif | ||
474 |