13#ifndef DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_SURFACE_HH
14#define DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_SURFACE_HH
18#include <dune/common/timer.hh>
19#include <dune/geometry/quadraturerules.hh>
34 static std::string
name() {
return "surface"; }
41template<
class MDTraits,
class CouplingMode>
42class Embedded1d3dCouplingManager;
51template<
class MDTraits>
52class Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Surface>
53:
public EmbeddedCouplingManagerBase<MDTraits, Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Surface>,
54 CircleAveragePointSourceTraits<MDTraits>>
56 using ThisType = Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Surface>;
57 using ParentType = EmbeddedCouplingManagerBase<MDTraits, ThisType, CircleAveragePointSourceTraits<MDTraits>>;
58 using Scalar =
typename MDTraits::Scalar;
59 using SolutionVector =
typename MDTraits::SolutionVector;
60 using PointSourceData =
typename ParentType::PointSourceTraits::PointSourceData;
62 static constexpr auto bulkIdx =
typename MDTraits::template SubDomain<0>::Index();
63 static constexpr auto lowDimIdx =
typename MDTraits::template SubDomain<1>::Index();
66 template<std::
size_t id>
using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
67 template<std::
size_t id>
using Problem = GetPropType<SubDomainTypeTag<id>, Properties::Problem>;
68 template<std::
size_t id>
using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>;
69 template<std::
size_t id>
using GridView =
typename GridGeometry<id>::GridView;
70 template<std::
size_t id>
using Element =
typename GridView<id>::template Codim<0>::Entity;
71 template<std::
size_t id>
using GridIndex =
typename IndexTraits<GridView<id>>::GridIndex;
73 using GlobalPosition =
typename Element<bulkIdx>::Geometry::GlobalCoordinate;
75 template<std::
size_t id>
76 static constexpr bool isBox()
80 bulkDim = GridView<bulkIdx>::dimension,
81 lowDimDim = GridView<lowDimIdx>::dimension,
82 dimWorld = GridView<bulkIdx>::dimensionworld
85 static constexpr Embedded1d3dCouplingMode::Surface couplingMode{};
87 using ParentType::ParentType;
89 void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem,
90 std::shared_ptr<Problem<lowDimIdx>> lowDimProblem,
91 const SolutionVector& curSol)
93 ParentType::init(bulkProblem, lowDimProblem, curSol);
94 computeLowDimVolumeFractions();
103 template<std::
size_t id,
class JacobianPattern>
104 void extendJacobianPattern(Dune::index_constant<id> domainI, JacobianPattern& pattern)
const
106 extendedSourceStencil_.extendJacobianPattern(*
this, domainI, pattern);
116 template<std::
size_t i,
class LocalAssemblerI,
class JacobianMatrixDiagBlock,
class Gr
idVariables>
117 void evalAdditionalDomainDerivatives(Dune::index_constant<i> domainI,
118 const LocalAssemblerI& localAssemblerI,
119 const typename LocalAssemblerI::LocalResidual::ElementResidualVector&,
120 JacobianMatrixDiagBlock& A,
121 GridVariables& gridVariables)
123 extendedSourceStencil_.evalAdditionalDomainDerivatives(*
this, domainI, localAssemblerI, A, gridVariables);
135 void computePointSourceData(std::size_t order = 1,
bool verbose =
false)
138 static const bool useCircleAverage =
getParam<bool>(
"MixedDimension.UseCircleAverage",
true);
141 const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry();
142 const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry();
143 const auto& bulkTree = bulkGridGeometry.boundingBoxTree();
148 std::cout <<
"Initializing the point sources..." << std::endl;
153 extendedSourceStencil_.stencil().clear();
156 this->precomputeVertexIndices(bulkIdx);
157 this->precomputeVertexIndices(lowDimIdx);
163 const auto& lowDimProblem = this->problem(lowDimIdx);
164 for (
const auto& is : intersections(this->glue()))
167 const auto& lowDimElement = is.targetEntity(0);
168 const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(lowDimElement);
171 const auto intersectionGeometry = is.geometry();
173 const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(intersectionGeometry.type(), order);
182 for (
auto&& qp : quad)
185 const auto globalPos = intersectionGeometry.global(qp.position());
191 if (bulkElementIndices.empty())
198 static const auto numIp =
getParam<int>(
"MixedDimension.NumCircleSegments");
199 const auto radius = lowDimProblem.spatialParams().radius(lowDimElementIdx);
200 const auto normal = intersectionGeometry.corner(1)-intersectionGeometry.corner(0);
201 const auto integrationElement = intersectionGeometry.integrationElement(qp.position())*2*M_PI*radius/Scalar(numIp);
202 const auto qpweight = qp.weight()/(2*M_PI*radius);
203 const auto circleAvgWeight = 2*M_PI*radius/numIp;
206 std::vector<std::vector<std::size_t>> circleBulkElementIndices(
circlePoints.size());
207 std::vector<Scalar> circleIpWeight; circleIpWeight.reserve(
circlePoints.size());
208 std::vector<GridIndex<bulkIdx>> circleStencil; circleStencil.reserve(
circlePoints.size());
210 std::vector<const std::vector<GridIndex<bulkIdx>>*> circleCornerIndices;
211 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
212 std::vector<ShapeValues> circleShapeValues;
218 if (circleBulkElementIndices[k].empty())
221 const auto localCircleAvgWeight = circleAvgWeight / circleBulkElementIndices[k].size();
222 for (
const auto bulkElementIdx : circleBulkElementIndices[k])
224 circleStencil.push_back(bulkElementIdx);
225 circleIpWeight.push_back(localCircleAvgWeight);
228 if constexpr (isBox<bulkIdx>())
230 const auto bulkElement = bulkGridGeometry.element(bulkElementIdx);
231 circleCornerIndices.push_back(&(this->vertexIndices(bulkIdx, bulkElementIdx)));
234 const auto bulkGeometry = bulkElement.geometry();
235 ShapeValues shapeValues;
236 this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, circlePoints[k], shapeValues);
237 circleShapeValues.emplace_back(std::move(shapeValues));
243 if constexpr (isBox<bulkIdx>())
246 for (
const auto& vertices : circleCornerIndices)
248 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
249 vertices->begin(), vertices->end());
255 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
256 circleStencil.begin(), circleStencil.end());
264 if (circleBulkElementIndices[k].empty())
269 for (
const auto bulkElementIdx : circleBulkElementIndices[k])
271 const auto id = this->idCounter_++;
273 this->pointSources(bulkIdx).emplace_back(circlePos,
id, qpweight, integrationElement, bulkElementIdx);
274 this->pointSources(bulkIdx).back().setEmbeddings(circleBulkElementIndices[k].size());
275 this->pointSources(lowDimIdx).emplace_back(globalPos,
id, qpweight, integrationElement, lowDimElementIdx);
276 this->pointSources(lowDimIdx).back().setEmbeddings(circleBulkElementIndices[k].size());
280 PointSourceData psData;
282 if constexpr (isBox<lowDimIdx>())
284 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
285 ShapeValues shapeValues;
286 this->getShapeValues(lowDimIdx, lowDimGridGeometry, lowDimElement.geometry(), globalPos, shapeValues);
287 psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx);
291 psData.addLowDimInterpolation(lowDimElementIdx);
295 if constexpr (isBox<bulkIdx>())
297 if (useCircleAverage)
298 psData.addCircleInterpolation(circleCornerIndices, circleShapeValues, circleIpWeight, circleStencil);
300 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
301 const auto bulkGeometry = bulkGridGeometry.element(bulkElementIdx).geometry();
302 ShapeValues shapeValues;
303 this->getShapeValues(bulkIdx, bulkGridGeometry, bulkGeometry, circlePos, shapeValues);
304 psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx);
308 if (useCircleAverage)
309 psData.addCircleInterpolation(circleIpWeight, circleStencil);
311 psData.addBulkInterpolation(bulkElementIdx);
315 this->pointSourceData().emplace_back(std::move(psData));
319 if constexpr (isBox<lowDimIdx>())
321 const auto& vertices = this->vertexIndices(lowDimIdx, lowDimElementIdx);
322 this->couplingStencils(bulkIdx)[bulkElementIdx].insert(this->couplingStencils(bulkIdx)[bulkElementIdx].end(),
323 vertices.begin(), vertices.end());
328 this->couplingStencils(bulkIdx)[bulkElementIdx].push_back(lowDimElementIdx);
332 if (useCircleAverage)
334 if constexpr (isBox<bulkIdx>())
337 for (
const auto& vertices : circleCornerIndices)
339 extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(),
340 vertices->begin(), vertices->end());
346 extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(),
347 circleStencil.begin(), circleStencil.end());
356 for (
auto&& stencil : extendedSourceStencil_.stencil())
358 std::sort(stencil.second.begin(), stencil.second.end());
359 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
362 if constexpr (isBox<bulkIdx>())
364 const auto& indices = this->vertexIndices(bulkIdx, stencil.first);
365 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
366 [&](
auto i){ return std::find(indices.begin(), indices.end(), i) != indices.end(); }),
367 stencil.second.end());
372 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
373 [&](
auto i){ return i == stencil.first; }),
374 stencil.second.end());
379 using namespace Dune::Hybrid;
380 forEach(integralRange(Dune::index_constant<2>{}), [&](
const auto domainIdx)
382 for (
auto&& stencil : this->couplingStencils(domainIdx))
384 std::sort(stencil.second.begin(), stencil.second.end());
385 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
389 std::cout <<
"took " << watch.elapsed() <<
" seconds." << std::endl;
393 void computeLowDimVolumeFractions()
396 lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0));
398 const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry();
399 const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry();
402 for (
const auto& is : intersections(this->glue()))
405 const auto& inside = is.targetEntity(0);
406 const auto intersectionGeometry = is.geometry();
407 const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside);
410 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
411 for (
int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
413 const auto& outside = is.domainEntity(outsideIdx);
414 const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside);
415 lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius;
426 Scalar radius(std::size_t
id)
const
428 const auto& data = this->pointSourceData()[id];
429 return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
434 Scalar lowDimVolume(
const Element<bulkIdx>& element)
const
436 const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
437 return lowDimVolumeInBulkElement_[eIdx];
442 Scalar lowDimVolumeFraction(
const Element<bulkIdx>& element)
const
444 const auto totalVolume =
element.geometry().volume();
445 return lowDimVolume(element) / totalVolume;
453 const typename ParentType::template CouplingStencils<bulkIdx>::mapped_type&
454 extendedSourceStencil(std::size_t eIdx)
const
456 const auto& sourceStencils = extendedSourceStencil_.stencil();
457 if (
auto stencil = sourceStencils.find(eIdx); stencil != sourceStencils.end())
458 return stencil->second;
460 return this->emptyStencil(bulkIdx);
465 EmbeddedCoupling::ExtendedSourceStencil<ThisType> extendedSourceStencil_;
468 std::vector<Scalar> lowDimVolumeInBulkElement_;
472template<
class MDTraits>
474:
public std::true_type {};
Point source traits for average-based coupling modes.
Helper function to compute points on a circle.
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition couplingmanager1d3d.hh:24
Defines all properties used in Dumux.
Coupling manager for low-dimensional domains embedded in the bulk domain. Point sources on each integ...
Extended source stencil helper class for coupling managers.
void circlePoints(std::vector< GlobalPosition > &points, const std::vector< Scalar > &sincos, const GlobalPosition ¢er, const GlobalPosition &normal, const Scalar radius)
Definition circlepoints.hh:38
Vector normal(const Vector &v)
Create a vector normal to the given one (v is expected to be non-zero)
Definition normal.hh:26
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 intersectingentities.hh:102
T getParam(Args &&... args)
A free function to get a parameter from the parameter tree singleton.
Definition parameters.hh:139
constexpr Box box
Definition method.hh:147
Definition couplingmanager1d3d_average.hh:34
constexpr Surface surface
Definition couplingmanager1d3d_surface.hh:37
Type trait that is specialized for coupling manager supporting multithreaded assembly.
Definition multistagemultidomainfvassembler.hh:78
Definition couplingmanager1d3d_surface.hh:33
static std::string name()
Definition couplingmanager1d3d_surface.hh:34
Helper class to create (named and comparable) tagged types Tags any given type. The tagged type is eq...
Definition tag.hh:30
Helper class to create (named and comparable) tagged types.