49 using Scalar =
typename IV::Traits::MatVecTraits::FaceVector::value_type;
53 using ParentType::ParentType;
68 template<
class DataHandle,
class IV,
class TensorFunc >
69 void assembleMatrices(DataHandle& handle, IV& iv,
const TensorFunc& getT, Scalar<IV> wijZeroThresh = 0.0)
71 assembleLocalMatrices_(handle.A(), handle.AB(), handle.CA(), handle.T(), handle.omegas(), iv, getT, wijZeroThresh);
74 if (iv.numUnknowns() > 0)
86 template<
class DataHandle,
class IV,
class GetU >
87 void assembleU(DataHandle& handle,
const IV& iv,
const GetU& getU)
89 auto& u = handle.uj();
93 typename IV::Traits::IndexSet::LocalIndexType i = 0;
94 for (; i < iv.numScvs(); i++)
95 u[i] = getU( this->
elemVolVars()[iv.localScv(i).gridScvIndex()] );
98 for (
const auto& data : iv.interiorBoundaryData())
100 const auto& scvf = this->
fvGeometry().scvf(data.scvfIndex());
101 const auto element = this->
fvGeometry().gridGeometry().element(scvf.insideScvIdx());
102 u[i++] = getU( this->
problem().couplingManager().getLowDimVolVars(element, scvf) );
106 for (
const auto& data : iv.dirichletData())
107 u[i++] = getU( this->
elemVolVars()[data.volVarIndex()] );
118 template<
class DataHandle,
class IV,
class GetRho >
121 using GridView =
typename IV::Traits::GridView;
122 static constexpr int dim = GridView::dimension;
123 static constexpr int dimWorld = GridView::dimensionworld;
124 static constexpr bool isSurfaceGrid = dim < dimWorld;
127 auto& g = handle.g();
128 auto& deltaG = handle.deltaG();
129 auto& outsideG = handle.gOutside();
139 using Scalar =
typename IV::Traits::MatVecTraits::TMatrix::value_type;
140 using LocalIndexType =
typename IV::Traits::IndexSet::LocalIndexType;
143 static const Scalar xi = getParamFromGroup<Scalar>(this->
problem().paramGroup(),
"FacetCoupling.Xi", 1.0);
145 for (LocalIndexType faceIdx = 0; faceIdx < iv.numFaces(); ++faceIdx)
148 const auto& curLocalScvf = iv.localScvf(faceIdx);
149 const auto& curGlobalScvf = this->
fvGeometry().scvf(curLocalScvf.gridScvfIndex());
150 const auto& gravity = this->
problem().spatialParams().gravity(curGlobalScvf.ipGlobal());
151 const auto curIsInteriorBoundary = curLocalScvf.isOnInteriorBoundary();
152 const Scalar curXiFactor = curIsInteriorBoundary ? (curGlobalScvf.boundary() ? 1.0 : xi) : 1.0;
155 const auto& neighborScvIndices = curLocalScvf.neighboringLocalScvIndices();
156 const auto& posGlobalScv = this->
fvGeometry().scv(iv.localScv(neighborScvIndices[0]).gridScvIndex());
157 const auto& posVolVars = this->
elemVolVars()[posGlobalScv];
158 const auto alpha_inside = posVolVars.extrusionFactor()*
vtmv(curGlobalScvf.unitOuterNormal(),
159 posVolVars.permeability(),
162 const auto numOutsideFaces = !curGlobalScvf.boundary() ? curGlobalScvf.numOutsideScvs() : 0;
163 using OutsideAlphaStorage = std::conditional_t< isSurfaceGrid,
165 Dune::ReservedVector<Scalar, 1> >;
166 OutsideAlphaStorage alpha_outside; alpha_outside.resize(numOutsideFaces);
167 std::fill(alpha_outside.begin(), alpha_outside.end(), 0.0);
170 if (isSurfaceGrid && !curIsInteriorBoundary)
173 if (!curLocalScvf.isDirichlet())
175 const auto localDofIdx = curLocalScvf.localDofIndex();
176 const Scalar curOneMinusXi = curIsInteriorBoundary ? -(1.0 - xi) : 1.0;
178 rho = getRho(posVolVars);
179 deltaG[localDofIdx] = 0.0;
181 if (!curGlobalScvf.boundary())
183 for (
unsigned int idxInOutside = 0; idxInOutside < curGlobalScvf.numOutsideScvs(); ++idxInOutside)
186 const auto negLocalScvIdx = neighborScvIndices[idxInOutside+1];
187 const auto& negGlobalScv = this->
fvGeometry().scv(iv.localScv(negLocalScvIdx).gridScvIndex());
188 const auto& negVolVars = this->
elemVolVars()[negGlobalScv];
189 const auto& flipScvf = !isSurfaceGrid ? curGlobalScvf
190 : this->
fvGeometry().flipScvf(curGlobalScvf.index(), idxInOutside);
192 alpha_outside[idxInOutside] = negVolVars.extrusionFactor()*
vtmv(flipScvf.unitOuterNormal(),
193 negVolVars.permeability(),
196 alpha_outside[idxInOutside] *= -1.0;
198 if (!curIsInteriorBoundary)
199 rho += getRho(negVolVars);
201 deltaG[localDofIdx] += curOneMinusXi*alpha_outside[idxInOutside];
205 if (curIsInteriorBoundary)
207 const auto posElement = this->
fvGeometry().gridGeometry().element(posGlobalScv.elementIndex());
208 const auto& facetVolVars = this->
problem().couplingManager().getLowDimVolVars(posElement, curGlobalScvf);
209 rho += getRho(facetVolVars);
211 const auto alphaFacet = posVolVars.extrusionFactor()*
vtmv(curGlobalScvf.unitOuterNormal(),
212 facetVolVars.permeability(),
214 deltaG[localDofIdx] += alphaFacet;
217 rho /= numOutsideFaces + 1;
219 deltaG[localDofIdx] -= curXiFactor*alpha_inside;
220 deltaG[localDofIdx] *= rho*Extrusion::area(this->
fvGeometry(), curGlobalScvf);
223 else if (curIsInteriorBoundary)
225 const auto posElement = this->
fvGeometry().gridGeometry().element(posGlobalScv.elementIndex());
226 const auto& facetVolVars = this->
problem().couplingManager().getLowDimVolVars(posElement, curGlobalScvf);
227 rho = 0.5*(getRho(facetVolVars) + getRho(posVolVars));
231 rho = getRho(this->
elemVolVars()[curGlobalScvf.outsideScvIdx()]);
234 g[faceIdx] = alpha_inside*rho*Extrusion::area(this->
fvGeometry(), curGlobalScvf);
236 if (isSurfaceGrid && !curIsInteriorBoundary)
239 for (
const auto& alpha : alpha_outside)
240 outsideG[faceIdx][i++] = alpha*rho*Extrusion::area(this->
fvGeometry(), curGlobalScvf);
245 handle.CA().umv(deltaG, g);
248 using FaceVector =
typename IV::Traits::MatVecTraits::FaceVector;
251 handle.A().mv(deltaG, AG);
254 for (
const auto& localFaceData : iv.localFaceData())
257 if (!localFaceData.isOutsideFace())
260 const auto localScvIdx = localFaceData.ivLocalInsideScvIndex();
261 const auto localScvfIdx = localFaceData.ivLocalScvfIndex();
262 const auto idxInOutside = localFaceData.scvfLocalOutsideScvfIndex();
263 const auto& posLocalScv = iv.localScv(localScvIdx);
264 const auto& wijk = handle.omegas()[localScvfIdx][idxInOutside+1];
267 for (LocalIndexType localDir = 0; localDir < dim; localDir++)
270 const auto& curLocalScvf = iv.localScvf(posLocalScv.localScvfIndex(localDir));
271 if (!curLocalScvf.isDirichlet())
272 outsideG[localScvfIdx][idxInOutside] -= wijk[localDir]*AG[curLocalScvf.localDofIndex()];
282 template<
class IV,
class TensorFunc >
283 void assembleLocalMatrices_(
typename IV::Traits::MatVecTraits::AMatrix& A,
284 typename IV::Traits::MatVecTraits::BMatrix& B,
285 typename IV::Traits::MatVecTraits::CMatrix& C,
286 typename IV::Traits::MatVecTraits::DMatrix& D,
287 typename IV::Traits::MatVecTraits::OmegaStorage& wijk,
288 IV& iv,
const TensorFunc& getT,
289 Scalar<IV> wijZeroThresh)
291 using Scalar =
typename IV::Traits::MatVecTraits::TMatrix::value_type;
292 using LocalIndexType =
typename IV::Traits::IndexSet::LocalIndexType;
293 static constexpr int dim = IV::Traits::GridView::dimension;
294 static constexpr int dimWorld = IV::Traits::GridView::dimensionworld;
297 static const Scalar xi = getParamFromGroup<Scalar>(this->
problem().paramGroup(),
"FacetCoupling.Xi", 1.0);
303 if (Dune::FloatCmp::ne(xi, 1.0, 1e-6))
304 DUNE_THROW(Dune::InvalidStateException,
"Xi != 1.0 cannot be used on surface grids");
306 std::vector< std::pair<LocalIndexType, LocalIndexType> > faceMarkers;
311 if (iv.numUnknowns() == 0)
317 for (LocalIndexType faceIdx = 0; faceIdx < iv.numFaces(); ++faceIdx)
319 const auto& curLocalScvf = iv.localScvf(faceIdx);
320 const auto& curGlobalScvf = this->
fvGeometry().scvf(curLocalScvf.gridScvfIndex());
321 const auto& neighborScvIndices = curLocalScvf.neighboringLocalScvIndices();
324 const auto& posLocalScv = iv.localScv(neighborScvIndices[0]);
325 const auto& posGlobalScv = this->
fvGeometry().scv(posLocalScv.gridScvIndex());
326 const auto& posVolVars = this->
elemVolVars()[posGlobalScv];
327 const auto tensor = getT(posVolVars);
331 wijk[faceIdx][0] = computeMpfaTransmissibility<EG>(this->
fvGeometry(), posLocalScv, curGlobalScvf, tensor, posVolVars.extrusionFactor());
333 const auto posScvLocalDofIdx = posLocalScv.localDofIndex();
334 for (LocalIndexType localDir = 0; localDir < dim; localDir++)
336 const auto& otherLocalScvf = iv.localScvf( posLocalScv.localScvfIndex(localDir) );
337 const auto otherLocalDofIdx = otherLocalScvf.localDofIndex();
338 D[faceIdx][otherLocalDofIdx] -= wijk[faceIdx][0][localDir];
339 D[faceIdx][posScvLocalDofIdx] += wijk[faceIdx][0][localDir];
351 for (LocalIndexType faceIdx = 0; faceIdx < iv.numFaces(); ++faceIdx)
353 const auto& curLocalScvf = iv.localScvf(faceIdx);
354 const auto& curGlobalScvf = this->
fvGeometry().scvf(curLocalScvf.gridScvfIndex());
355 const auto curIsDirichlet = curLocalScvf.isDirichlet();
356 const auto curLocalDofIdx = curLocalScvf.localDofIndex();
357 const auto curIsInteriorBoundary = curLocalScvf.isOnInteriorBoundary();
358 const Scalar curXiFactor = curIsInteriorBoundary ? (curGlobalScvf.boundary() ? 1.0 : xi) : 1.0;
361 const auto& neighborScvIndices = curLocalScvf.neighboringLocalScvIndices();
362 const auto& posLocalScv = iv.localScv(neighborScvIndices[0]);
363 const auto& posGlobalScv = this->
fvGeometry().scv(posLocalScv.gridScvIndex());
364 const auto& posVolVars = this->
elemVolVars()[posGlobalScv];
365 const auto& posElement = iv.element(neighborScvIndices[0]);
366 const auto tensor = getT(posVolVars);
370 wijk[faceIdx][0] = computeMpfaTransmissibility<EG>(this->
fvGeometry(), posLocalScv, curGlobalScvf, tensor, posVolVars.extrusionFactor());
373 bool isZeroWij =
false;
376 for (
unsigned int localDir = 0; localDir < dim; localDir++)
378 const auto& otherLocalScvf = iv.localScvf( posLocalScv.localScvfIndex(localDir) );
379 const auto otherLocalDofIdx = otherLocalScvf.localDofIndex();
381 if (otherLocalDofIdx == curLocalDofIdx)
383 if (abs(wijk[faceIdx][0][localDir]) <= wijZeroThresh)
388 faceMarkers.emplace_back( std::make_pair(curLocalDofIdx, faceIdx) );
395 if (!otherLocalScvf.isDirichlet())
397 C[faceIdx][otherLocalDofIdx] -= wijk[faceIdx][0][localDir];
399 A[curLocalDofIdx][otherLocalDofIdx] -= curXiFactor*wijk[faceIdx][0][localDir];
404 D[faceIdx][otherLocalDofIdx] -= wijk[faceIdx][0][localDir];
406 B[curLocalDofIdx][otherLocalDofIdx] += curXiFactor*wijk[faceIdx][0][localDir];
410 const auto posScvLocalDofIdx = posLocalScv.localDofIndex();
411 D[faceIdx][posScvLocalDofIdx] += wijk[faceIdx][0][localDir];
414 B[curLocalDofIdx][posScvLocalDofIdx] -= curXiFactor*wijk[faceIdx][0][localDir];
418 if (curIsInteriorBoundary && !curIsDirichlet)
420 const auto facetVolVars = this->
problem().couplingManager().getLowDimVolVars(posElement, curGlobalScvf);
421 const auto facetTensor = getT(facetVolVars);
425 const auto wFacet = 2.0*Extrusion::area(this->
fvGeometry(), curGlobalScvf)*posVolVars.extrusionFactor()
426 *
vtmv(curGlobalScvf.unitOuterNormal(), facetTensor, curGlobalScvf.unitOuterNormal())
427 / (dim < dimWorld ? sqrt(facetVolVars.extrusionFactor()) : facetVolVars.extrusionFactor());
429 A[curLocalDofIdx][curLocalDofIdx] -= wFacet;
430 B[curLocalDofIdx][curLocalScvf.coupledFacetLocalDofIndex()] -= wFacet;
433 if (!isZeroWij && abs(wFacet) <= wijZeroThresh)
436 faceMarkers.emplace_back( std::make_pair(curLocalDofIdx, faceIdx) );
441 if (!curGlobalScvf.boundary() && !curIsDirichlet)
444 const Scalar curOneMinusXi = curIsInteriorBoundary ? -(1.0 - xi) : 1.0;
447 for (
unsigned int idxInOutside = 0; idxInOutside < curGlobalScvf.numOutsideScvs(); ++idxInOutside)
449 const auto idxOnScvf = idxInOutside+1;
450 const auto& negLocalScv = iv.localScv( neighborScvIndices[idxOnScvf] );
451 const auto& negGlobalScv = this->
fvGeometry().scv(negLocalScv.gridScvIndex());
452 const auto& negVolVars = this->
elemVolVars()[negGlobalScv];
453 const auto negTensor = getT(negVolVars);
456 const auto& scvf = dim < dimWorld ? this->
fvGeometry().flipScvf(curGlobalScvf.index(), idxInOutside)
458 wijk[faceIdx][idxOnScvf] = computeMpfaTransmissibility<EG>(this->
fvGeometry(), negLocalScv, scvf, negTensor, negVolVars.extrusionFactor());
462 wijk[faceIdx][idxOnScvf] *= -1.0;
465 for (
int localDir = 0; localDir < dim; localDir++)
467 const auto otherLocalScvfIdx = negLocalScv.localScvfIndex(localDir);
468 const auto& otherLocalScvf = iv.localScvf(otherLocalScvfIdx);
469 const auto otherLocalDofIdx = otherLocalScvf.localDofIndex();
472 if (otherLocalDofIdx == curLocalDofIdx && !isZeroWij)
473 if (abs(wijk[faceIdx][idxOnScvf][localDir]) <= wijZeroThresh)
474 faceMarkers.emplace_back( std::make_pair(curLocalDofIdx, faceIdx) );
476 if (!otherLocalScvf.isDirichlet())
477 A[curLocalDofIdx][otherLocalDofIdx] += curOneMinusXi*wijk[faceIdx][idxOnScvf][localDir];
479 B[curLocalDofIdx][otherLocalDofIdx] -= curOneMinusXi*wijk[faceIdx][idxOnScvf][localDir];
482 B[curLocalDofIdx][negLocalScv.localDofIndex()] += curOneMinusXi*wijk[faceIdx][idxOnScvf][localDir];