124 const Element& element,
125 const FVElementGeometry& fvGeometry,
126 const ElementVolumeVariables& elemVolVars,
127 const ElementFluxVarsCache& elemFluxVarsCache,
130 const auto geometry = element.geometry();
131 const Dune::GeometryType geomType = geometry.type();
134 auto upwindTerm = [phaseIdx](
const auto& volVars) {
return volVars.mobility(phaseIdx); };
136 if constexpr (isBox && dim == 1)
138 Velocity tmpVelocity(0.0);
139 tmpVelocity = (geometry.corner(1) - geometry.corner(0));
140 tmpVelocity /= tmpVelocity.two_norm();
142 for (
auto&& scvf : scvfs(fvGeometry))
148 FluxVariables fluxVars;
149 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
153 Scalar localArea = scvfReferenceArea_(geomType, scvf.index());
154 Scalar flux = fluxVars.advectiveFlux(phaseIdx, upwindTerm) / localArea;
155 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
156 flux /= insideVolVars.extrusionFactor() * Extrusion::area(fvGeometry, scvf) / scvf.area();
159 const int eIdxGlobal = gridGeometry_.elementMapper().index(element);
160 velocity[eIdxGlobal] = tmpVelocity;
166 using Dune::referenceElement;
167 const auto localPos = referenceElement(geometry).position(0, 0);
168 const auto jacobianT2 = geometry.jacobianTransposed(localPos);
172 using ScvVelocities = Dune::BlockVector<Velocity>;
173 ScvVelocities scvVelocities(fvGeometry.numScv());
176 for (
auto&& scvf : scvfs(fvGeometry))
182 const auto localPosIP = geometry.local(scvf.ipGlobal());
185 const auto jacobianT1 = geometry.jacobianTransposed(localPosIP);
186 const auto globalNormal = scvf.unitOuterNormal();
187 GlobalPosition localNormal(0);
188 jacobianT1.mv(globalNormal, localNormal);
189 localNormal /= localNormal.two_norm();
192 FluxVariables fluxVars;
193 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
197 Scalar localArea = scvfReferenceArea_(geomType, scvf.index());
198 Scalar flux = fluxVars.advectiveFlux(phaseIdx, upwindTerm) / localArea;
199 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
200 flux /= insideVolVars.extrusionFactor() * Extrusion::area(fvGeometry, scvf) / scvf.area();
203 Velocity tmpVelocity = localNormal;
206 scvVelocities[scvf.insideScvIdx()] += tmpVelocity;
207 scvVelocities[scvf.outsideScvIdx()] += tmpVelocity;
211 for (
auto&& scv :
scvs(fvGeometry))
213 int vIdxGlobal = scv.dofIndex();
216 Velocity scvVelocity(0);
218 jacobianT2.mtv(scvVelocities[scv.indexInElement()], scvVelocity);
219 scvVelocity /= geometry.integrationElement(localPos)*cellNum_[vIdxGlobal];
221 velocity[vIdxGlobal] += scvVelocity;
224 else if constexpr (isDiamond)
225 DUNE_THROW(Dune::NotImplemented,
"Velocity output with diamond discretization");
232 const int numScvfsPerFace = isMpfa ? element.template subEntity<1>(0).geometry().corners() : 1;
234 if (fvGeometry.numScvf() != element.subEntities(1)*numScvfsPerFace)
235 DUNE_THROW(Dune::NotImplemented,
"Velocity output for non-conforming grids");
237 if (!geomType.isCube() && !geomType.isSimplex())
238 DUNE_THROW(Dune::NotImplemented,
"Velocity output for other geometry types than cube and simplex");
244 std::vector<bool> handledScvf;
246 handledScvf.resize(element.subEntities(1),
false);
249 std::vector<unsigned int> scvfIndexInInside(fvGeometry.numScvf());
250 int localScvfIdx = 0;
251 for (
const auto& intersection : intersections(gridGeometry_.gridView(), element))
254 if (handledScvf[intersection.indexInInside()])
257 if (intersection.neighbor() || intersection.boundary())
259 for (
int i = 0; i < numScvfsPerFace; ++i)
260 scvfIndexInInside[localScvfIdx++] = intersection.indexInInside();
264 handledScvf[intersection.indexInInside()] =
true;
268 Dune::ReservedVector<Scalar, 2*dim> scvfFluxes(element.subEntities(1), 0.0);
270 for (
auto&& scvf : scvfs(fvGeometry))
272 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
273 if (!scvf.boundary())
275 FluxVariables fluxVars;
276 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
277 scvfFluxes[scvfIndexInInside[localScvfIdx]] += fluxVars.advectiveFlux(phaseIdx, upwindTerm)/insideVolVars.extrusionFactor();
281 auto bcTypes = problem_.boundaryTypes(element, scvf);
282 if (bcTypes.hasOnlyDirichlet())
284 FluxVariables fluxVars;
285 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
286 scvfFluxes[scvfIndexInInside[localScvfIdx]] += fluxVars.advectiveFlux(phaseIdx, upwindTerm)/insideVolVars.extrusionFactor();
301 for (
auto&& scvf : scvfs(fvGeometry))
305 auto bcTypes = problem_.boundaryTypes(element, scvf);
306 if (bcTypes.hasNeumann())
312 if (stationaryVelocityField)
314 const auto flux = AdvectionType::flux(problem_, element, fvGeometry, elemVolVars,
315 scvf, phaseIdx, elemFluxVarsCache);
317 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
318 scvfFluxes[scvfIndexInInside[localScvfIdx]] += flux / insideVolVars.extrusionFactor();
323 const auto neumannFlux = problem_.neumann(element, fvGeometry, elemVolVars, elemFluxVarsCache, scvf);
324 using NumEqVector = std::decay_t<
decltype(neumannFlux)>;
325 if (Dune::FloatCmp::eq<NumEqVector, Dune::FloatCmp::CmpStyle::absolute>(neumannFlux,
NumEqVector(0.0), 1e-30))
326 scvfFluxes[scvfIndexInInside[localScvfIdx]] = 0;
330 else if (dim == 1 || geomType.isCube())
332 const auto fIdx = scvfIndexInInside[localScvfIdx];
334 if constexpr (!modelIsCompositional)
337 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
338 const auto eqIdx = VolumeVariables::Indices::conti0EqIdx + phaseIdx;
339 scvfFluxes[fIdx] += neumannFlux[eqIdx] / insideVolVars.density(phaseIdx) * scvf.area();
345 const auto fIdxOpposite = fIdx%2 ? fIdx-1 : fIdx+1;
346 scvfFluxes[fIdx] = -scvfFluxes[fIdxOpposite];
351 else if (geomType.isSimplex())
352 scvfFluxes[scvfIndexInInside[localScvfIdx]] = 0;
355 DUNE_THROW(Dune::NotImplemented,
"Velocity computation at Neumann boundaries for cell-centered and prism/pyramid");
365 ReferenceElementVelocity refVelocity;
368 if (dim == 1 || geomType.isCube())
370 assert(scvfFluxes.size() == 2*dim);
371 for (
int i = 0; i < dim; ++i)
372 refVelocity[i] = 0.5 * (scvfFluxes[2*i + 1] - scvfFluxes[2*i]);
376 else if (geomType.isSimplex())
378 assert(scvfFluxes.size() == dim+1);
379 for (
int i = 0; i < dim; ++i)
381 refVelocity[i] = -scvfFluxes[dim - 1 - i];
382 for (
int fIdx = 0; fIdx < dim + 1; ++fIdx)
383 refVelocity[i] += scvfFluxes[fIdx]/(dim + 1);
389 DUNE_THROW(Dune::NotImplemented,
"Velocity computation for cell-centered and prism/pyramid");
391 Velocity scvVelocity(0);
392 jacobianT2.mtv(refVelocity, scvVelocity);
394 scvVelocity /= geometry.integrationElement(localPos);
396 int eIdxGlobal = gridGeometry_.elementMapper().index(element);
398 velocity[eIdxGlobal] = scvVelocity;