12#ifndef DUMUX_FREELOW_NAVIERSTOKES_FLUX_OVER_AXISALIGNED_SURFACE_HH
13#define DUMUX_FREELOW_NAVIERSTOKES_FLUX_OVER_AXISALIGNED_SURFACE_HH
19#include <dune/common/exceptions.hh>
20#include <dune/geometry/axisalignedcubegeometry.hh>
35template<
class Gr
idVariables,
class SolutionVector,
class LocalRes
idual>
38 using Scalar =
typename GridVariables::Scalar;
39 using GridGeometry =
typename GridVariables::GridGeometry;
40 using FVElementGeometry =
typename GridGeometry::LocalView;
41 using SubControlVolumeFace =
typename FVElementGeometry::SubControlVolumeFace;
42 using GridView =
typename GridGeometry::GridView;
43 using VolumeVariables =
typename GridVariables::VolumeVariables;
44 using Element =
typename GridView::template Codim<0>::Entity;
45 using NumEqVector =
typename LocalResidual::ElementResidualVector::value_type;
47 static constexpr auto dim = GridView::dimension;
48 static constexpr auto dimWorld = GridView::dimensionworld;
50 static_assert(dim > 1,
"Only implemented for dim > 1");
52 using GlobalPosition =
typename Element::Geometry::GlobalCoordinate;
55 using SurfaceT = Dune::AxisAlignedCubeGeometry<Scalar, (dim == 2 ? 1 : 2), dimWorld>;
60 std::size_t normalDirectionIndex;
72 const SolutionVector& sol,
73 const LocalResidual& localResidual)
74 : gridVariables_(gridVariables)
76 , localResidual_(localResidual)
78 verbose_ = getParamFromGroup<bool>(problem_().paramGroup(),
"FluxOverAxisAlignedSurface.Verbose",
false);
90 static_assert(std::is_same_v<std::decay_t<T>,
Surface>);
91 surfaces_.emplace(std::make_pair(
92 name, std::make_pair(
surface, NumEqVector(0.0))
104 const GlobalPosition& lowerLeft,
105 const GlobalPosition& upperRight)
108 const GlobalPosition v = upperRight - lowerLeft;
109 const auto it = std::find_if(v.begin(), v.end(), [](
const auto& x){ return abs(x) < 1e-20; });
111 DUNE_THROW(Dune::InvalidStateException,
"Surface is not axis-parallel!");
113 const std::size_t normalDirectionIndex =
std::distance(v.begin(), it);
114 auto inSurfaceAxes = std::move(std::bitset<dimWorld>{}.set());
115 inSurfaceAxes.set(normalDirectionIndex,
false);
118 surfaces_.emplace(std::make_pair(
121 std::move(
surface), normalDirectionIndex, NumEqVector(0.0)
134 const GlobalPosition&
center,
135 const std::size_t normalDirectionIndex)
137 GlobalPosition lowerLeft = gridVariables_.gridGeometry().bBoxMin();
138 GlobalPosition upperRight = gridVariables_.gridGeometry().bBoxMax();
140 lowerLeft[normalDirectionIndex] =
center[normalDirectionIndex];
141 upperRight[normalDirectionIndex] =
center[normalDirectionIndex];
143 auto inSurfaceAxes = std::move(std::bitset<dimWorld>{}.set());
144 inSurfaceAxes.set(normalDirectionIndex,
false);
147 surfaces_.emplace(std::make_pair(
150 std::move(
surface), normalDirectionIndex, NumEqVector(0.0)
160 auto fluxType = [
this](
const auto& element,
161 const auto& fvGeometry,
162 const auto& elemVolVars,
164 const auto& elemFluxVarsCache)
166 return localResidual_.evalFlux(
167 problem_(), element, fvGeometry, elemVolVars, elemFluxVarsCache, scvf
185 template<
class FluxType>
189 for (
auto&
surface : surfaces_)
192 snapSurfaceToClosestFace_();
193 calculateFluxes_(fluxType);
201 const auto&
flux(
const std::string& name)
const
203 return surfaces_.at(name).flux;
209 const std::map<std::string, SurfaceData>&
surfaces()
const
210 {
return surfaces_; }
217 for (
const auto& [name, data] : surfaces_)
218 std::cout <<
"Flux over surface " << name <<
": " << data.flux << std::endl;
223 template<
class FluxType>
224 void calculateFluxes_(
const FluxType& fluxType)
226 auto fvGeometry =
localView(problem_().gridGeometry());
227 auto elemVolVars =
localView(gridVariables_.curGridVolVars());
228 auto elemFluxVarsCache =
localView(gridVariables_.gridFluxVarsCache());
230 for (
const auto& element : elements(problem_().gridGeometry().gridView()))
232 fvGeometry.bindElement(element);
233 elemVolVars.bindElement(element, fvGeometry, sol_);
234 elemFluxVarsCache.bindElement(element, fvGeometry, elemVolVars);
236 for (
const auto& scvf : scvfs(fvGeometry))
240 for (
auto& [name, surfaceData] : surfaces_)
242 if (considerScvf_(scvf, surfaceData))
244 const auto result = fluxType(element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
245 surfaceData.flux += result;
248 std::cout <<
"At element " << problem_().gridGeometry().elementMapper().index(element)
249 <<
": Flux at face " << scvf.ipGlobal() <<
": " << result <<
" (" << name <<
")" << std::endl;
257 bool considerScvf_(
const SubControlVolumeFace& scvf,
const SurfaceData& SurfaceData)
const
262 if (scvf.boundary() || !std::signbit(scvf.unitOuterNormal()[SurfaceData.normalDirectionIndex]))
268 void snapSurfaceToClosestFace_()
271 const auto gridView = problem_().gridGeometry().gridView();
273 for (
auto& [name, surfaceData] : surfaces_)
275 GeometriesEntitySet entitySet({surfaceData.surface});
278 problem_().gridGeometry().boundingBoxTree(), geometriesTree
281 if (intersectingElements.empty())
283 std::cout <<
"surface boundaries: " << std::endl;
284 printSurfaceBoundaries_(surfaceData.surface);
286 DUNE_THROW(Dune::InvalidStateException,
"surface " << name <<
" does not intersect with any element");
289 std::vector<std::size_t> sortedResults;
290 sortedResults.reserve(gridView.size(0));
292 for (
const auto& i : intersectingElements)
293 sortedResults.push_back(i.first());
295 std::sort(sortedResults.begin(), sortedResults.end());
296 sortedResults.erase(std::unique(
297 sortedResults.begin(), sortedResults.end()
298 ), sortedResults.end());
301 GlobalPosition normalVector(0.0);
302 normalVector[surfaceData.normalDirectionIndex] = 1.0;
304 const auto& firstIntersectingElement = problem_().gridGeometry().element(sortedResults[0]);
305 Scalar
distance = std::numeric_limits<Scalar>::max();
306 bool snappingOcurred =
false;
308 GlobalPosition surfaceLowerLeft = surfaceData.surface.corner(0);
309 GlobalPosition surfaceUpperRight = surfaceData.surface.corner(3);
311 bool surfaceAlreadyOnFaces =
false;
312 for (
const auto& intersection : intersections(gridView, firstIntersectingElement))
314 if (surfaceAlreadyOnFaces)
318 if (abs(1.0 - abs(normalVector * intersection.centerUnitOuterNormal())) < 1e-8)
321 const auto getDistance = [](
const auto& p,
const auto& geo)
323 if constexpr (dim == 2)
329 const auto& geo = intersection.geometry();
330 if (
const Scalar d = getDistance(geo.center(), surfaceData.surface); d < 1e-8 *
diameter(geo))
333 surfaceAlreadyOnFaces =
true;
334 snappingOcurred =
false;
339 snappingOcurred =
true;
342 for (
int i = 0; i < surfaceData.surface.corners(); ++i)
344 const auto& faceCenter = geo.center();
345 surfaceLowerLeft[surfaceData.normalDirectionIndex] = faceCenter[surfaceData.normalDirectionIndex];
346 surfaceUpperRight[surfaceData.normalDirectionIndex] = faceCenter[surfaceData.normalDirectionIndex];
354 std::cout <<
"\n\nSurface '" << name <<
"' was automatically snapped to the closest faces" << std::endl;
355 std::cout <<
"Old surface boundaries: " << std::endl;
356 printSurfaceBoundaries_(surfaceData.surface);
359 auto inSurfaceAxes = std::move(std::bitset<dimWorld>{}.set());
360 inSurfaceAxes.set(surfaceData.normalDirectionIndex,
false);
361 surfaceData.surface =
Surface{surfaceLowerLeft, surfaceUpperRight, inSurfaceAxes};
363 std::cout <<
"New surface boundaries: " << std::endl;
364 printSurfaceBoundaries_(surfaceData.surface);
365 std::cout << std::endl;
372 for (
int i = 0; i <
surface.corners(); ++i)
373 std::cout <<
surface.corner(i) << std::endl;
376 const auto& problem_()
const {
return gridVariables_.curGridVolVars().problem(); }
378 std::map<std::string, SurfaceData> surfaces_;
379 const GridVariables& gridVariables_;
380 const SolutionVector& sol_;
381 const LocalResidual localResidual_;
An axis-aligned bounding box volume tree implementation.
Definition: boundingboxtree.hh:56
Class used to calculate fluxes over axis-aligned surfaces.
Definition: fluxoveraxisalignedsurface.hh:37
void addAxisAlignedPlane(const std::string &name, const GlobalPosition ¢er, const std::size_t normalDirectionIndex)
Add an axis-aligned plane (line in 2D) with a given name, specifying the planes's center and normal.
Definition: fluxoveraxisalignedsurface.hh:133
FluxOverAxisAlignedSurface(const GridVariables &gridVariables, const SolutionVector &sol, const LocalResidual &localResidual)
The constructor.
Definition: fluxoveraxisalignedsurface.hh:71
void printAllFluxes() const
Prints all fluxes.
Definition: fluxoveraxisalignedsurface.hh:215
void addAxisAlignedSurface(const std::string &name, T &&surface)
Add an axis-aligned surface with a given name.
Definition: fluxoveraxisalignedsurface.hh:88
const std::map< std::string, SurfaceData > & surfaces() const
Provides access to all surfaces.
Definition: fluxoveraxisalignedsurface.hh:209
const auto & flux(const std::string &name) const
Return the flux over given surface.
Definition: fluxoveraxisalignedsurface.hh:201
void calculateAllFluxes()
Calculate the fluxes over all surfaces.
Definition: fluxoveraxisalignedsurface.hh:158
SurfaceT Surface
Definition: fluxoveraxisalignedsurface.hh:66
void addAxisAlignedSurface(const std::string &name, const GlobalPosition &lowerLeft, const GlobalPosition &upperRight)
Add an axis-aligned surface (segment in 2D) with a given name, specifying the surface's corner points...
Definition: fluxoveraxisalignedsurface.hh:103
void calculateFluxes(const FluxType &fluxType)
Calculate the fluxes over all surfaces for a given flux type.
Definition: fluxoveraxisalignedsurface.hh:186
An interface for a set of geometric entities.
Definition: geometricentityset.hh:109
A function to compute a geometry's diameter, i.e. the longest distance between points of a geometry.
Helper functions for distance queries.
An interface for a set of geometric entities.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.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
static ctype distance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest distance between two points.
Definition: distance.hh:282
static Geometry::ctype distancePointPolygon(const typename Geometry::GlobalCoordinate &p, const Geometry &geometry)
Compute the shortest distance from a point to a given polygon geometry.
Definition: distance.hh:256
static Point::value_type distancePointSegment(const Point &p, const Point &a, const Point &b)
Compute the distance from a point to the segment connecting the points a and b.
Definition: distance.hh:135
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
Corners::value_type center(const Corners &corners)
The center of a given list of corners.
Definition: center.hh:24
Algorithms that finds which geometric entities intersect.
Detect if a point intersects a geometry.
constexpr Surface surface
Definition: couplingmanager1d3d_surface.hh:37
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.