50 void update(
const FreeFlowMomentumGridGeometry& ffMomentumGridGeometry,
51 const FreeFlowMassGridGeometry& ffMassGridGeometry,
52 const PoreNetworkGridGeometry& pnmGridGeometry)
55 resize_(ffMomentumGridGeometry, pnmGridGeometry);
57 std::cout <<
"Initializing the coupling map..." << std::endl;
59 auto ffFvGeometry =
localView(ffMomentumGridGeometry);
60 auto pnmFvGeometry =
localView(pnmGridGeometry);
62 using GlobalPosition =
typename FreeFlowMomentumGridGeometry::GridView::template Codim<0>::Entity::Geometry::GlobalCoordinate;
64 for (
const auto& pnmElement : elements(pnmGridGeometry.gridView()))
66 const auto pnmElementIdx = pnmGridGeometry.elementMapper().index(pnmElement);
67 pnmFvGeometry.bindElement(pnmElement);
68 for (
const auto& pnmScv :
scvs(pnmFvGeometry))
71 if (!pnmGridGeometry.dofOnBoundary(pnmScv.dofIndex()))
75 const auto pnmPos = pnmScv.dofPosition();
76 const auto pnmDofIdx = pnmScv.dofIndex();
77 const auto& otherPNMScv = pnmFvGeometry.scv(1 - pnmScv.indexInElement());
78 const auto otherPNMScvDofIdx = otherPNMScv.dofIndex();
81 const auto directlyCoupledFreeFlowElements =
intersectingEntities(pnmPos, ffMomentumGridGeometry.boundingBoxTree());
82 if (directlyCoupledFreeFlowElements.empty())
85 isCoupledPNMDof_[pnmDofIdx] =
true;
90 const std::size_t couplingNormalDirectionIndex = [&]
92 using Key = std::pair<std::size_t, bool>;
93 std::map<Key, std::size_t> result;
94 for (
const auto eIdx : directlyCoupledFreeFlowElements)
96 for (
const auto& intersection : intersections(ffMomentumGridGeometry.gridView(), ffMomentumGridGeometry.element(eIdx)))
100 const auto&
normal = intersection.centerUnitOuterNormal();
109 if (directlyCoupledFreeFlowElements.size() == 1 && result.size() > 1)
110 DUNE_THROW(Dune::InvalidStateException,
"Pore may not intersect with faces of different orientation when coupled to only one element");
112 return std::max_element(result.begin(), result.end(), [](
const auto& x,
const auto& y) { return x.second < y.second;})->first.first;
115 using Scalar =
typename FreeFlowMomentumGridGeometry::GridView::ctype;
117 const Scalar couplingPoreRadius = pnmGridGeometry.poreInscribedRadius(pnmDofIdx);
118 const Scalar eps = couplingPoreRadius*relEps_;
120 GlobalPosition lowerLeft = pnmPos - GlobalPosition(couplingPoreRadius - eps);
121 lowerLeft[couplingNormalDirectionIndex] = pnmPos[couplingNormalDirectionIndex];
122 GlobalPosition upperRight = pnmPos + GlobalPosition(couplingPoreRadius - eps);
123 upperRight[couplingNormalDirectionIndex] = pnmPos[couplingNormalDirectionIndex];
125 auto axes = std::move(std::bitset<FreeFlowMomentumGridGeometry::Grid::dimensionworld>{}.set());
126 axes.set(couplingNormalDirectionIndex,
false);
128 using PoreIntersectionGeometryType = Dune::AxisAlignedCubeGeometry<Scalar,
129 FreeFlowMomentumGridGeometry::GridView::dimension-1,
130 FreeFlowMomentumGridGeometry::GridView::dimensionworld>;
132 PoreIntersectionGeometryType poreIntersectionGeometry(lowerLeft, upperRight, axes);
133 const auto allCoupledFreeFlowElements =
intersectingEntities(std::move(poreIntersectionGeometry), ffMomentumGridGeometry.boundingBoxTree());
136 for (
const auto& ffElementInfo : allCoupledFreeFlowElements)
138 const auto freeFlowElementIndex = ffElementInfo.second();
139 pnmElementToFreeFlowElementsMap_[pnmElementIdx].push_back(freeFlowElementIndex);
140 freeFlowElementToPNMElementMap_[freeFlowElementIndex] = pnmElementIdx;
142 pnmToFreeFlowMassStencils_[pnmElementIdx].push_back(freeFlowElementIndex);
143 freeFlowMassToPNMStencils_[freeFlowElementIndex].push_back(pnmDofIdx);
145 ffFvGeometry.bindElement(ffMomentumGridGeometry.element(freeFlowElementIndex));
146 const auto coupledFreeFlowMomentumDofIndices = coupledFFMomentumDofs_(ffFvGeometry, ffMassGridGeometry, pnmPos, couplingPoreRadius, couplingNormalDirectionIndex);
148 pnmToFreeFlowMomentumStencils_[pnmElementIdx].push_back(coupledFreeFlowMomentumDofIndices.coupledFrontalDof);
149 freeFlowMomentumToPNMStencils_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof].push_back(pnmDofIdx);
150 freeFlowMomentumToPNMStencils_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof].push_back(otherPNMScvDofIdx);
152 isCoupledFreeFlowMomentumDof_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof] =
true;
153 isCoupledFreeFlowMomentumDofOnInterface_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof] =
true;
156 for (
const auto ffDofIdx : coupledFreeFlowMomentumDofIndices.coupledLateralDofs)
158 freeFlowMomentumToPNMStencils_[ffDofIdx].push_back(pnmDofIdx);
159 freeFlowMomentumToPNMStencils_[ffDofIdx].push_back(otherPNMScvDofIdx);
160 isCoupledFreeFlowMomentumDof_[ffDofIdx] =
true;
166 std::cout <<
"took " << watch.elapsed() <<
" seconds." << std::endl;