25#ifndef DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_KERNEL_HH
26#define DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_KERNEL_HH
30#include <dune/common/timer.hh>
31#include <dune/geometry/quadraturerules.hh>
32#include <dune/grid/common/capabilities.hh>
45namespace Embedded1d3dCouplingMode {
47 static std::string
name() {
return "kernel"; }
54template<
class MDTraits,
class CouplingMode>
55class Embedded1d3dCouplingManager;
63template<
class MDTraits>
69 using Scalar =
typename MDTraits::Scalar;
70 using SolutionVector =
typename MDTraits::SolutionVector;
71 using PointSourceData =
typename ParentType::PointSourceTraits::PointSourceData;
73 static constexpr auto bulkIdx =
typename MDTraits::template SubDomain<0>::Index();
74 static constexpr auto lowDimIdx =
typename MDTraits::template SubDomain<1>::Index();
77 template<std::
size_t id>
using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
80 template<std::
size_t id>
using GridView =
typename GridGeometry<id>::GridView;
81 template<std::
size_t id>
using Element =
typename GridView<id>::template Codim<0>::Entity;
84 using GlobalPosition =
typename Element<bulkIdx>::Geometry::GlobalCoordinate;
86 template<std::
size_t id>
87 static constexpr bool isBox()
90 static_assert(!isBox<bulkIdx>() && !isBox<lowDimIdx>(),
"The kernel coupling method is only implemented for the tpfa method");
91 static_assert(Dune::Capabilities::isCartesian<typename GridView<bulkIdx>::Grid>::v,
"The kernel coupling method is only implemented for structured grids");
94 bulkDim = GridView<bulkIdx>::dimension,
95 lowDimDim = GridView<lowDimIdx>::dimension,
96 dimWorld = GridView<bulkIdx>::dimensionworld
100 template <
typename T,
typename ...Ts>
101 using VariableKernelWidthDetector =
decltype(std::declval<T>().kernelWidthFactor(std::declval<Ts>()...));
103 template<
class T,
typename ...Args>
104 static constexpr bool hasKernelWidthFactor()
105 {
return Dune::Std::is_detected<VariableKernelWidthDetector, T, Args...>::value; }
110 using ParentType::ParentType;
112 void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem,
113 std::shared_ptr<Problem<lowDimIdx>> lowDimProblem,
114 const SolutionVector& curSol)
116 ParentType::init(bulkProblem, lowDimProblem, curSol);
117 computeLowDimVolumeFractions();
119 const auto refinement = getParamFromGroup<int>(bulkProblem->paramGroup(),
"Grid.Refinement", 0);
121 DUNE_THROW(Dune::NotImplemented,
"The current intersection detection may likely fail for refined grids.");
130 template<std::
size_t id,
class JacobianPattern>
133 extendedSourceStencil_.extendJacobianPattern(*
this, domainI, pattern);
143 template<std::
size_t i,
class LocalAssemblerI,
class JacobianMatrixDiagBlock,
class Gr
idVariables>
145 const LocalAssemblerI& localAssemblerI,
146 const typename LocalAssemblerI::LocalResidual::ElementResidualVector&,
147 JacobianMatrixDiagBlock& A,
148 GridVariables& gridVariables)
150 extendedSourceStencil_.evalAdditionalDomainDerivatives(*
this, domainI, localAssemblerI, A, gridVariables);
167 std::cout <<
"[coupling] Initializing the integration point source data structures..." << std::endl;
170 prepareDataStructures_();
171 std::cout <<
"[coupling] Resized data structures." << std::endl;
173 const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry();
174 const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry();
178 static const double characteristicRelativeLength = getParam<double>(
"MixedDimension.KernelIntegrationCRL", 0.1);
181 static const bool writeIntegrationPointsToFile = getParam<bool>(
"MixedDimension.WriteIntegrationPointsToFile",
false);
182 if (writeIntegrationPointsToFile)
184 std::ofstream ipPointFile(
"kernel_points.log", std::ios::trunc);
185 ipPointFile <<
"x,y,z\n";
186 std::cout <<
"[coupling] Initialized kernel_points.log." << std::endl;
189 for (
const auto& is : intersections(this->glue()))
192 const auto& inside = is.targetEntity(0);
194 const auto intersectionGeometry = is.geometry();
195 const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside);
200 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
201 const auto kernelWidthFactor = kernelWidthFactor_(this->problem(lowDimIdx).spatialParams(), lowDimElementIdx);
202 const auto kernelWidth = kernelWidthFactor*radius;
203 const auto a = intersectionGeometry.corner(0);
204 const auto b = intersectionGeometry.corner(1);
208 for (
int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
216 const auto id = this->idCounter_++;
219 const auto& outside = is.domainEntity(outsideIdx);
220 const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside);
221 const auto surfaceFactor = computeBulkSource(intersectionGeometry, radius, kernelWidth,
id, lowDimElementIdx, bulkElementIdx, cylIntegration, is.numDomainNeighbors());
224 const auto center = intersectionGeometry.center();
225 this->pointSources(lowDimIdx).emplace_back(
center,
id, surfaceFactor, intersectionGeometry.volume(), lowDimElementIdx);
226 this->pointSources(lowDimIdx).back().setEmbeddings(is.numDomainNeighbors());
230 PointSourceData psData;
233 if constexpr (isBox<lowDimIdx>())
235 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
236 const auto lowDimGeometry = this->problem(lowDimIdx).gridGeometry().element(lowDimElementIdx).geometry();
237 ShapeValues shapeValues;
238 this->getShapeValues(lowDimIdx, this->problem(lowDimIdx).gridGeometry(), lowDimGeometry,
center, shapeValues);
239 psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx);
243 psData.addLowDimInterpolation(lowDimElementIdx);
247 if constexpr (isBox<bulkIdx>())
249 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
250 const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry();
251 ShapeValues shapeValues;
252 this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry,
center, shapeValues);
253 psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx);
257 psData.addBulkInterpolation(bulkElementIdx);
261 this->pointSourceData().emplace_back(std::move(psData));
264 this->averageDistanceToBulkCell().push_back(avgMinDist);
265 fluxScalingFactor_.push_back(this->problem(bulkIdx).fluxScalingFactor(avgMinDist, radius, kernelWidth));
269 if constexpr (isBox<bulkIdx>())
271 const auto& vertices = this->vertexIndices(bulkIdx, bulkElementIdx);
272 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
273 vertices.begin(), vertices.end());
277 this->couplingStencils(lowDimIdx)[lowDimElementIdx].push_back(bulkElementIdx);
283 makeUniqueStencil_();
285 if (!this->pointSources(bulkIdx).empty())
286 DUNE_THROW(Dune::InvalidStateException,
"Kernel method shouldn't have point sources in the bulk domain but only volume sources!");
288 std::cout <<
"[coupling] Finished preparing manager in " << watch.elapsed() <<
" seconds." << std::endl;
295 lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0));
297 const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry();
298 const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry();
301 for (
const auto& is : intersections(this->glue()))
304 const auto& inside = is.targetEntity(0);
305 const auto intersectionGeometry = is.geometry();
306 const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside);
309 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
310 for (
int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
312 const auto& outside = is.domainEntity(outsideIdx);
313 const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside);
314 lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius;
327 const auto& data = this->pointSourceData()[id];
328 return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
335 const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
336 return lowDimVolumeInBulkElement_[eIdx];
343 const auto totalVolume = element.geometry().volume();
344 return lowDimVolume(element) / totalVolume;
348 const std::vector<std::size_t>&
bulkSourceIds(GridIndex<bulkIdx> eIdx,
int scvIdx = 0)
const
349 {
return bulkSourceIds_[eIdx][scvIdx]; }
353 {
return bulkSourceWeights_[eIdx][scvIdx]; }
357 {
return fluxScalingFactor_[id]; }
364 const typename ParentType::template CouplingStencils<bulkIdx>::mapped_type&
367 const auto& sourceStencils = extendedSourceStencil_.stencil();
368 if (
auto stencil = sourceStencils.find(eIdx); stencil != sourceStencils.end())
369 return stencil->second;
371 return this->emptyStencil(bulkIdx);
376 template<
class Line,
class CylIntegration>
377 Scalar computeBulkSource(
const Line&
line,
const Scalar radius,
const Scalar kernelWidth,
378 std::size_t
id, GridIndex<lowDimIdx> lowDimElementIdx, GridIndex<bulkIdx> coupledBulkElementIdx,
379 const CylIntegration& cylIntegration,
int embeddings)
382 static const auto bulkParamGroup = this->problem(bulkIdx).paramGroup();
383 static const auto min = getParamFromGroup<GlobalPosition>(bulkParamGroup,
"Grid.LowerLeft");
384 static const auto max = getParamFromGroup<GlobalPosition>(bulkParamGroup,
"Grid.UpperRight");
385 static const auto cells = getParamFromGroup<std::array<int, bulkDim>>(bulkParamGroup,
"Grid.Cells");
386 const auto cylSamples = cylIntegration.size();
387 const auto& a =
line.corner(0);
388 const auto& b =
line.corner(1);
391 static const auto writeIntegrationPointsToFile = getParam<bool>(
"MixedDimension.WriteIntegrationPointsToFile",
false);
392 if (writeIntegrationPointsToFile)
394 std::ofstream ipPointFile(
"kernel_points.log", std::ios::app);
395 for (
int i = 0; i < cylSamples; ++i)
397 const auto& point = cylIntegration.integrationPoint(i);
399 ipPointFile << point[0] <<
"," << point[1] <<
"," << point[2] <<
'\n';
403 Scalar integral = 0.0;
404 for (
int i = 0; i < cylSamples; ++i)
406 const auto& point = cylIntegration.integrationPoint(i);
413 assert(bulkElementIdx < this->problem(bulkIdx).gridGeometry().gridView().size(0));
414 const auto localWeight = evalConstKernel_(a, b, point, radius, kernelWidth)*cylIntegration.integrationElement(i)/Scalar(embeddings);
415 integral += localWeight;
416 if (!bulkSourceIds_[bulkElementIdx][0].empty() &&
id == bulkSourceIds_[bulkElementIdx][0].back())
418 bulkSourceWeights_[bulkElementIdx][0].back() += localWeight;
422 bulkSourceIds_[bulkElementIdx][0].emplace_back(
id);
423 bulkSourceWeights_[bulkElementIdx][0].emplace_back(localWeight);
424 addBulkSourceStencils_(bulkElementIdx, lowDimElementIdx, coupledBulkElementIdx);
430 const auto length = (a-b).two_norm()/Scalar(embeddings);
431 return integral/length;
434 void prepareDataStructures_()
439 bulkSourceIds_.clear();
440 bulkSourceWeights_.clear();
441 extendedSourceStencil_.stencil().clear();
444 this->precomputeVertexIndices(bulkIdx);
445 this->precomputeVertexIndices(lowDimIdx);
447 bulkSourceIds_.resize(this->gridView(bulkIdx).size(0));
448 bulkSourceWeights_.resize(this->gridView(bulkIdx).size(0));
454 this->pointSourceData().reserve(this->glue().size());
455 this->averageDistanceToBulkCell().reserve(this->glue().size());
456 fluxScalingFactor_.reserve(this->glue().size());
459 const auto numBulkElements = this->gridView(bulkIdx).size(0);
460 for (GridIndex<bulkIdx> bulkElementIdx = 0; bulkElementIdx < numBulkElements; ++bulkElementIdx)
462 this->couplingStencils(bulkIdx)[bulkElementIdx].reserve(10);
463 extendedSourceStencil_.stencil()[bulkElementIdx].reserve(10);
464 bulkSourceIds_[bulkElementIdx][0].reserve(10);
465 bulkSourceWeights_[bulkElementIdx][0].reserve(10);
470 void makeUniqueStencil_()
473 for (
auto&& stencil : extendedSourceStencil_.stencil())
475 std::sort(stencil.second.begin(), stencil.second.end());
476 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
479 if constexpr (isBox<bulkIdx>())
481 const auto& indices = this->vertexIndices(bulkIdx, stencil.first);
482 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
483 [&](
auto i){ return std::find(indices.begin(), indices.end(), i) != indices.end(); }),
484 stencil.second.end());
489 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
490 [&](
auto i){ return i == stencil.first; }),
491 stencil.second.end());
496 using namespace Dune::Hybrid;
497 forEach(integralRange(Dune::index_constant<2>{}), [&](
const auto domainIdx)
499 for (
auto&& stencil : this->couplingStencils(domainIdx))
501 std::sort(stencil.second.begin(), stencil.second.end());
502 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
508 void addBulkSourceStencils_(GridIndex<bulkIdx> bulkElementIdx, GridIndex<lowDimIdx> coupledLowDimElementIdx, GridIndex<bulkIdx> coupledBulkElementIdx)
511 if constexpr (isBox<lowDimIdx>())
513 const auto& vertices = this->vertexIndices(lowDimIdx, coupledLowDimElementIdx);
514 this->couplingStencils(bulkIdx)[bulkElementIdx].insert(this->couplingStencils(bulkIdx)[bulkElementIdx].end(),
515 vertices.begin(), vertices.end());
520 auto& s = this->couplingStencils(bulkIdx)[bulkElementIdx];
521 s.push_back(coupledLowDimElementIdx);
526 if constexpr (isBox<bulkIdx>())
528 const auto& vertices = this->vertexIndices(bulkIdx, coupledBulkElementIdx);
529 extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(),
530 vertices.begin(), vertices.end());
534 auto& s = extendedSourceStencil_.stencil()[bulkElementIdx];
535 s.push_back(coupledBulkElementIdx);
540 Scalar evalConstKernel_(
const GlobalPosition& a,
541 const GlobalPosition& b,
542 const GlobalPosition& point,
544 const Scalar rho)
const noexcept
547 const auto ab = b - a;
548 const auto t = (point - a)*ab/ab.two_norm2();
551 if (t < 0.0 || t > 1.0)
555 auto proj = a; proj.axpy(t, ab);
556 const auto radiusSquared = (proj - point).two_norm2();
558 if (radiusSquared > rho*rho)
561 return 1.0/(M_PI*rho*rho);
567 template<
class SpatialParams>
568 auto kernelWidthFactor_(
const SpatialParams& spatialParams,
unsigned int eIdx)
569 -> std::enable_if_t<hasKernelWidthFactor<SpatialParams, unsigned int>(), Scalar>
570 {
return spatialParams.kernelWidthFactor(eIdx); }
575 template<
class SpatialParams>
576 auto kernelWidthFactor_(
const SpatialParams& spatialParams,
unsigned int eIdx)
577 -> std::enable_if_t<!hasKernelWidthFactor<SpatialParams, unsigned int>(), Scalar>
579 static const Scalar kernelWidthFactor = getParam<Scalar>(
"MixedDimension.KernelWidthFactor");
580 return kernelWidthFactor;
584 EmbeddedCoupling::ExtendedSourceStencil<ThisType> extendedSourceStencil_;
586 std::vector<Scalar> lowDimVolumeInBulkElement_;
588 std::vector<std::array<std::vector<std::size_t>, isBox<bulkIdx>() ? 1<<bulkDim : 1>> bulkSourceIds_;
590 std::vector<std::array<std::vector<Scalar>, isBox<bulkIdx>() ? 1<<bulkDim : 1>> bulkSourceWeights_;
593 std::vector<Scalar> fluxScalingFactor_;
597template<
class MDTraits>
599:
public std::true_type {};
Helper class to create (named and comparable) tagged types.
Defines the index types used for grid and local indices.
Integration over cylindrical and elliptic cylindrical domains Lowest order integration formulas that ...
Coupling manager for low-dimensional domains embedded in the bulk domain. Point sources on each integ...
Extended source stencil helper class for coupling managers.
Helper functions for distance queries.
std::size_t intersectingEntityCartesianGrid(const Dune::FieldVector< ctype, dimworld > &point, const Dune::FieldVector< ctype, dimworld > &min, const Dune::FieldVector< ctype, dimworld > &max, const std::array< int, std::size_t(dimworld)> &cells)
Compute the index of the intersecting element of a Cartesian grid with a point The grid is given by t...
Definition: intersectingentities.hh:391
Corners::value_type center(const Corners &corners)
The center of a given list of corners.
Definition: center.hh:36
static Geometry::ctype averageDistanceSegmentGeometry(const typename Geometry::GlobalCoordinate &a, const typename Geometry::GlobalCoordinate &b, const Geometry &geometry, std::size_t integrationOrder=2)
Compute the average distance from a segment to a geometry by integration.
Definition: distance.hh:277
Adaption of the non-isothermal two-phase two-component flow model to problems with CO2.
Definition: adapt.hh:29
bool intersectsPointBoundingBox(const Dune::FieldVector< ctype, dimworld > &point, const ctype *b)
Check whether a point is intersectin a bounding box (dimworld == 3)
Definition: boundingboxtree.hh:306
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:180
constexpr Box box
Definition: method.hh:136
constexpr Kernel kernel
Definition: couplingmanager1d3d_kernel.hh:50
constexpr Line line
Definition: couplingmanager1d3d_line.hh:43
Structure 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:55
Definition: common/properties.hh:100
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_kernel.hh:46
static std::string name()
Definition: couplingmanager1d3d_kernel.hh:47
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d_kernel.hh:66
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_kernel.hh:144
void computeLowDimVolumeFractions()
Compute the low dim volume fraction in the bulk domain cells.
Definition: couplingmanager1d3d_kernel.hh:292
Scalar radius(std::size_t id) const
Methods to be accessed by the subproblems.
Definition: couplingmanager1d3d_kernel.hh:325
Scalar lowDimVolume(const Element< bulkIdx > &element) const
The volume the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d_kernel.hh:333
const std::vector< Scalar > & bulkSourceWeights(GridIndex< bulkIdx > eIdx, int scvIdx=0) const
return all source ids for a bulk elements
Definition: couplingmanager1d3d_kernel.hh:352
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_kernel.hh:131
const std::vector< std::size_t > & bulkSourceIds(GridIndex< bulkIdx > eIdx, int scvIdx=0) const
return all source ids for a bulk elements
Definition: couplingmanager1d3d_kernel.hh:348
const ParentType::template CouplingStencils< bulkIdx >::mapped_type & extendedSourceStencil(std::size_t eIdx) const
Extended source stencil (for the bulk domain)
Definition: couplingmanager1d3d_kernel.hh:365
Scalar lowDimVolumeFraction(const Element< bulkIdx > &element) const
The volume fraction the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d_kernel.hh:341
void computePointSourceData(std::size_t order=1, bool verbose=false)
Definition: couplingmanager1d3d_kernel.hh:162
Scalar fluxScalingFactor(std::size_t id) const
The flux scaling factor for a source with id.
Definition: couplingmanager1d3d_kernel.hh:356
void init(std::shared_ptr< Problem< bulkIdx > > bulkProblem, std::shared_ptr< Problem< lowDimIdx > > lowDimProblem, const SolutionVector &curSol)
Definition: couplingmanager1d3d_kernel.hh:112
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanagerbase.hh:83
Helper class to integrate over a cylinder domain.
Definition: cylinderintegration.hh:60
void setGeometry(const GlobalPosition &bottomCenter, const GlobalPosition &topCenter, const Scalar radius, int verbosity=0)
Set the geometry of the cylinder.
Definition: cylinderintegration.hh:97
trait that is specialized for coupling manager supporting multithreaded assembly
Definition: multidomain/fvassembler.hh:85
Declares all properties used in Dumux.