Loading [MathJax]/extensions/tex2jax.js
3.3.0
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
couplingmanager1d3d_surface.hh
Go to the documentation of this file.
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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
25#ifndef DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_SURFACE_HH
26#define DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_SURFACE_HH
27
28#include <vector>
29
30#include <dune/common/timer.hh>
31#include <dune/geometry/quadraturerules.hh>
32
33#include <dumux/common/tag.hh>
36
40
41namespace Dumux {
42
43namespace Embedded1d3dCouplingMode {
44struct Surface : public Utility::Tag<Surface> {
45 static std::string name() { return "surface"; }
46
47 [[deprecated("Comparison with enum is deprecated. Removed after 3.3. Use tags.")]]
49 [[deprecated("Comparison with enum is deprecated. Removed after 3.3. Use tags.")]]
51 [[deprecated("Comparison with enum is deprecated. Removed after 3.3. Use tags.")]]
53 [[deprecated("Comparison with enum is deprecated. Removed after 3.3. Use tags.")]]
55};
56
57inline constexpr Surface surface{};
58} // end namespace Embedded1d3dCouplingMode
59
60// forward declaration
61template<class MDTraits, class CouplingMode>
62class Embedded1d3dCouplingManager;
63
71template<class MDTraits>
72class Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Surface>
73: public EmbeddedCouplingManagerBase<MDTraits, Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Surface>,
74 CircleAveragePointSourceTraits<MDTraits>>
75{
78 using Scalar = typename MDTraits::Scalar;
79 using SolutionVector = typename MDTraits::SolutionVector;
80 using PointSourceData = typename ParentType::PointSourceTraits::PointSourceData;
81
82 static constexpr auto bulkIdx = typename MDTraits::template SubDomain<0>::Index();
83 static constexpr auto lowDimIdx = typename MDTraits::template SubDomain<1>::Index();
84
85 // the sub domain type aliases
86 template<std::size_t id> using SubDomainTypeTag = typename MDTraits::template SubDomain<id>::TypeTag;
87 template<std::size_t id> using Problem = GetPropType<SubDomainTypeTag<id>, Properties::Problem>;
88 template<std::size_t id> using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>;
89 template<std::size_t id> using GridView = typename GridGeometry<id>::GridView;
90 template<std::size_t id> using Element = typename GridView<id>::template Codim<0>::Entity;
91 template<std::size_t id> using GridIndex = typename IndexTraits<GridView<id>>::GridIndex;
92
93 using GlobalPosition = typename Element<bulkIdx>::Geometry::GlobalCoordinate;
94
95 template<std::size_t id>
96 static constexpr bool isBox()
97 { return GridGeometry<id>::discMethod == DiscretizationMethod::box; }
98
99 enum {
100 bulkDim = GridView<bulkIdx>::dimension,
101 lowDimDim = GridView<lowDimIdx>::dimension,
102 dimWorld = GridView<bulkIdx>::dimensionworld
103 };
104public:
105 static constexpr Embedded1d3dCouplingMode::Surface couplingMode{};
106
107 using ParentType::ParentType;
108
109 void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem,
110 std::shared_ptr<Problem<lowDimIdx>> lowDimProblem,
111 const SolutionVector& curSol)
112 {
113 ParentType::init(bulkProblem, lowDimProblem, curSol);
114 computeLowDimVolumeFractions();
115 }
116
123 template<std::size_t id, class JacobianPattern>
124 void extendJacobianPattern(Dune::index_constant<id> domainI, JacobianPattern& pattern) const
125 {
126 extendedSourceStencil_.extendJacobianPattern(*this, domainI, pattern);
127 }
128
136 template<std::size_t i, class LocalAssemblerI, class JacobianMatrixDiagBlock, class GridVariables>
137 void evalAdditionalDomainDerivatives(Dune::index_constant<i> domainI,
138 const LocalAssemblerI& localAssemblerI,
139 const typename LocalAssemblerI::LocalResidual::ElementResidualVector&,
140 JacobianMatrixDiagBlock& A,
141 GridVariables& gridVariables)
142 {
143 extendedSourceStencil_.evalAdditionalDomainDerivatives(*this, domainI, localAssemblerI, this->curSol(), A, gridVariables);
144 }
145
146 /* \brief Compute integration point point sources and associated data
147 *
148 * This method uses grid glue to intersect the given grids. Over each intersection
149 * we later need to integrate a source term. This method places point sources
150 * at each quadrature point and provides the point source with the necessary
151 * information to compute integrals (quadrature weight and integration element)
152 * \param order The order of the quadrature rule for integration of sources over an intersection
153 * \param verbose If the point source computation is verbose
154 */
155 void computePointSourceData(std::size_t order = 1, bool verbose = false)
156 {
157 // if we use the circle average as the 3D values or a point evaluation
158 static const bool useCircleAverage = getParam<bool>("MixedDimension.UseCircleAverage", true);
159
160 // Initialize the bulk bounding box tree
161 const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry();
162 const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry();
163 const auto& bulkTree = bulkGridGeometry.boundingBoxTree();
164
165 // initialize the maps
166 // do some logging and profiling
167 Dune::Timer watch;
168 std::cout << "Initializing the point sources..." << std::endl;
169
170 // clear all internal members like pointsource vectors and stencils
171 // initializes the point source id counter
172 this->clear();
173 extendedSourceStencil_.stencil().clear();
174
175 // precompute the vertex indices for efficiency
176 this->precomputeVertexIndices(bulkIdx);
177 this->precomputeVertexIndices(lowDimIdx);
178
179 // intersect the bounding box trees
180 this->glueGrids();
181
182 // iterate over all intersection and add point sources
183 const auto& lowDimProblem = this->problem(lowDimIdx);
184 for (const auto& is : intersections(this->glue()))
185 {
186 // all inside elements are identical...
187 const auto& lowDimElement = is.targetEntity(0);
188 const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(lowDimElement);
189
190 // get the intersection geometry
191 const auto intersectionGeometry = is.geometry();
192 // get the Gaussian quadrature rule for the local intersection
193 const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(intersectionGeometry.type(), order);
194
195 // apply the Gaussian quadrature rule and define point sources at each quadrature point
196 // note that the approximation is not optimal if
197 // (a) the one-dimensional elements are too large,
198 // (b) whenever a one-dimensional element is split between two or more elements,
199 // (c) when gradients of important quantities in the three-dimensional domain are large.
200
201 // iterate over all quadrature points
202 for (auto&& qp : quad)
203 {
204 // global position of the quadrature point
205 const auto globalPos = intersectionGeometry.global(qp.position());
206
207 const auto bulkElementIndices = intersectingEntities(globalPos, bulkTree);
208
209 // do not add a point source if the qp is outside of the 3d grid
210 // this is equivalent to having a source of zero for that qp
211 if (bulkElementIndices.empty())
212 continue;
213
215 // get points on the cylinder surface at the integration point
217
218 static const auto numIp = getParam<int>("MixedDimension.NumCircleSegments");
219 const auto radius = lowDimProblem.spatialParams().radius(lowDimElementIdx);
220 const auto normal = intersectionGeometry.corner(1)-intersectionGeometry.corner(0);
221 const auto integrationElement = intersectionGeometry.integrationElement(qp.position())*2*M_PI*radius/Scalar(numIp);
222 const auto qpweight = qp.weight()/(2*M_PI*radius);
223 const auto circleAvgWeight = 2*M_PI*radius/numIp;
224
225 const auto circlePoints = EmbeddedCoupling::circlePoints(globalPos, normal, radius, numIp);
226 std::vector<std::vector<std::size_t>> circleBulkElementIndices(circlePoints.size());
227 std::vector<Scalar> circleIpWeight; circleIpWeight.reserve(circlePoints.size());
228 std::vector<GridIndex<bulkIdx>> circleStencil; circleStencil.reserve(circlePoints.size());
229 // for box
230 std::vector<const std::vector<GridIndex<bulkIdx>>*> circleCornerIndices;
231 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
232 std::vector<ShapeValues> circleShapeValues;
233
234 // go over all points of the average operator
235 for (int k = 0; k < circlePoints.size(); ++k)
236 {
237 circleBulkElementIndices[k] = intersectingEntities(circlePoints[k], bulkTree);
238 if (circleBulkElementIndices[k].empty())
239 continue;
240
241 const auto localCircleAvgWeight = circleAvgWeight / circleBulkElementIndices[k].size();
242 for (const auto bulkElementIdx : circleBulkElementIndices[k])
243 {
244 circleStencil.push_back(bulkElementIdx);
245 circleIpWeight.push_back(localCircleAvgWeight);
246
247 // precompute interpolation data for box scheme for each cut bulk element
248 if constexpr (isBox<bulkIdx>())
249 {
250 const auto bulkElement = bulkGridGeometry.element(bulkElementIdx);
251 circleCornerIndices.push_back(&(this->vertexIndices(bulkIdx, bulkElementIdx)));
252
253 // evaluate shape functions at the integration point
254 const auto bulkGeometry = bulkElement.geometry();
255 ShapeValues shapeValues;
256 this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, circlePoints[k], shapeValues);
257 circleShapeValues.emplace_back(std::move(shapeValues));
258 }
259 }
260 }
261
262 // export low dim circle stencil
263 if constexpr (isBox<bulkIdx>())
264 {
265 // we insert all vertices and make it unique later
266 for (const auto& vertices : circleCornerIndices)
267 {
268 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
269 vertices->begin(), vertices->end());
270
271 }
272 }
273 else
274 {
275 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
276 circleStencil.begin(), circleStencil.end());
277 }
278
279 for (int k = 0; k < circlePoints.size(); ++k)
280 {
281 const auto& circlePos = circlePoints[k];
282
283 // find bulk elements intersection with the circle elements
284 if (circleBulkElementIndices[k].empty())
285 continue;
286
287 // loop over the bulk elements at the integration points (usually one except when it is on a face or edge or vertex)
288 // and add a point source at every point on the circle
289 for (const auto bulkElementIdx : circleBulkElementIndices[k])
290 {
291 const auto id = this->idCounter_++;
292
293 this->pointSources(bulkIdx).emplace_back(circlePos, id, qpweight, integrationElement, bulkElementIdx);
294 this->pointSources(bulkIdx).back().setEmbeddings(circleBulkElementIndices[k].size());
295 this->pointSources(lowDimIdx).emplace_back(globalPos, id, qpweight, integrationElement, lowDimElementIdx);
296 this->pointSources(lowDimIdx).back().setEmbeddings(circleBulkElementIndices[k].size());
297
298 // pre compute additional data used for the evaluation of
299 // the actual solution dependent source term
300 PointSourceData psData;
301
302 if constexpr (isBox<lowDimIdx>())
303 {
304 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
305 ShapeValues shapeValues;
306 this->getShapeValues(lowDimIdx, lowDimGridGeometry, intersectionGeometry, globalPos, shapeValues);
307 psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx);
308 }
309 else
310 {
311 psData.addLowDimInterpolation(lowDimElementIdx);
312 }
313
314 // add data needed to compute integral over the circle
315 if constexpr (isBox<bulkIdx>())
316 {
317 if (useCircleAverage)
318 psData.addCircleInterpolation(circleCornerIndices, circleShapeValues, circleIpWeight, circleStencil);
319
320 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
321 const auto bulkGeometry = bulkGridGeometry.element(bulkElementIdx).geometry();
322 ShapeValues shapeValues;
323 this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, circlePos, shapeValues);
324 psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx);
325 }
326 else
327 {
328 if (useCircleAverage)
329 psData.addCircleInterpolation(circleIpWeight, circleStencil);
330
331 psData.addBulkInterpolation(bulkElementIdx);
332 }
333
334 // publish point source data in the global vector
335 this->pointSourceData().emplace_back(std::move(psData));
336
337 // export the bulk coupling stencil
338 // we insert all vertices / elements and make it unique later
339 if constexpr (isBox<lowDimIdx>())
340 {
341 const auto& vertices = this->vertexIndices(lowDimIdx, lowDimElementIdx);
342 this->couplingStencils(bulkIdx)[bulkElementIdx].insert(this->couplingStencils(bulkIdx)[bulkElementIdx].end(),
343 vertices.begin(), vertices.end());
344
345 }
346 else
347 {
348 this->couplingStencils(bulkIdx)[bulkElementIdx].push_back(lowDimElementIdx);
349 }
350
351 // export bulk circle stencil (only needed for circle average)
352 if (useCircleAverage)
353 {
354 if constexpr (isBox<bulkIdx>())
355 {
356 // we insert all vertices and make it unique later
357 for (const auto& vertices : circleCornerIndices)
358 {
359 extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(),
360 vertices->begin(), vertices->end());
361
362 }
363 }
364 else
365 {
366 extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(),
367 circleStencil.begin(), circleStencil.end());
368 }
369 }
370 }
371 }
372 }
373 }
374
375 // make the circle stencil unique (for source derivatives)
376 for (auto&& stencil : extendedSourceStencil_.stencil())
377 {
378 std::sort(stencil.second.begin(), stencil.second.end());
379 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
380
381 // remove the vertices element (box)
382 if constexpr (isBox<bulkIdx>())
383 {
384 const auto& indices = this->vertexIndices(bulkIdx, stencil.first);
385 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
386 [&](auto i){ return std::find(indices.begin(), indices.end(), i) != indices.end(); }),
387 stencil.second.end());
388 }
389 // remove the own element (cell-centered)
390 else
391 {
392 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
393 [&](auto i){ return i == stencil.first; }),
394 stencil.second.end());
395 }
396 }
397
398 // make stencils unique
399 using namespace Dune::Hybrid;
400 forEach(integralRange(Dune::index_constant<2>{}), [&](const auto domainIdx)
401 {
402 for (auto&& stencil : this->couplingStencils(domainIdx))
403 {
404 std::sort(stencil.second.begin(), stencil.second.end());
405 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
406 }
407 });
408
409 std::cout << "took " << watch.elapsed() << " seconds." << std::endl;
410 }
411
414 {
415 // resize the storage vector
416 lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0));
417 // get references to the grid geometries
418 const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry();
419 const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry();
420
421 // compute the low dim volume fractions
422 for (const auto& is : intersections(this->glue()))
423 {
424 // all inside elements are identical...
425 const auto& inside = is.targetEntity(0);
426 const auto intersectionGeometry = is.geometry();
427 const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside);
428
429 // compute the volume the low-dim domain occupies in the bulk domain if it were full-dimensional
430 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
431 for (int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
432 {
433 const auto& outside = is.domainEntity(outsideIdx);
434 const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside);
435 lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius;
436 }
437 }
438 }
439
443 // \{
444
446 Scalar radius(std::size_t id) const
447 {
448 const auto& data = this->pointSourceData()[id];
449 return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
450 }
451
453 // For one-dimensional low dim domain we assume radial tubes
454 Scalar lowDimVolume(const Element<bulkIdx>& element) const
455 {
456 const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
457 return lowDimVolumeInBulkElement_[eIdx];
458 }
459
461 // For one-dimensional low dim domain we assume radial tubes
462 Scalar lowDimVolumeFraction(const Element<bulkIdx>& element) const
463 {
464 const auto totalVolume = element.geometry().volume();
465 return lowDimVolume(element) / totalVolume;
466 }
467
468 // \}
469
470private:
473
475 std::vector<Scalar> lowDimVolumeInBulkElement_;
476};
477
478} // end namespace Dumux
479
480#endif
Helper function to compute points on a circle.
Point source traits for average-based coupling modes.
Coupling manager for low-dimensional domains embedded in the bulk domain. Point sources on each integ...
Helper class to create (named and comparable) tagged types.
Defines the index types used for grid and local indices.
Vector normal(const Vector &v)
Create a vector normal to the given one (v is expected to be non-zero)
Definition: geometry/normal.hh:36
std::vector< std::size_t > intersectingEntities(const Dune::FieldVector< ctype, dimworld > &point, const BoundingBoxTree< EntitySet > &tree, bool isCartesianGrid=false)
Compute all intersections between entities and a point.
Definition: geometry/intersectingentities.hh:100
EmbeddedCouplingMode
The coupling mode.
Definition: couplingmanager1d3d.hh:44
void circlePoints(std::vector< GlobalPosition > &points, const std::vector< Scalar > &sincos, const GlobalPosition &center, const GlobalPosition &normal, const Scalar radius)
Definition: circlepoints.hh:50
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:149
constexpr Surface surface
Definition: couplingmanager1d3d_surface.hh:57
Struture to define the index types used for grid and local indices.
Definition: indextraits.hh:38
Property to specify the type of a problem which has to be solved.
Definition: common/properties.hh:57
Definition: common/properties.hh:101
Helper class to create (named and comparable) tagged types Tags any given type. The tagged type is eq...
Definition: tag.hh:42
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d.hh:36
Definition: couplingmanager1d3d_surface.hh:44
friend constexpr bool operator==(Surface, EmbeddedCouplingMode m)
Definition: couplingmanager1d3d_surface.hh:48
friend constexpr bool operator!=(EmbeddedCouplingMode m, Surface)
Definition: couplingmanager1d3d_surface.hh:54
static std::string name()
Definition: couplingmanager1d3d_surface.hh:45
friend constexpr bool operator!=(Surface, EmbeddedCouplingMode m)
Definition: couplingmanager1d3d_surface.hh:52
friend constexpr bool operator==(EmbeddedCouplingMode m, Surface)
Definition: couplingmanager1d3d_surface.hh:50
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d_surface.hh:75
void computePointSourceData(std::size_t order=1, bool verbose=false)
Definition: couplingmanager1d3d_surface.hh:155
void evalAdditionalDomainDerivatives(Dune::index_constant< i > domainI, const LocalAssemblerI &localAssemblerI, const typename LocalAssemblerI::LocalResidual::ElementResidualVector &, JacobianMatrixDiagBlock &A, GridVariables &gridVariables)
evaluate additional derivatives of the element residual of a domain with respect to dofs in the same ...
Definition: couplingmanager1d3d_surface.hh:137
Scalar lowDimVolume(const Element< bulkIdx > &element) const
The volume the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d_surface.hh:454
void extendJacobianPattern(Dune::index_constant< id > domainI, JacobianPattern &pattern) const
extend the jacobian pattern of the diagonal block of domain i by those entries that are not already i...
Definition: couplingmanager1d3d_surface.hh:124
void computeLowDimVolumeFractions()
Compute the low dim volume fraction in the bulk domain cells.
Definition: couplingmanager1d3d_surface.hh:413
Scalar radius(std::size_t id) const
Methods to be accessed by the subproblems.
Definition: couplingmanager1d3d_surface.hh:446
Scalar lowDimVolumeFraction(const Element< bulkIdx > &element) const
The volume fraction the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d_surface.hh:462
void init(std::shared_ptr< Problem< bulkIdx > > bulkProblem, std::shared_ptr< Problem< lowDimIdx > > lowDimProblem, const SolutionVector &curSol)
Definition: couplingmanager1d3d_surface.hh:109
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanagerbase.hh:78
A class managing an extended source stencil.
Definition: extendedsourcestencil.hh:46
Declares all properties used in Dumux.