26#ifndef DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_HH
27#define DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_HH
31#include <dune/common/timer.hh>
32#include <dune/geometry/quadraturerules.hh>
51template<
class MDTraits>
55 template<std::
size_t i>
using SubDomainTypeTag =
typename MDTraits::template SubDomain<i>::TypeTag;
60 template<std::
size_t i>
64 template<std::
size_t i>
76template<
class MDTraits, EmbeddedCouplingMode mode>
87template<
class MDTraits>
94 using Scalar =
typename MDTraits::Scalar;
95 using SolutionVector =
typename MDTraits::SolutionVector;
97 static constexpr auto bulkIdx =
typename MDTraits::template SubDomain<0>::Index();
98 static constexpr auto lowDimIdx =
typename MDTraits::template SubDomain<1>::Index();
101 template<std::
size_t id>
using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
104 template<std::
size_t id>
using GridView =
typename GridGeometry<id>::GridView;
105 template<std::
size_t id>
using Element =
typename GridView<id>::template Codim<0>::Entity;
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();
124 lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0));
127 for (
const auto& is : intersections(this->glue()))
130 const auto& inside = is.targetEntity(0);
131 const auto intersectionGeometry = is.geometry();
132 const std::size_t lowDimElementIdx = this->problem(lowDimIdx).gridGeometry().elementMapper().index(inside);
135 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
136 for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
138 const auto& outside = is.domainEntity(outsideIdx);
139 const std::size_t bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(outside);
140 lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius;
153 const auto& data = this->pointSourceData()[id];
154 return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
161 const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
162 return lowDimVolumeInBulkElement_[eIdx];
169 const auto totalVolume = element.geometry().volume();
170 return lowDimVolume(element) / totalVolume;
177 std::vector<Scalar> lowDimVolumeInBulkElement_;
186template<
class MDTraits>
189 CircleAveragePointSourceTraits<MDTraits>>
193 using Scalar =
typename MDTraits::Scalar;
194 using SolutionVector =
typename MDTraits::SolutionVector;
195 using PointSourceData =
typename ParentType::PointSourceTraits::PointSourceData;
197 static constexpr auto bulkIdx =
typename MDTraits::template SubDomain<0>::Index();
198 static constexpr auto lowDimIdx =
typename MDTraits::template SubDomain<1>::Index();
201 template<std::
size_t id>
using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
204 template<std::
size_t id>
using GridView =
typename GridGeometry<id>::GridView;
205 template<std::
size_t id>
using Element =
typename GridView<id>::template Codim<0>::Entity;
207 using GlobalPosition =
typename Element<bulkIdx>::Geometry::GlobalCoordinate;
209 template<std::
size_t id>
210 static constexpr bool isBox()
216 bulkDim = GridView<bulkIdx>::dimension,
217 lowDimDim = GridView<lowDimIdx>::dimension,
218 dimWorld = GridView<bulkIdx>::dimensionworld
225 void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem,
226 std::shared_ptr<Problem<lowDimIdx>> lowDimProblem,
227 const SolutionVector& curSol)
229 ParentType::init(bulkProblem, lowDimProblem, curSol);
230 computeLowDimVolumeFractions();
239 template<std::
size_t id,
class JacobianPattern>
242 extendedSourceStencil_.extendJacobianPattern(*
this, domainI, pattern);
252 template<std::
size_t i,
class LocalAssemblerI,
class JacobianMatrixDiagBlock,
class Gr
idVariables>
254 const LocalAssemblerI& localAssemblerI,
255 const typename LocalAssemblerI::LocalResidual::ElementResidualVector&,
256 JacobianMatrixDiagBlock& A,
257 GridVariables& gridVariables)
259 extendedSourceStencil_.evalAdditionalDomainDerivatives(*
this, domainI, localAssemblerI, this->curSol(), A, gridVariables);
274 const auto& bulkTree = this->problem(bulkIdx).gridGeometry().boundingBoxTree();
279 std::cout <<
"Initializing the point sources..." << std::endl;
284 extendedSourceStencil_.stencil().clear();
287 this->preComputeVertexIndices(bulkIdx);
288 this->preComputeVertexIndices(lowDimIdx);
291 const auto& lowDimProblem = this->problem(lowDimIdx);
292 for (
const auto& lowDimElement : elements(this->gridView(lowDimIdx)))
295 const auto lowDimGeometry = lowDimElement.geometry();
296 const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(lowDimGeometry.type(), order);
298 const auto lowDimElementIdx = lowDimProblem.gridGeometry().elementMapper().index(lowDimElement);
307 for (
auto&& qp : quad)
310 const auto globalPos = lowDimGeometry.global(qp.position());
316 if (bulkElementIndices.empty())
323 static const auto numIp = getParam<int>(
"MixedDimension.NumCircleSegments");
324 const auto radius = lowDimProblem.spatialParams().radius(lowDimElementIdx);
325 const auto normal = lowDimGeometry.corner(1)-lowDimGeometry.corner(0);
326 const auto weight = 2*M_PI*radius/numIp;
329 std::vector<Scalar> circleIpWeight(
circlePoints.size());
330 std::vector<std::size_t> circleStencil(
circlePoints.size());
332 std::unordered_map<std::size_t, std::vector<std::size_t> > circleCornerIndices;
333 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
334 std::unordered_map<std::size_t, ShapeValues> circleShapeValues;
339 if (circleBulkElementIndices.empty())
342 const auto bulkElementIdx = circleBulkElementIndices[0];
343 circleStencil[k] = bulkElementIdx;
344 circleIpWeight[k] = weight;
346 if (isBox<bulkIdx>())
348 if (!
static_cast<bool>(circleCornerIndices.count(bulkElementIdx)))
350 const auto bulkElement = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx);
351 circleCornerIndices[bulkElementIdx] = this->vertexIndices(bulkIdx, bulkElementIdx);
354 const auto bulkGeometry = bulkElement.geometry();
355 this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry,
circlePoints[k], circleShapeValues[bulkElementIdx]);
361 if (isBox<bulkIdx>())
364 for (
const auto& vertices : circleCornerIndices)
366 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
367 vertices.second.begin(), vertices.second.end());
373 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
374 circleStencil.begin(), circleStencil.end());
378 for (
auto bulkElementIdx : bulkElementIndices)
380 const auto id = this->idCounter_++;
381 const auto ie = lowDimGeometry.integrationElement(qp.position());
382 const auto qpweight = qp.weight();
384 this->pointSources(bulkIdx).emplace_back(globalPos,
id, qpweight, ie, std::vector<std::size_t>({bulkElementIdx}));
385 this->pointSources(bulkIdx).back().setEmbeddings(bulkElementIndices.size());
386 this->pointSources(lowDimIdx).emplace_back(globalPos,
id, qpweight, ie, std::vector<std::size_t>({lowDimElementIdx}));
387 this->pointSources(lowDimIdx).back().setEmbeddings(bulkElementIndices.size());
391 PointSourceData psData;
393 if (isBox<lowDimIdx>())
395 ShapeValues shapeValues;
396 this->getShapeValues(lowDimIdx, this->problem(lowDimIdx).gridGeometry(), lowDimGeometry, globalPos, shapeValues);
397 psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx);
401 psData.addLowDimInterpolation(lowDimElementIdx);
405 if (isBox<bulkIdx>())
407 psData.addCircleInterpolation(circleCornerIndices, circleShapeValues, circleIpWeight, circleStencil);
409 const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry();
410 ShapeValues shapeValues;
411 this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry, globalPos, shapeValues);
412 psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx);
416 psData.addCircleInterpolation(circleIpWeight, circleStencil);
417 psData.addBulkInterpolation(bulkElementIdx);
421 this->pointSourceData().emplace_back(std::move(psData));
424 if (isBox<lowDimIdx>())
426 this->couplingStencils(bulkIdx)[bulkElementIdx].insert(this->couplingStencils(bulkIdx)[bulkElementIdx].end(),
427 this->vertexIndices(lowDimIdx, lowDimElementIdx).begin(),
428 this->vertexIndices(lowDimIdx, lowDimElementIdx).end());
433 this->couplingStencils(bulkIdx)[bulkElementIdx].push_back(lowDimElementIdx);
437 if (isBox<bulkIdx>())
440 for (
const auto& vertices : circleCornerIndices)
442 extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(),
443 vertices.second.begin(), vertices.second.end());
449 extendedSourceStencil_.stencil()[bulkElementIdx].insert(extendedSourceStencil_.stencil()[bulkElementIdx].end(),
450 circleStencil.begin(), circleStencil.end());
457 for (
auto&& stencil : extendedSourceStencil_.stencil())
459 std::sort(stencil.second.begin(), stencil.second.end());
460 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
463 if (isBox<bulkIdx>())
465 const auto& indices = this->vertexIndices(bulkIdx, stencil.first);
466 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
467 [&](
auto i){ return std::find(indices.begin(), indices.end(), i) != indices.end(); }),
468 stencil.second.end());
473 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
474 [&](
auto i){ return i == stencil.first; }),
475 stencil.second.end());
480 using namespace Dune::Hybrid;
481 forEach(integralRange(Dune::index_constant<2>{}), [&](
const auto domainIdx)
483 for (
auto&& stencil : this->couplingStencils(domainIdx))
485 std::sort(stencil.second.begin(), stencil.second.end());
486 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
490 std::cout <<
"took " << watch.elapsed() <<
" seconds." << std::endl;
497 lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0));
500 for (
const auto& is : intersections(this->glue()))
503 const auto& inside = is.targetEntity(0);
504 const auto intersectionGeometry = is.geometry();
505 const std::size_t lowDimElementIdx = this->problem(lowDimIdx).gridGeometry().elementMapper().index(inside);
508 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
509 for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
511 const auto& outside = is.domainEntity(outsideIdx);
512 const std::size_t bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(outside);
513 lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius;
526 const auto& data = this->pointSourceData()[id];
527 return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
534 const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
535 return lowDimVolumeInBulkElement_[eIdx];
542 const auto totalVolume = element.geometry().volume();
543 return lowDimVolume(element) / totalVolume;
553 std::vector<Scalar> lowDimVolumeInBulkElement_;
564template<
class MDTraits>
570 using Scalar =
typename MDTraits::Scalar;
571 using SolutionVector =
typename MDTraits::SolutionVector;
572 using PointSourceData =
typename ParentType::PointSourceTraits::PointSourceData;
574 static constexpr auto bulkIdx =
typename MDTraits::template SubDomain<0>::Index();
575 static constexpr auto lowDimIdx =
typename MDTraits::template SubDomain<1>::Index();
578 template<std::
size_t id>
using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
581 template<std::
size_t id>
using GridView =
typename GridGeometry<id>::GridView;
582 template<std::
size_t id>
using Element =
typename GridView<id>::template Codim<0>::Entity;
584 using GlobalPosition =
typename Element<bulkIdx>::Geometry::GlobalCoordinate;
586 template<std::
size_t id>
587 static constexpr bool isBox()
591 bulkDim = GridView<bulkIdx>::dimension,
592 lowDimDim = GridView<lowDimIdx>::dimension,
593 dimWorld = GridView<bulkIdx>::dimensionworld
600 void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem,
601 std::shared_ptr<Problem<lowDimIdx>> lowDimProblem,
602 const SolutionVector& curSol)
604 ParentType::init(bulkProblem, lowDimProblem, curSol);
605 computeLowDimVolumeFractions();
620 const auto& bulkTree = this->problem(bulkIdx).gridGeometry().boundingBoxTree();
625 std::cout <<
"Initializing the point sources..." << std::endl;
632 this->preComputeVertexIndices(bulkIdx);
633 this->preComputeVertexIndices(lowDimIdx);
636 const auto& lowDimProblem = this->problem(lowDimIdx);
637 for (
const auto& lowDimElement : elements(this->gridView(lowDimIdx)))
640 const auto lowDimGeometry = lowDimElement.geometry();
641 const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(lowDimGeometry.type(), order);
643 const auto lowDimElementIdx = lowDimProblem.gridGeometry().elementMapper().index(lowDimElement);
652 for (
auto&& qp : quad)
655 const auto globalPos = lowDimGeometry.global(qp.position());
661 if (bulkElementIndices.empty())
668 static const auto numIp = getParam<int>(
"MixedDimension.NumCircleSegments", 25);
669 const auto radius = lowDimProblem.spatialParams().radius(lowDimElementIdx);
670 const auto normal = lowDimGeometry.corner(1)-lowDimGeometry.corner(0);
671 const auto integrationElement = lowDimGeometry.integrationElement(qp.position())*2*M_PI*radius/Scalar(numIp);
672 const auto weight = qp.weight()/(2*M_PI*radius);
679 if (circleBulkElementIndices.empty())
684 for (
const auto bulkElementIdx : circleBulkElementIndices)
686 const auto id = this->idCounter_++;
687 this->pointSources(bulkIdx).emplace_back(circlePos,
id, weight, integrationElement, std::vector<std::size_t>({bulkElementIdx}));
688 this->pointSources(bulkIdx).back().setEmbeddings(circleBulkElementIndices.size());
689 this->pointSources(lowDimIdx).emplace_back(globalPos,
id, weight, integrationElement, std::vector<std::size_t>({lowDimElementIdx}));
690 this->pointSources(lowDimIdx).back().setEmbeddings(circleBulkElementIndices.size());
694 PointSourceData psData;
696 if (isBox<lowDimIdx>())
698 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
699 ShapeValues shapeValues;
700 this->getShapeValues(lowDimIdx, this->problem(lowDimIdx).gridGeometry(), lowDimGeometry, globalPos, shapeValues);
701 psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx);
705 psData.addLowDimInterpolation(lowDimElementIdx);
709 if (isBox<bulkIdx>())
711 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
712 const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry();
713 ShapeValues shapeValues;
714 this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry, circlePos, shapeValues);
715 psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx);
719 psData.addBulkInterpolation(bulkElementIdx);
723 this->pointSourceData().emplace_back(std::move(psData));
727 if (isBox<bulkIdx>())
729 const auto& vertices = this->vertexIndices(bulkIdx, bulkElementIdx);
730 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
731 vertices.begin(), vertices.end());
735 this->couplingStencils(lowDimIdx)[lowDimElementIdx].push_back(bulkElementIdx);
740 if (isBox<lowDimIdx>())
742 const auto& vertices = this->vertexIndices(lowDimIdx, lowDimElementIdx);
743 this->couplingStencils(bulkIdx)[bulkElementIdx].insert(this->couplingStencils(bulkIdx)[bulkElementIdx].end(),
744 vertices.begin(), vertices.end());
749 this->couplingStencils(bulkIdx)[bulkElementIdx].push_back(lowDimElementIdx);
758 using namespace Dune::Hybrid;
759 forEach(integralRange(Dune::index_constant<2>{}), [&](
const auto domainIdx)
761 for (
auto&& stencil : this->couplingStencils(domainIdx))
763 std::sort(stencil.second.begin(), stencil.second.end());
764 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
768 std::cout <<
"took " << watch.elapsed() <<
" seconds." << std::endl;
775 lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0));
778 for (
const auto& is : intersections(this->glue()))
781 const auto& inside = is.targetEntity(0);
782 const auto intersectionGeometry = is.geometry();
783 const std::size_t lowDimElementIdx = this->problem(lowDimIdx).gridGeometry().elementMapper().index(inside);
786 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
787 for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
789 const auto& outside = is.domainEntity(outsideIdx);
790 const std::size_t bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(outside);
791 lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius;
804 const auto& data = this->pointSourceData()[id];
805 return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
812 const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
813 return lowDimVolumeInBulkElement_[eIdx];
820 const auto totalVolume = element.geometry().volume();
821 return lowDimVolume(element) / totalVolume;
829 std::vector<Scalar> lowDimVolumeInBulkElement_;
840template<
class MDTraits>
846 using Scalar =
typename MDTraits::Scalar;
847 using SolutionVector =
typename MDTraits::SolutionVector;
848 using PointSourceData =
typename ParentType::PointSourceTraits::PointSourceData;
850 static constexpr auto bulkIdx =
typename MDTraits::template SubDomain<0>::Index();
851 static constexpr auto lowDimIdx =
typename MDTraits::template SubDomain<1>::Index();
854 template<std::
size_t id>
using SubDomainTypeTag =
typename MDTraits::template SubDomain<id>::TypeTag;
857 template<std::
size_t id>
using GridView =
typename GridGeometry<id>::GridView;
858 template<std::
size_t id>
using Element =
typename GridView<id>::template Codim<0>::Entity;
860 using GlobalPosition =
typename Element<bulkIdx>::Geometry::GlobalCoordinate;
862 template<std::
size_t id>
863 static constexpr bool isBox()
867 bulkDim = GridView<bulkIdx>::dimension,
868 lowDimDim = GridView<lowDimIdx>::dimension,
869 dimWorld = GridView<bulkIdx>::dimensionworld
876 void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem,
877 std::shared_ptr<Problem<lowDimIdx>> lowDimProblem,
878 const SolutionVector& curSol)
880 ParentType::init(bulkProblem, lowDimProblem, curSol);
881 computeLowDimVolumeFractions();
890 template<std::
size_t id,
class JacobianPattern>
893 extendedSourceStencil_.extendJacobianPattern(*
this, domainI, pattern);
903 template<std::
size_t i,
class LocalAssemblerI,
class JacobianMatrixDiagBlock,
class Gr
idVariables>
905 const LocalAssemblerI& localAssemblerI,
906 const typename LocalAssemblerI::LocalResidual::ElementResidualVector&,
907 JacobianMatrixDiagBlock& A,
908 GridVariables& gridVariables)
910 extendedSourceStencil_.evalAdditionalDomainDerivatives(*
this, domainI, localAssemblerI, this->curSol(), A, gridVariables);
927 std::cout <<
"Initializing the point sources..." << std::endl;
932 bulkSourceIds_.clear();
933 bulkSourceWeights_.clear();
934 extendedSourceStencil_.stencil().clear();
937 this->preComputeVertexIndices(bulkIdx);
938 this->preComputeVertexIndices(lowDimIdx);
940 const auto& bulkFvGridGeometry = this->problem(bulkIdx).gridGeometry();
941 const auto& lowDimFvGridGeometry = this->problem(lowDimIdx).gridGeometry();
943 bulkSourceIds_.resize(this->gridView(bulkIdx).size(0));
944 bulkSourceWeights_.resize(this->gridView(bulkIdx).size(0));
949 this->pointSourceData().reserve(this->glue().size());
950 this->averageDistanceToBulkCell().reserve(this->glue().size());
951 const Scalar kernelWidth = getParam<Scalar>(
"MixedDimension.KernelWidth");
952 for (
const auto& is : intersections(this->glue()))
955 const auto& inside = is.targetEntity(0);
957 const auto intersectionGeometry = is.geometry();
960 const auto& quad = Dune::QuadratureRules<Scalar, lowDimDim>::rule(intersectionGeometry.type(), order);
961 const std::size_t lowDimElementIdx = lowDimFvGridGeometry.elementMapper().index(inside);
966 for (
auto&& qp : quad)
969 for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
971 const auto& outside = is.domainEntity(outsideIdx);
972 const std::size_t bulkElementIdx = bulkFvGridGeometry.elementMapper().index(outside);
975 const auto globalPos = intersectionGeometry.global(qp.position());
976 const auto id = this->idCounter_++;
977 const auto qpweight = qp.weight();
978 const auto ie = intersectionGeometry.integrationElement(qp.position());
979 this->pointSources(lowDimIdx).emplace_back(globalPos,
id, qpweight, ie, std::vector<std::size_t>({lowDimElementIdx}));
980 this->pointSources(lowDimIdx).back().setEmbeddings(is.numDomainNeighbors());
981 computeBulkSource(globalPos, kernelWidth,
id, lowDimElementIdx, bulkElementIdx, qpweight*ie/is.numDomainNeighbors());
985 PointSourceData psData;
987 if (isBox<lowDimIdx>())
989 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
990 const auto lowDimGeometry = this->problem(lowDimIdx).gridGeometry().element(lowDimElementIdx).geometry();
991 ShapeValues shapeValues;
992 this->getShapeValues(lowDimIdx, this->problem(lowDimIdx).gridGeometry(), lowDimGeometry, globalPos, shapeValues);
993 psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx);
997 psData.addLowDimInterpolation(lowDimElementIdx);
1001 if (isBox<bulkIdx>())
1003 using ShapeValues = std::vector<Dune::FieldVector<Scalar, 1> >;
1004 const auto bulkGeometry = this->problem(bulkIdx).gridGeometry().element(bulkElementIdx).geometry();
1005 ShapeValues shapeValues;
1006 this->getShapeValues(bulkIdx, this->problem(bulkIdx).gridGeometry(), bulkGeometry, globalPos, shapeValues);
1007 psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx);
1011 psData.addBulkInterpolation(bulkElementIdx);
1015 this->pointSourceData().emplace_back(std::move(psData));
1018 this->averageDistanceToBulkCell().push_back(this->computeDistance(outside.geometry(), globalPos));
1022 if (isBox<bulkIdx>())
1024 const auto& vertices = this->vertexIndices(bulkIdx, bulkElementIdx);
1025 this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
1026 vertices.begin(), vertices.end());
1030 this->couplingStencils(lowDimIdx)[lowDimElementIdx].push_back(bulkElementIdx);
1037 for (
auto&& stencil : extendedSourceStencil_.stencil())
1039 std::sort(stencil.second.begin(), stencil.second.end());
1040 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
1043 if (isBox<bulkIdx>())
1045 const auto& indices = this->vertexIndices(bulkIdx, stencil.first);
1046 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
1047 [&](
auto i){ return std::find(indices.begin(), indices.end(), i) != indices.end(); }),
1048 stencil.second.end());
1053 stencil.second.erase(std::remove_if(stencil.second.begin(), stencil.second.end(),
1054 [&](
auto i){ return i == stencil.first; }),
1055 stencil.second.end());
1060 using namespace Dune::Hybrid;
1061 forEach(integralRange(Dune::index_constant<2>{}), [&](
const auto domainIdx)
1063 for (
auto&& stencil : this->couplingStencils(domainIdx))
1065 std::sort(stencil.second.begin(), stencil.second.end());
1066 stencil.second.erase(std::unique(stencil.second.begin(), stencil.second.end()), stencil.second.end());
1070 if (!this->pointSources(bulkIdx).empty())
1071 DUNE_THROW(Dune::InvalidStateException,
"Kernel method shouldn't have point sources in the bulk domain but only volume sources!");
1073 std::cout <<
"took " << watch.elapsed() <<
" seconds." << std::endl;
1080 lowDimVolumeInBulkElement_.resize(this->gridView(bulkIdx).size(0));
1083 for (
const auto& is : intersections(this->glue()))
1086 const auto& inside = is.targetEntity(0);
1087 const auto intersectionGeometry = is.geometry();
1088 const std::size_t lowDimElementIdx = this->problem(lowDimIdx).gridGeometry().elementMapper().index(inside);
1091 const auto radius = this->problem(lowDimIdx).spatialParams().radius(lowDimElementIdx);
1092 for (std::size_t outsideIdx = 0; outsideIdx < is.numDomainNeighbors(); ++outsideIdx)
1094 const auto& outside = is.domainEntity(outsideIdx);
1095 const std::size_t bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(outside);
1096 lowDimVolumeInBulkElement_[bulkElementIdx] += intersectionGeometry.volume()*M_PI*radius*radius;
1109 const auto& data = this->pointSourceData()[id];
1110 return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
1117 const auto eIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
1118 return lowDimVolumeInBulkElement_[eIdx];
1125 const auto totalVolume = element.geometry().volume();
1126 return lowDimVolume(element) / totalVolume;
1131 {
return bulkSourceIds_[eIdx]; }
1135 {
return bulkSourceWeights_[eIdx]; }
1141 void computeBulkSource(
const GlobalPosition& globalPos,
const Scalar kernelWidth,
1142 std::size_t
id, std::size_t lowDimElementIdx, std::size_t coupledBulkElementIdx,
1143 Scalar pointSourceWeight)
1149 Scalar checkSum = 0.0;
1150 std::vector<bool> mask(this->gridView(bulkIdx).size(0),
false);
1151 for (
const auto& element : elements(this->gridView(bulkIdx)))
1153 Scalar weight = 0.0;
1154 const auto geometry = element.geometry();
1155 const auto& quad = Dune::QuadratureRules<Scalar, bulkDim>::rule(geometry.type(), 3);
1156 for (
auto&& qp : quad)
1158 const auto qpweight = qp.weight();
1159 const auto ie = geometry.integrationElement(qp.position());
1160 weight += evalKernel(globalPos, geometry.global(qp.position()), kernelWidth)*qpweight*ie;
1165 const auto bulkElementIdx = this->problem(bulkIdx).gridGeometry().elementMapper().index(element);
1166 bulkSourceIds_[bulkElementIdx].push_back(
id);
1167 bulkSourceWeights_[bulkElementIdx].push_back(weight*pointSourceWeight);
1168 mask[bulkElementIdx] =
true;
1171 if (isBox<lowDimIdx>())
1173 const auto& vertices = this->vertexIndices(lowDimIdx, lowDimElementIdx);
1174 this->couplingStencils(bulkIdx)[bulkElementIdx].insert(this->couplingStencils(bulkIdx)[bulkElementIdx].end(),
1175 vertices.begin(), vertices.end());
1180 this->couplingStencils(bulkIdx)[bulkElementIdx].push_back(lowDimElementIdx);
1184 extendedSourceStencil_.stencil()[bulkElementIdx].push_back(coupledBulkElementIdx);
1191 for (std::size_t eIdx = 0; eIdx < bulkSourceWeights_.size(); ++eIdx)
1192 if (mask[eIdx]) bulkSourceWeights_[eIdx].back() /= checkSum;
1200 inline Scalar evalKernel(
const GlobalPosition& origin,
1201 const GlobalPosition& pos,
1202 const Scalar width)
const noexcept
1204 const auto r = (pos-origin).two_norm();
1205 const auto r2 = r*r;
1206 const auto r3 = r2*r;
1211 const Scalar w2 = width*width;
1212 const Scalar w3 = w2*width;
1213 const Scalar k = 15.0/(4*M_PI*w3);
1214 const Scalar a = 2.0/w3;
1215 const Scalar b = 3.0/w2;
1217 return k*(a*r3 - b*r2 + 1.0);
1221 EmbeddedCoupling::ExtendedSourceStencil<ThisType> extendedSourceStencil_;
1223 std::vector<Scalar> lowDimVolumeInBulkElement_;
1225 std::vector<std::vector<std::size_t>> bulkSourceIds_;
1227 std::vector<std::vector<Scalar>> bulkSourceWeights_;
Helper function to compute points on a circle.
Extended source stencil helper class for coupling managers.
An integration point source class, i.e. sources located at a single point in space associated with a ...
Data associated with a point source.
Coupling manager for low-dimensional domains embedded in the bulk domain. Point sources on each integ...
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:99
std::vector< GlobalPosition > circlePoints(const GlobalPosition ¢er, const GlobalPosition &normal, const typename GlobalPosition::value_type radius, const std::size_t numPoints=20)
returns a vector of points on a circle
Definition: circlepoints.hh:45
EmbeddedCouplingMode
The coupling mode.
Definition: couplingmanager1d3d.hh:48
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
A vector of size number equations that can be used for Neumann fluxes, sources, residuals,...
Definition: common/properties.hh:62
Property to specify the type of a problem which has to be solved.
Definition: common/properties.hh:70
Definition: common/properties.hh:113
point source traits for the circle average coupling mode
Definition: couplingmanager1d3d.hh:53
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d.hh:77
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d.hh:90
Scalar lowDimVolume(const Element< bulkIdx > &element) const
The volume the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d.hh:159
Scalar radius(std::size_t id) const
Methods to be accessed by the subproblems.
Definition: couplingmanager1d3d.hh:151
Scalar lowDimVolumeFraction(const Element< bulkIdx > &element) const
The volume fraction the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d.hh:167
void computeLowDimVolumeFractions()
Compute the low dim volume fraction in the bulk domain cells.
Definition: couplingmanager1d3d.hh:121
void init(std::shared_ptr< Problem< bulkIdx > > bulkProblem, std::shared_ptr< Problem< lowDimIdx > > lowDimProblem, const SolutionVector &curSol)
Definition: couplingmanager1d3d.hh:112
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d.hh:190
Scalar lowDimVolumeFraction(const Element< bulkIdx > &element) const
The volume fraction the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d.hh:540
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.hh:253
void computeLowDimVolumeFractions()
Compute the low dim volume fraction in the bulk domain cells.
Definition: couplingmanager1d3d.hh:494
void computePointSourceData(std::size_t order=1, bool verbose=false)
Definition: couplingmanager1d3d.hh:271
Scalar radius(std::size_t id) const
Methods to be accessed by the subproblems.
Definition: couplingmanager1d3d.hh:524
Scalar lowDimVolume(const Element< bulkIdx > &element) const
The volume the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d.hh:532
void init(std::shared_ptr< Problem< bulkIdx > > bulkProblem, std::shared_ptr< Problem< lowDimIdx > > lowDimProblem, const SolutionVector &curSol)
Definition: couplingmanager1d3d.hh:225
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.hh:240
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d.hh:567
Scalar lowDimVolume(const Element< bulkIdx > &element) const
The volume the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d.hh:810
Scalar lowDimVolumeFraction(const Element< bulkIdx > &element) const
The volume fraction the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d.hh:818
void computeLowDimVolumeFractions()
Compute the low dim volume fraction in the bulk domain cells.
Definition: couplingmanager1d3d.hh:772
Scalar radius(std::size_t id) const
Methods to be accessed by the subproblems.
Definition: couplingmanager1d3d.hh:802
void computePointSourceData(std::size_t order=1, bool verbose=false)
Definition: couplingmanager1d3d.hh:617
void init(std::shared_ptr< Problem< bulkIdx > > bulkProblem, std::shared_ptr< Problem< lowDimIdx > > lowDimProblem, const SolutionVector &curSol)
Definition: couplingmanager1d3d.hh:600
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanager1d3d.hh:843
void computePointSourceData(std::size_t order=1, bool verbose=false)
Definition: couplingmanager1d3d.hh:922
Scalar lowDimVolumeFraction(const Element< bulkIdx > &element) const
The volume fraction the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d.hh:1123
void computeLowDimVolumeFractions()
Compute the low dim volume fraction in the bulk domain cells.
Definition: couplingmanager1d3d.hh:1077
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.hh:891
Scalar lowDimVolume(const Element< bulkIdx > &element) const
The volume the lower dimensional domain occupies in the bulk domain element.
Definition: couplingmanager1d3d.hh:1115
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.hh:904
Scalar radius(std::size_t id) const
Methods to be accessed by the subproblems.
Definition: couplingmanager1d3d.hh:1107
const std::vector< Scalar > bulkSourceWeights(std::size_t eIdx) const
return all source ids for a bulk elements
Definition: couplingmanager1d3d.hh:1134
const std::vector< std::size_t > bulkSourceIds(std::size_t eIdx) const
return all source ids for a bulk elements
Definition: couplingmanager1d3d.hh:1130
void init(std::shared_ptr< Problem< bulkIdx > > bulkProblem, std::shared_ptr< Problem< lowDimIdx > > lowDimProblem, const SolutionVector &curSol)
Definition: couplingmanager1d3d.hh:876
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition: couplingmanagerbase.hh:77
A class managing an extended source stencil.
Definition: extendedsourcestencil.hh:47
An integration point source class with an identifier to attach data and a quadrature weight and integ...
Definition: integrationpointsource.hh:44
A helper class calculating a DOF-index to point source map.
Definition: integrationpointsource.hh:107
A point source data class used for integration in multidimension models.
Definition: pointsourcedata.hh:149
Declares all properties used in Dumux.