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>
44namespace Embedded1d3dCouplingMode {
46 static std::string
name() {
return "kernel"; }
48 [[deprecated(
"Comparison with enum is deprecated. Removed after 3.3. Use tags.")]]
50 [[deprecated(
"Comparison with enum is deprecated. Removed after 3.3. Use tags.")]]
52 [[deprecated(
"Comparison with enum is deprecated. Removed after 3.3. Use tags.")]]
54 [[deprecated(
"Comparison with enum is deprecated. Removed after 3.3. Use tags.")]]
62template<
class MDTraits,
class CouplingMode>
63class Embedded1d3dCouplingManager;
71template<
class MDTraits>
77 using Scalar =
typename MDTraits::Scalar;
78 using SolutionVector =
typename MDTraits::SolutionVector;
79 using PointSourceData =
typename ParentType::PointSourceTraits::PointSourceData;
81 static constexpr auto bulkIdx =
typename MDTraits::template SubDomain<0>::Index();
82 static constexpr auto lowDimIdx =
typename MDTraits::template SubDomain<1>::Index();
85 template<std::
size_t id>
using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
88 template<std::
size_t id>
using GridView =
typename GridGeometry<id>::GridView;
89 template<std::
size_t id>
using Element =
typename GridView<id>::template Codim<0>::Entity;
92 using GlobalPosition =
typename Element<bulkIdx>::Geometry::GlobalCoordinate;
94 template<std::
size_t id>
95 static constexpr bool isBox()
98 static_assert(!isBox<bulkIdx>() && !isBox<lowDimIdx>(),
"The kernel coupling method is only implemented for the tpfa method");
99 static_assert(Dune::Capabilities::isCartesian<typename GridView<bulkIdx>::Grid>::v,
"The kernel coupling method is only implemented for structured grids");
102 bulkDim = GridView<bulkIdx>::dimension,
103 lowDimDim = GridView<lowDimIdx>::dimension,
104 dimWorld = GridView<bulkIdx>::dimensionworld
108 template <
typename T,
typename ...Ts>
109 using VariableKernelWidthDetector =
decltype(std::declval<T>().kernelWidthFactor(std::declval<Ts>()...));
111 template<
class T,
typename ...Args>
112 static constexpr bool hasKernelWidthFactor()
113 {
return Dune::Std::is_detected<VariableKernelWidthDetector, T, Args...>::value; }
118 using ParentType::ParentType;
120 void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem,
121 std::shared_ptr<Problem<lowDimIdx>> lowDimProblem,
122 const SolutionVector& curSol)
124 ParentType::init(bulkProblem, lowDimProblem, curSol);
125 computeLowDimVolumeFractions();
127 const auto refinement = getParamFromGroup<int>(bulkProblem->paramGroup(),
"Grid.Refinement", 0);
129 DUNE_THROW(Dune::NotImplemented,
"The current intersection detection may likely fail for refined grids.");
138 template<std::
size_t id,
class JacobianPattern>
141 extendedSourceStencil_.extendJacobianPattern(*
this, domainI, pattern);
151 template<std::
size_t i,
class LocalAssemblerI,
class JacobianMatrixDiagBlock,
class Gr
idVariables>
153 const LocalAssemblerI& localAssemblerI,
154 const typename LocalAssemblerI::LocalResidual::ElementResidualVector&,
155 JacobianMatrixDiagBlock& A,
156 GridVariables& gridVariables)
158 extendedSourceStencil_.evalAdditionalDomainDerivatives(*
this, domainI, localAssemblerI, this->curSol(), A, gridVariables);
175 std::cout <<
"[coupling] Initializing the integration point source data structures..." << std::endl;
178 prepareDataStructures_();
179 std::cout <<
"[coupling] Resized data structures." << std::endl;
181 const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry();
182 const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry();
186 static const double characteristicRelativeLength = getParam<double>(
"MixedDimension.KernelIntegrationCRL", 0.1);
189 static const bool writeIntegrationPointsToFile = getParam<bool>(
"MixedDimension.WriteIntegrationPointsToFile",
false);
190 if (writeIntegrationPointsToFile)
192 std::ofstream ipPointFile(
"kernel_points.log", std::ios::trunc);
193 ipPointFile <<
"x,y,z\n";
194 std::cout <<
"[coupling] Initialized kernel_points.log." << std::endl;
197 for (
const auto& is : intersections(this->glue()))
200 const auto& inside = is.targetEntity(0);
202 const auto intersectionGeometry = is.geometry();
203 const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside);
208 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
209 const auto kernelWidthFactor = kernelWidthFactor_(this->problem(lowDimIdx).spatialParams(), lowDimElementIdx);
210 const auto kernelWidth = kernelWidthFactor*radius;
211 const auto a = intersectionGeometry.corner(0);
212 const auto b = intersectionGeometry.corner(1);
216 for (
int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
224 const auto id = this->idCounter_++;
227 const auto& outside = is.domainEntity(outsideIdx);
228 const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside);
229 const auto surfaceFactor = computeBulkSource(intersectionGeometry, radius, kernelWidth,
id, lowDimElementIdx, bulkElementIdx, cylIntegration, is.numDomainNeighbors());
232 const auto center = intersectionGeometry.center();
233 this->pointSources(lowDimIdx).emplace_back(center,
id, surfaceFactor, intersectionGeometry.volume(), lowDimElementIdx);
234 this->pointSources(lowDimIdx).back().setEmbeddings(is.numDomainNeighbors());
238 PointSourceData psData;
241 if constexpr (isBox<lowDimIdx>())
243 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
244 const auto lowDimGeometry = this->problem(lowDimIdx).gridGeometry().element(lowDimElementIdx).geometry();
245 ShapeValues shapeValues;
246 this->getShapeValues(lowDimIdx, this->problem(lowDimIdx).gridGeometry(), lowDimGeometry, center, shapeValues);
247 psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx);
251 psData.addLowDimInterpolation(lowDimElementIdx);
255 if constexpr (isBox<bulkIdx>())
257 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
258 const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry();
259 ShapeValues shapeValues;
260 this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry, center, shapeValues);
261 psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx);
265 psData.addBulkInterpolation(bulkElementIdx);
269 this->pointSourceData().emplace_back(std::move(psData));
272 this->averageDistanceToBulkCell().push_back(avgMinDist);
273 fluxScalingFactor_.push_back(this->problem(bulkIdx).fluxScalingFactor(avgMinDist, radius, kernelWidth));
277 if constexpr (isBox<bulkIdx>())
279 const auto& vertices = this->vertexIndices(bulkIdx, bulkElementIdx);
280 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
281 vertices.begin(), vertices.end());
285 this->couplingStencils(lowDimIdx)[lowDimElementIdx].push_back(bulkElementIdx);
291 makeUniqueStencil_();
293 if (!this->pointSources(bulkIdx).empty())
294 DUNE_THROW(Dune::InvalidStateException,
"Kernel method shouldn't have point sources in the bulk domain but only volume sources!");
296 std::cout <<
"[coupling] Finished preparing manager in " << watch.elapsed() <<
" seconds." << std::endl;
303 lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0));
305 const auto& lowDimGridGeometry = this->problem(lowDimIdx).gridGeometry();
306 const auto& bulkGridGeometry = this->problem(bulkIdx).gridGeometry();
309 for (
const auto& is : intersections(this->glue()))
312 const auto& inside = is.targetEntity(0);
313 const auto intersectionGeometry = is.geometry();
314 const auto lowDimElementIdx = lowDimGridGeometry.elementMapper().index(inside);
317 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
318 for (
int outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
320 const auto& outside = is.domainEntity(outsideIdx);
321 const auto bulkElementIdx = bulkGridGeometry.elementMapper().index(outside);
322 lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius;
335 const auto& data = this->pointSourceData()[id];
336 return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
343 const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
344 return lowDimVolumeInBulkElement_[eIdx];
351 const auto totalVolume = element.geometry().volume();
352 return lowDimVolume(element) / totalVolume;
356 const std::vector<std::size_t>&
bulkSourceIds(GridIndex<bulkIdx> eIdx,
int scvIdx = 0)
const
357 {
return bulkSourceIds_[eIdx][scvIdx]; }
361 {
return bulkSourceWeights_[eIdx][scvIdx]; }
365 {
return fluxScalingFactor_[id]; }
371 template<
class Line,
class CylIntegration>
372 Scalar computeBulkSource(
const Line& line,
const Scalar radius,
const Scalar kernelWidth,
373 std::size_t
id, GridIndex<lowDimIdx> lowDimElementIdx, GridIndex<bulkIdx> coupledBulkElementIdx,
374 const CylIntegration& cylIntegration,
int embeddings)
377 static const auto bulkParamGroup = this->problem(bulkIdx).paramGroup();
378 static const auto min = getParamFromGroup<GlobalPosition>(bulkParamGroup,
"Grid.LowerLeft");
379 static const auto max = getParamFromGroup<GlobalPosition>(bulkParamGroup,
"Grid.UpperRight");
380 static const auto cells = getParamFromGroup<std::array<int, bulkDim>>(bulkParamGroup,
"Grid.Cells");
381 const auto cylSamples = cylIntegration.size();
382 const auto& a = line.corner(0);
383 const auto& b = line.corner(1);
386 static const auto writeIntegrationPointsToFile = getParam<bool>(
"MixedDimension.WriteIntegrationPointsToFile",
false);
387 if (writeIntegrationPointsToFile)
389 std::ofstream ipPointFile(
"kernel_points.log", std::ios::app);
390 for (
int i = 0; i < cylSamples; ++i)
392 const auto& point = cylIntegration.integrationPoint(i);
394 ipPointFile << point[0] <<
"," << point[1] <<
"," << point[2] <<
'\n';
398 Scalar integral = 0.0;
399 for (
int i = 0; i < cylSamples; ++i)
401 const auto& point = cylIntegration.integrationPoint(i);
408 assert(bulkElementIdx < this->problem(bulkIdx).gridGeometry().gridView().size(0));
409 const auto localWeight = evalConstKernel_(a, b, point, radius, kernelWidth)*cylIntegration.integrationElement(i)/Scalar(embeddings);
410 integral += localWeight;
411 if (!bulkSourceIds_[bulkElementIdx][0].empty() &&
id == bulkSourceIds_[bulkElementIdx][0].back())
413 bulkSourceWeights_[bulkElementIdx][0].back() += localWeight;
417 bulkSourceIds_[bulkElementIdx][0].emplace_back(
id);
418 bulkSourceWeights_[bulkElementIdx][0].emplace_back(localWeight);
419 addBulkSourceStencils_(bulkElementIdx, lowDimElementIdx, coupledBulkElementIdx);
425 const auto length = (a-b).two_norm()/Scalar(embeddings);
426 return integral/length;
429 void prepareDataStructures_()
434 bulkSourceIds_.clear();
435 bulkSourceWeights_.clear();
436 extendedSourceStencil_.stencil().clear();
439 this->precomputeVertexIndices(bulkIdx);
440 this->precomputeVertexIndices(lowDimIdx);
442 bulkSourceIds_.resize(this->gridView(bulkIdx).size(0));
443 bulkSourceWeights_.resize(this->gridView(bulkIdx).size(0));
449 this->pointSourceData().reserve(this->glue().size());
450 this->averageDistanceToBulkCell().reserve(this->glue().size());
451 fluxScalingFactor_.reserve(this->glue().size());
454 const auto numBulkElements = this->gridView(bulkIdx).size(0);
455 for (GridIndex<bulkIdx> bulkElementIdx = 0; bulkElementIdx < numBulkElements; ++bulkElementIdx)
457 this->couplingStencils(bulkIdx)[bulkElementIdx].reserve(10);
458 extendedSourceStencil_.stencil()[bulkElementIdx].reserve(10);
459 bulkSourceIds_[bulkElementIdx][0].reserve(10);
460 bulkSourceWeights_[bulkElementIdx][0].reserve(10);
465 void makeUniqueStencil_()
468 for (
auto&& stencil : extendedSourceStencil_.stencil())
470 std::sort(stencil.second.begin(), stencil.second.end());
471 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
474 if constexpr (isBox<bulkIdx>())
476 const auto& indices = this->vertexIndices(bulkIdx, stencil.first);
477 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
478 [&](
auto i){ return std::find(indices.begin(), indices.end(), i) != indices.end(); }),
479 stencil.second.end());
484 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
485 [&](
auto i){ return i == stencil.first; }),
486 stencil.second.end());
491 using namespace Dune::Hybrid;
492 forEach(integralRange(Dune::index_constant<2>{}), [&](
const auto domainIdx)
494 for (
auto&& stencil : this->couplingStencils(domainIdx))
496 std::sort(stencil.second.begin(), stencil.second.end());
497 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
503 void addBulkSourceStencils_(GridIndex<bulkIdx> bulkElementIdx, GridIndex<lowDimIdx> coupledLowDimElementIdx, GridIndex<bulkIdx> coupledBulkElementIdx)
506 if constexpr (isBox<lowDimIdx>())
508 const auto& vertices = this->vertexIndices(lowDimIdx, coupledLowDimElementIdx);
509 this->couplingStencils(bulkIdx)[bulkElementIdx].insert(this->couplingStencils(bulkIdx)[bulkElementIdx].end(),
510 vertices.begin(), vertices.end());
515 auto& s = this->couplingStencils(bulkIdx)[bulkElementIdx];
516 s.push_back(coupledLowDimElementIdx);
521 if constexpr (isBox<bulkIdx>())
523 const auto& vertices = this->vertexIndices(bulkIdx, coupledBulkElementIdx);
524 extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(),
525 vertices.begin(), vertices.end());
529 auto& s = extendedSourceStencil_.stencil()[bulkElementIdx];
530 s.push_back(coupledBulkElementIdx);
535 Scalar evalConstKernel_(
const GlobalPosition& a,
536 const GlobalPosition& b,
537 const GlobalPosition& point,
539 const Scalar rho)
const noexcept
542 const auto ab = b - a;
543 const auto t = (point - a)*ab/ab.two_norm2();
546 if (t < 0.0 || t > 1.0)
550 auto proj = a; proj.axpy(t, ab);
551 const auto r = (proj - point).two_norm();
556 return 1.0/(M_PI*rho*rho);
562 template<
class SpatialParams>
563 auto kernelWidthFactor_(
const SpatialParams& spatialParams,
unsigned int eIdx)
564 -> std::enable_if_t<hasKernelWidthFactor<SpatialParams, unsigned int>(), Scalar>
565 {
return spatialParams.kernelWidthFactor(eIdx); }
570 template<
class SpatialParams>
571 auto kernelWidthFactor_(
const SpatialParams& spatialParams,
unsigned int eIdx)
572 -> std::enable_if_t<!hasKernelWidthFactor<SpatialParams, unsigned int>(), Scalar>
574 static const Scalar kernelWidthFactor = getParam<Scalar>(
"MixedDimension.KernelWidthFactor");
575 return kernelWidthFactor;
579 EmbeddedCoupling::ExtendedSourceStencil<ThisType> extendedSourceStencil_;
581 std::vector<Scalar> lowDimVolumeInBulkElement_;
583 std::vector<std::array<std::vector<std::size_t>, isBox<bulkIdx>() ? 1<<bulkDim : 1>> bulkSourceIds_;
585 std::vector<std::array<std::vector<Scalar>, isBox<bulkIdx>() ? 1<<bulkDim : 1>> bulkSourceWeights_;
588 std::vector<Scalar> fluxScalingFactor_;
Defines the index types used for grid and local indices.
Helper class to create (named and comparable) tagged types.
Coupling manager for low-dimensional domains embedded in the bulk domain. Point sources on each integ...
Integration over cylindrical and elliptic cylindrical domains Lowest order integration formulas that ...
Extended source stencil helper class for coupling managers.
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: geometry/distance.hh:121
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: geometry/intersectingentities.hh:376
EmbeddedCouplingMode
The coupling mode.
Definition: couplingmanager1d3d.hh:44
bool intersectsPointBoundingBox(const Dune::FieldVector< ctype, dimworld > &point, const ctype *b)
Check whether a point is intersectin a bounding box (dimworld == 3)
Definition: geometry/boundingboxtree.hh:304
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 Kernel kernel
Definition: couplingmanager1d3d_kernel.hh:58
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_kernel.hh:45
friend constexpr bool operator!=(Kernel, EmbeddedCouplingMode m)
Definition: couplingmanager1d3d_kernel.hh:53
friend constexpr bool operator==(Kernel, EmbeddedCouplingMode m)
Definition: couplingmanager1d3d_kernel.hh:49
friend constexpr bool operator!=(EmbeddedCouplingMode m, Kernel)
Definition: couplingmanager1d3d_kernel.hh:55
static std::string name()
Definition: couplingmanager1d3d_kernel.hh:46
friend constexpr bool operator==(EmbeddedCouplingMode m, Kernel)
Definition: couplingmanager1d3d_kernel.hh:51
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d_kernel.hh:74
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:152
void computeLowDimVolumeFractions()
Compute the low dim volume fraction in the bulk domain cells.
Definition: couplingmanager1d3d_kernel.hh:300
Scalar radius(std::size_t id) const
Methods to be accessed by the subproblems.
Definition: couplingmanager1d3d_kernel.hh:333
Scalar lowDimVolume(const Element< bulkIdx > &element) const
The volume the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d_kernel.hh:341
const std::vector< Scalar > & bulkSourceWeights(GridIndex< bulkIdx > eIdx, int scvIdx=0) const
return all source ids for a bulk elements
Definition: couplingmanager1d3d_kernel.hh:360
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:139
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:356
Scalar lowDimVolumeFraction(const Element< bulkIdx > &element) const
The volume fraction the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d_kernel.hh:349
void computePointSourceData(std::size_t order=1, bool verbose=false)
Definition: couplingmanager1d3d_kernel.hh:170
Scalar fluxScalingFactor(std::size_t id) const
The flux scaling factor for a source with id.
Definition: couplingmanager1d3d_kernel.hh:364
void init(std::shared_ptr< Problem< bulkIdx > > bulkProblem, std::shared_ptr< Problem< lowDimIdx > > lowDimProblem, const SolutionVector &curSol)
Definition: couplingmanager1d3d_kernel.hh:120
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanagerbase.hh:78
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
Helper functions for distance queries.
Declares all properties used in Dumux.