13#ifndef DUMUX_MULTIDOMAIN_FREEFLOW_POROUSMEDIUM_COUPLINGMAPPER_HH
14#define DUMUX_MULTIDOMAIN_FREEFLOW_POROUSMEDIUM_COUPLINGMAPPER_HH
19#include <unordered_map>
23#include <dune/common/timer.hh>
24#include <dune/common/exceptions.hh>
25#include <dune/common/indices.hh>
26#include <dune/common/reservedvector.hh>
27#include <dune/geometry/axisalignedcubegeometry.hh>
43 using MapType = std::unordered_map<std::size_t, std::vector<std::size_t>>;
49 template<
class FreeFlowMomentumGr
idGeometry,
class FreeFlowMassGr
idGeometry,
class PoreNetworkGr
idGeometry>
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;
116 const Scalar couplingPoreRadius = pnmGridGeometry.poreInscribedRadius(pnmDofIdx);
117 GlobalPosition lowerLeft = pnmPos - GlobalPosition(couplingPoreRadius);
118 lowerLeft[couplingNormalDirectionIndex] = pnmPos[couplingNormalDirectionIndex];
119 GlobalPosition upperRight = pnmPos + GlobalPosition(couplingPoreRadius);
120 upperRight[couplingNormalDirectionIndex] = pnmPos[couplingNormalDirectionIndex];
122 auto axes = std::move(std::bitset<FreeFlowMomentumGridGeometry::Grid::dimensionworld>{}.set());
123 axes.set(couplingNormalDirectionIndex,
false);
125 using PoreIntersectionGeometryType = Dune::AxisAlignedCubeGeometry<Scalar,
126 FreeFlowMomentumGridGeometry::GridView::dimension-1,
127 FreeFlowMomentumGridGeometry::GridView::dimensionworld>;
129 PoreIntersectionGeometryType poreIntersectionGeometry(lowerLeft, upperRight, axes);
130 const auto allCoupledFreeFlowElements =
intersectingEntities(std::move(poreIntersectionGeometry), ffMomentumGridGeometry.boundingBoxTree());
133 for (
const auto& ffElementInfo : allCoupledFreeFlowElements)
135 const auto freeFlowElementIndex = ffElementInfo.second();
136 pnmElementToFreeFlowElementsMap_[pnmElementIdx].push_back(freeFlowElementIndex);
137 freeFlowElementToPNMElementMap_[freeFlowElementIndex] = pnmElementIdx;
139 pnmToFreeFlowMassStencils_[pnmElementIdx].push_back(freeFlowElementIndex);
140 freeFlowMassToPNMStencils_[freeFlowElementIndex].push_back(pnmDofIdx);
142 ffFvGeometry.bindElement(ffMomentumGridGeometry.element(freeFlowElementIndex));
143 const auto coupledFreeFlowMomentumDofIndices = coupledFFMomentumDofs_(ffFvGeometry, ffMassGridGeometry, pnmPos, couplingPoreRadius, couplingNormalDirectionIndex);
145 pnmToFreeFlowMomentumStencils_[pnmElementIdx].push_back(coupledFreeFlowMomentumDofIndices.coupledFrontalDof);
146 freeFlowMomentumToPNMStencils_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof].push_back(pnmDofIdx);
147 freeFlowMomentumToPNMStencils_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof].push_back(otherPNMScvDofIdx);
149 isCoupledFreeFlowMomentumDof_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof] =
true;
150 isCoupledFreeFlowMomentumDofOnInterface_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof] =
true;
153 for (
const auto ffDofIdx : coupledFreeFlowMomentumDofIndices.coupledLateralDofs)
155 freeFlowMomentumToPNMStencils_[ffDofIdx].push_back(pnmDofIdx);
156 freeFlowMomentumToPNMStencils_[ffDofIdx].push_back(otherPNMScvDofIdx);
157 isCoupledFreeFlowMomentumDof_[ffDofIdx] =
true;
163 std::cout <<
"took " << watch.elapsed() <<
" seconds." << std::endl;
174 return pnmToFreeFlowMomentumStencils_.at(eIdxI);
176 return emptyStencil_;
187 return pnmToFreeFlowMassStencils_.at(eIdxI);
189 return emptyStencil_;
200 return freeFlowMassToPNMStencils_.at(eIdxI);
202 return emptyStencil_;
213 return freeFlowMomentumToPNMStencils_.at(dofIndex);
215 return emptyStencil_;
223 return static_cast<bool>(freeFlowElementToPNMElementMap_.count(eIdx));
231 return isCoupledFreeFlowMomentumDof_[dofIdx];
239 return static_cast<bool>(pnmElementToFreeFlowElementsMap_.count(eIdx));
247 return isCoupledPNMDof_[dofIdx];
252 return isCoupledFrontalFreeFlowMomentumScvf_.count(scvfIdx);
257 return isCoupledLateralFreeFlowMomentumScvf_.count(scvfIdx);
262 return isCoupledFreeFlowMassScvf_.count(scvfIdx);
266 {
return pnmElementToFreeFlowElementsMap_;}
269 {
return freeFlowElementToPNMElementMap_; }
275 pnmElementToFreeFlowElementsMap_.clear();
276 freeFlowElementToPNMElementMap_.clear();
277 isCoupledPNMDof_.clear();
278 isCoupledFreeFlowMomentumDof_.clear();
279 isCoupledFreeFlowMomentumDofOnInterface_.clear();
280 pnmToFreeFlowMassStencils_.clear();
281 pnmToFreeFlowMomentumStencils_.clear();
282 freeFlowMassToPNMStencils_.clear();
283 freeFlowMomentumToPNMStencils_.clear();
286 template<
class FreeFlowMomentumGr
idGeometry,
class PoreNetworkGr
idGeometry>
287 void resize_(
const FreeFlowMomentumGridGeometry& ffMomentumGridGeometry,
288 const PoreNetworkGridGeometry& pnmGridGeometry)
290 const auto numPNMDofs = pnmGridGeometry.numDofs();
291 const auto numFreeFlowMomentumDofs = ffMomentumGridGeometry.numDofs();
292 isCoupledPNMDof_.resize(numPNMDofs,
false);
293 isCoupledFreeFlowMomentumDof_.resize(numFreeFlowMomentumDofs,
false);
294 isCoupledFreeFlowMomentumDofOnInterface_.resize(numFreeFlowMomentumDofs,
false);
298 template<
class FVElementGeometry,
class FreeFlowMassGr
idGeometry,
class GlobalPosition,
class Scalar>
299 auto coupledFFMomentumDofs_(
const FVElementGeometry& fvGeometry,
300 const FreeFlowMassGridGeometry& ffMassGridGeometry,
301 const GlobalPosition& pnmPos,
302 const Scalar couplingPoreRadius,
303 const int couplingInterfaceDirectionIdx)
308 Dune::ReservedVector<std::size_t, FVElementGeometry::maxNumElementScvs> coupledLateralDofs;
309 std::size_t coupledFrontalDof;
314 for (
const auto& scv : scvs(fvGeometry))
316 const Scalar eps =
diameter(fvGeometry.geometry(scv))*1e-6;
317 assert(eps < couplingPoreRadius);
319 if (scv.dofAxis() == couplingInterfaceDirectionIdx)
321 if (abs(scv.dofPosition()[couplingInterfaceDirectionIdx] - pnmPos[couplingInterfaceDirectionIdx]) < eps)
323 result.coupledFrontalDof = scv.dofIndex();
326 for (
const auto& scvf : scvfs(fvGeometry, scv))
329 if (scvf.isLateral() && !scvf.boundary())
330 isCoupledLateralFreeFlowMomentumScvf_[scvf.index()] =
true;
331 else if (scvf.isFrontal() && scvf.boundary())
333 isCoupledFrontalFreeFlowMomentumScvf_[scvf.index()] =
true;
335 const auto&
element = ffMassGridGeometry.element(fvGeometry.elementIndex());
336 const auto ffMassFVGeometry =
localView(ffMassGridGeometry).bindElement(element);
337 for (
const auto& ffMassScvf : scvfs(ffMassFVGeometry))
339 if (abs(ffMassScvf.center()[couplingInterfaceDirectionIdx] - pnmPos[couplingInterfaceDirectionIdx]) < eps)
340 isCoupledFreeFlowMassScvf_[ffMassScvf.index()] =
true;
348 bool isCoupledDof =
false;
350 for (
int dimIdx = 0; dimIdx < GlobalPosition::dimension; ++dimIdx)
352 if (dimIdx == couplingInterfaceDirectionIdx || scv.boundary())
355 isCoupledDof = abs(scv.dofPosition()[dimIdx] - pnmPos[dimIdx]) < couplingPoreRadius + eps;
360 result.coupledLateralDofs.push_back(scv.dofIndex());
363 for (
const auto& scvf : scvfs(fvGeometry, scv))
365 if (scvf.isLateral() && scvf.boundary())
368 if (abs(scvf.ipGlobal()[couplingInterfaceDirectionIdx] - pnmPos[couplingInterfaceDirectionIdx]) < eps)
369 isCoupledLateralFreeFlowMomentumScvf_[scvf.index()] =
true;
379 std::vector<std::size_t> emptyStencil_;
381 std::unordered_map<std::size_t, std::vector<std::size_t>> pnmElementToFreeFlowElementsMap_;
382 std::unordered_map<std::size_t, std::size_t> freeFlowElementToPNMElementMap_;
384 std::vector<bool> isCoupledPNMDof_;
385 std::vector<bool> isCoupledFreeFlowMomentumDof_;
386 std::vector<bool> isCoupledFreeFlowMomentumDofOnInterface_;
388 std::unordered_map<std::size_t, bool> isCoupledLateralFreeFlowMomentumScvf_;
389 std::unordered_map<std::size_t, bool> isCoupledFrontalFreeFlowMomentumScvf_;
390 std::unordered_map<std::size_t, bool> isCoupledFreeFlowMassScvf_;
392 MapType pnmToFreeFlowMassStencils_;
393 MapType pnmToFreeFlowMomentumStencils_;
394 MapType freeFlowMassToPNMStencils_;
395 MapType freeFlowMomentumToPNMStencils_;
Coupling mapper for staggered free-flow and pore-network models.
Definition: boundary/freeflowporenetwork/couplingmapper.hh:42
bool isCoupledFreeFlowMomentumLateralScvf(std::size_t scvfIdx) const
Definition: boundary/freeflowporenetwork/couplingmapper.hh:255
const std::vector< std::size_t > & freeFlowMassToPoreNetworkCouplingStencil(const std::size_t eIdxI) const
returns an iterable container of all indices of degrees of freedom of domain j that couple with / inf...
Definition: boundary/freeflowporenetwork/couplingmapper.hh:197
void update(const FreeFlowMomentumGridGeometry &ffMomentumGridGeometry, const FreeFlowMassGridGeometry &ffMassGridGeometry, const PoreNetworkGridGeometry &pnmGridGeometry)
Main update routine.
Definition: boundary/freeflowporenetwork/couplingmapper.hh:50
const std::vector< std::size_t > & freeFlowMomentumToPoreNetworkCouplingStencil(const std::size_t dofIndex) const
returns an iterable container of all indices of degrees of freedom of domain j that couple with / inf...
Definition: boundary/freeflowporenetwork/couplingmapper.hh:210
bool isCoupledFreeFlowMomentumScvf(std::size_t scvfIdx) const
Definition: boundary/freeflowporenetwork/couplingmapper.hh:250
bool isCoupledPoreNetworkDof(std::size_t dofIdx) const
Return if an element residual with index eIdx of domain i is coupled to domain j.
Definition: boundary/freeflowporenetwork/couplingmapper.hh:245
bool isCoupledFreeFlowMassScvf(std::size_t scvfIdx) const
Definition: boundary/freeflowporenetwork/couplingmapper.hh:260
const std::vector< std::size_t > & poreNetworkToFreeFlowMomentumCouplingStencil(const std::size_t eIdxI) const
returns an iterable container of all indices of degrees of freedom of domain j that couple with / inf...
Definition: boundary/freeflowporenetwork/couplingmapper.hh:171
const auto & freeFlowElementToPNMElementMap() const
Definition: boundary/freeflowporenetwork/couplingmapper.hh:268
const auto & pnmElementToFreeFlowElementsMap() const
Definition: boundary/freeflowporenetwork/couplingmapper.hh:265
bool isCoupledFreeFlowMomentumDof(std::size_t dofIdx) const
Return if an element residual with index eIdx of domain i is coupled to domain j.
Definition: boundary/freeflowporenetwork/couplingmapper.hh:229
const std::vector< std::size_t > & poreNetworkToFreeFlowMassCouplingStencil(const std::size_t eIdxI) const
returns an iterable container of all indices of degrees of freedom of domain j that couple with / inf...
Definition: boundary/freeflowporenetwork/couplingmapper.hh:184
bool isCoupledFreeFlowElement(std::size_t eIdx) const
Return if an element residual with index eIdx of domain i is coupled to domain j.
Definition: boundary/freeflowporenetwork/couplingmapper.hh:221
bool isCoupledPoreNetworkElement(std::size_t eIdx) const
Return if an element residual with index eIdx of domain i is coupled to domain j.
Definition: boundary/freeflowporenetwork/couplingmapper.hh:237
A function to compute a geometry's diameter, i.e. the longest distance between points of a geometry.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
static std::size_t normalAxis(const Vector &v)
Returns the normal axis index of a unit vector (0 = x, 1 = y, 2 = z)
Definition: normalaxis.hh:26
bool intersectsPointGeometry(const Dune::FieldVector< ctype, dimworld > &point, const Geometry &g)
Find out whether a point is inside a three-dimensional geometry.
Definition: intersectspointgeometry.hh:28
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
Geometry::ctype diameter(const Geometry &geo)
Computes the longest distance between points of a geometry.
Definition: diameter.hh:26
Algorithms that finds which geometric entities intersect.
The available discretization methods in Dumux.