132 const Element& element,
133 const FVElementGeometry& fvGeometry,
134 const ElementVolumeVariables& elemVolVars,
135 const ElementFluxVarsCache& elemFluxVarsCache,
138 using Velocity =
typename VelocityVector::value_type;
140 const auto geometry = element.geometry();
141 const Dune::GeometryType geomType = geometry.type();
144 auto upwindTerm = [phaseIdx](
const auto& volVars) {
return volVars.mobility(phaseIdx); };
146 if constexpr (isBox && dim == 1)
148 Velocity tmpVelocity(0.0);
149 tmpVelocity = (geometry.corner(1) - geometry.corner(0));
150 tmpVelocity /= tmpVelocity.two_norm();
152 for (
auto&& scvf : scvfs(fvGeometry))
158 FluxVariables fluxVars;
159 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
163 Scalar localArea = scvfReferenceArea_(geomType, scvf.index());
164 Scalar flux = fluxVars.advectiveFlux(phaseIdx, upwindTerm) / localArea;
165 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
166 flux /= insideVolVars.extrusionFactor() * Extrusion::area(fvGeometry, scvf) / scvf.area();
169 const int eIdxGlobal = gridGeometry_.elementMapper().index(element);
170 velocity[eIdxGlobal] = tmpVelocity;
176 using Dune::referenceElement;
177 const auto refElement = referenceElement(geometry);
178 const auto& localPos = refElement.position(0, 0);
179 const auto jacobianT2 = geometry.jacobianTransposed(localPos);
183 using ScvVelocities = Dune::BlockVector<Velocity>;
184 ScvVelocities scvVelocities(fvGeometry.numScv());
187 for (
auto&& scvf : scvfs(fvGeometry))
193 const auto localPosIP = geometry.local(scvf.ipGlobal());
196 const auto jacobianT1 = geometry.jacobianTransposed(localPosIP);
197 const auto globalNormal = scvf.unitOuterNormal();
198 GlobalPosition localNormal(0);
199 jacobianT1.mv(globalNormal, localNormal);
200 localNormal /= localNormal.two_norm();
203 FluxVariables fluxVars;
204 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
208 Scalar localArea = scvfReferenceArea_(geomType, scvf.index());
209 Scalar flux = fluxVars.advectiveFlux(phaseIdx, upwindTerm) / localArea;
210 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
211 flux /= insideVolVars.extrusionFactor() * Extrusion::area(fvGeometry, scvf) / scvf.area();
214 Velocity tmpVelocity = localNormal;
217 scvVelocities[scvf.insideScvIdx()] += tmpVelocity;
218 scvVelocities[scvf.outsideScvIdx()] += tmpVelocity;
222 for (
auto&& scv : scvs(fvGeometry))
224 int vIdxGlobal = scv.dofIndex();
227 Velocity scvVelocity(0);
229 jacobianT2.mtv(scvVelocities[scv.indexInElement()], scvVelocity);
230 scvVelocity /= geometry.integrationElement(localPos)*cellNum_[vIdxGlobal];
232 velocity[vIdxGlobal] += scvVelocity;
235 else if constexpr (isDiamond)
236 DUNE_THROW(Dune::NotImplemented,
"Velocity output with diamond discretization");
243 const int numScvfsPerFace = isMpfa ? element.template subEntity<1>(0).geometry().corners() : 1;
245 if (fvGeometry.numScvf() != element.subEntities(1)*numScvfsPerFace)
246 DUNE_THROW(Dune::NotImplemented,
"Velocity output for non-conforming grids");
248 if (!geomType.isCube() && !geomType.isSimplex())
249 DUNE_THROW(Dune::NotImplemented,
"Velocity output for other geometry types than cube and simplex");
255 std::vector<bool> handledScvf;
257 handledScvf.resize(element.subEntities(1),
false);
260 std::vector<unsigned int> scvfIndexInInside(fvGeometry.numScvf());
261 int localScvfIdx = 0;
262 for (
const auto& intersection : intersections(gridGeometry_.gridView(), element))
265 if (handledScvf[intersection.indexInInside()])
268 if (intersection.neighbor() || intersection.boundary())
270 for (
int i = 0; i < numScvfsPerFace; ++i)
271 scvfIndexInInside[localScvfIdx++] = intersection.indexInInside();
275 handledScvf[intersection.indexInInside()] =
true;
279 std::vector<Scalar> scvfFluxes(element.subEntities(1), 0.0);
281 for (
auto&& scvf : scvfs(fvGeometry))
283 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
284 if (!scvf.boundary())
286 FluxVariables fluxVars;
287 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
288 scvfFluxes[scvfIndexInInside[localScvfIdx]] += fluxVars.advectiveFlux(phaseIdx, upwindTerm)/insideVolVars.extrusionFactor();
292 auto bcTypes = problem_.boundaryTypes(element, scvf);
293 if (bcTypes.hasOnlyDirichlet())
295 FluxVariables fluxVars;
296 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
297 scvfFluxes[scvfIndexInInside[localScvfIdx]] += fluxVars.advectiveFlux(phaseIdx, upwindTerm)/insideVolVars.extrusionFactor();
312 for (
auto&& scvf : scvfs(fvGeometry))
316 auto bcTypes = problem_.boundaryTypes(element, scvf);
317 if (bcTypes.hasNeumann())
323 if (stationaryVelocityField)
325 const auto flux = AdvectionType::flux(problem_, element, fvGeometry, elemVolVars,
326 scvf, phaseIdx, elemFluxVarsCache);
328 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
329 scvfFluxes[scvfIndexInInside[localScvfIdx]] += flux / insideVolVars.extrusionFactor();
334 const auto neumannFlux = problem_.neumann(element, fvGeometry, elemVolVars, elemFluxVarsCache, scvf);
335 using NumEqVector = std::decay_t<
decltype(neumannFlux)>;
336 if (Dune::FloatCmp::eq<NumEqVector, Dune::FloatCmp::CmpStyle::absolute>(neumannFlux,
NumEqVector(0.0), 1e-30))
337 scvfFluxes[scvfIndexInInside[localScvfIdx]] = 0;
341 else if (dim == 1 || geomType.isCube())
343 const auto fIdx = scvfIndexInInside[localScvfIdx];
345 if constexpr (!modelIsCompositional)
348 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
349 const auto eqIdx = VolumeVariables::Indices::conti0EqIdx + phaseIdx;
350 scvfFluxes[fIdx] += neumannFlux[eqIdx] / insideVolVars.density(phaseIdx) * scvf.area() * insideVolVars.extrusionFactor();
356 const auto fIdxOpposite = fIdx%2 ? fIdx-1 : fIdx+1;
357 scvfFluxes[fIdx] = -scvfFluxes[fIdxOpposite];
362 else if (geomType.isSimplex())
363 scvfFluxes[scvfIndexInInside[localScvfIdx]] = 0;
366 DUNE_THROW(Dune::NotImplemented,
"Velocity computation at Neumann boundaries for cell-centered and prism/pyramid");
376 Velocity refVelocity;
379 if (dim == 1 || geomType.isCube())
381 for (
int i = 0; i < dim; i++)
382 refVelocity[i] = 0.5 * (scvfFluxes[2*i + 1] - scvfFluxes[2*i]);
385 else if (geomType.isSimplex())
387 for (
int dimIdx = 0; dimIdx < dim; dimIdx++)
389 refVelocity[dimIdx] = -scvfFluxes[dim - 1 - dimIdx];
390 for (
int fIdx = 0; fIdx < dim + 1; fIdx++)
391 refVelocity[dimIdx] += scvfFluxes[fIdx]/(dim + 1);
396 DUNE_THROW(Dune::NotImplemented,
"Velocity computation for cell-centered and prism/pyramid");
398 Velocity scvVelocity(0);
399 jacobianT2.mtv(refVelocity, scvVelocity);
401 scvVelocity /= geometry.integrationElement(localPos);
403 int eIdxGlobal = gridGeometry_.elementMapper().index(element);
405 velocity[eIdxGlobal] = scvVelocity;