// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*****************************************************************************
* See the file COPYING for full copying permissions. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
*****************************************************************************/
/*!
* \file
* \ingroup FreeflowModels
* \copydoc Dumux::FluxOverPlane
*/
#ifndef DUMUX_FLUX_OVER_PLANE_STAGGERED_HH
#define DUMUX_FLUX_OVER_PLANE_STAGGERED_HH
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace Dumux {
/*!
* \ingroup FreeflowModels
* \brief Class used to calculate fluxes over planes. This only works for the staggered grid discretization.
*/
template
class FluxOverPlane
{
using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
using GridVariables = typename GET_PROP_TYPE(TypeTag, GridVariables);
using Element = typename GridView::template Codim<0>::Entity;
using DofTypeIndices = typename GET_PROP(TypeTag, DofTypeIndices);
typename DofTypeIndices::CellCenterIdx cellCenterIdx;
typename DofTypeIndices::FaceIdx faceIdx;
enum {
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
using GlobalPosition = Dune::FieldVector;
static constexpr auto planeDim = dim - 1;
using PlaneGeometryType = Dune::AffineGeometry< Scalar, planeDim, dim >;
/*!
* \brief Auxiliary class that holds the plane-specific data.
*/
template
class PlaneData
{
using Geo = Dune::AffineGeometry< Scalar, mydim, coordDim >;
public:
PlaneData() {}
PlaneData(Geo&& geo)
{
values_.resize(1);
geometries_.push_back(std::move(geo));
}
PlaneData(std::vector&& geo)
{
values_.resize(geo.size());
geometries_ = std::forward(geo);
}
void addValue(int planeIdx, Scalar value)
{
values_[planeIdx] += value;
}
void addSubPlane(Geo&& geo)
{
values_.push_back(0.0);
geometries_.push_back(std::move(geo));
}
auto& subPlanes() const
{
return geometries_;
}
Scalar value(int planeIdx) const
{
return values_[planeIdx];
}
auto& values() const
{
return values_;
}
void printPlaneBoundaries(int planeIdx) const
{
const auto& geometry = geometries_[planeIdx];
for(int i = 0; i < geometry.corners(); ++i)
std::cout << geometry.corner(i) << " ";
}
void resetValues()
{
std::fill(values_.begin(), values_.end(), 0.0);
}
private:
std::vector geometries_;
std::vector values_;
};
public:
using PlaneList = std::vector;
/*!
* \brief The constructor
*
* \param assembler The assembler
* \param sol The solution vector
*/
template
FluxOverPlane(const Assembler& assembler,
const SolutionVector& sol)
: problem_(assembler.problem())
, gridVariables_(assembler.gridVariables())
, sol_(sol)
{
verbose_ = getParamFromGroup(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "FluxOverPlane.Verbose", false);
}
/*!
* \brief Add a collection of sub planes under a given name
*
* \param name The name of the plane
* \param planes The list of sub planes
*/
void addPlane(const std::string& name, PlaneList&& planes )
{
planes_[name] = PlaneData(std::forward(planes));
}
/*!
* \brief Add a plane under a given name, specifing the plane's corner points.
* This is a specialization for 2D, therefore the plane is actually a line.
*
* \param name The name of the plane
* \param p0 The first corner
* \param p1 The second corner
*/
void addPlane(const std::string& name, const GlobalPosition& p0, const GlobalPosition& p1)
{
planes_[name].addSubPlane(makePlane(p0, p1));
}
/*!
* \brief Add a plane under a given name, specifing the plane's corner points.
* This is a specialization for 3D.
*
* \param name The name of the plane
* \param p0 The first corner
* \param p1 The second corner
* \param p2 The third corner
* \param p3 The fourth corner
*/
void addPlane(const std::string& name,
const GlobalPosition& p0,
const GlobalPosition& p1,
const GlobalPosition& p2,
const GlobalPosition& p3)
{
planes_[name].addSubPlane(makePlane(p0, p1, p2, p3));
}
/*!
* \brief Creates a geometrical plane object.
* This is a specialization for 2D, therefore the plane is actually a line.
*
* \param p0 The first corner
* \param p1 The second corner
*/
static PlaneGeometryType makePlane(const GlobalPosition& p0, const GlobalPosition& p1)
{
const std::vector< Dune::FieldVector< Scalar, dim > > corners = {p0, p1};
#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6)
return PlaneGeometryType(Dune::GeometryTypes::line, corners);
#else
return PlaneGeometryType(Dune::GeometryType::simplex, corners);
#endif
}
/*!
* \brief Creates a geometrical plane object.
* This is a specialization for 3D.
*
* \param p0 The first corner
* \param p1 The second corner
* \param p2 The third corner
* \param p3 The fourth corner
*/
static PlaneGeometryType makePlane(const GlobalPosition& p0,
const GlobalPosition& p1,
const GlobalPosition& p2,
const GlobalPosition& p3)
{
const std::vector< Dune::FieldVector< Scalar, dim > > corners = {p0, p1, p2, p3};
#if DUNE_VERSION_NEWER(DUNE_COMMON,2,6)
return PlaneGeometryType(Dune::GeometryTypes::quadrilaterial, corners);
#else
return PlaneGeometryType(Dune::GeometryType::cube, corners);
#endif
}
/*!
* \brief Calculate the fluxes over all planes for a given flux type.
*
* \param fluxType The flux type. This can be a lambda of the following form:
* [](const auto& element,
* const auto& fvGeometry,
* const auto& scvf,
* const Scalar velocity) { return velocity * ... ;}
*/
template
void calculateFluxes(const FluxType& fluxType)
{
// make sure to reset all the values of the planes, in case this method has been called already before
for(auto&& plane : planes_)
plane.second.resetValues();
// make sure not to iterate over the same dofs twice
std::vector dofVisited(problem_.fvGridGeometry().numFaceDofs(), false);
for(auto&& element : elements(problem_.fvGridGeometry().gridView()))
{
auto fvGeometry = localView(problem_.fvGridGeometry());
fvGeometry.bindElement(element);
for(auto && scvf : scvfs(fvGeometry))
{
const auto dofIdx = scvf.dofIndex();
// do nothing of the dof was already visited
if(dofVisited[dofIdx])
continue;
dofVisited[dofIdx] = true;
// iterate through all planes and check if the flux at the given position
// should be accounted for in the respective plane
for(auto&& plane : planes_)
{
const auto& subPlanes = plane.second.subPlanes();
for(int planeIdx = 0; planeIdx < subPlanes.size(); ++planeIdx)
{
if(intersectsPointGeometry(scvf.center(), subPlanes[planeIdx]))
{
const Scalar velocity = sol_[faceIdx][dofIdx][0];
const Scalar result = fluxType(element, fvGeometry, scvf, velocity);
plane.second.addValue(planeIdx, result);
if(verbose_)
{
std::cout << "Flux at face " << scvf.center() << " (" << plane.first << "): " << result;
std::cout << " (directionIndex: " << scvf.directionIndex() << "; plane boundaries: ";
plane.second.printPlaneBoundaries(planeIdx);
std::cout << ", planeIdx " << planeIdx << ")" << std::endl;
}
}
}
}
}
}
}
/*!
* \brief Return the fluxes of the individual sub planes of a given name.
*
* \param name The name of the plane
*/
auto& values(const std::string& name) const
{
return planes_.at(name).values();
}
/*!
* \brief Return the cumulative net fluxes of a plane of a given name.
*
* \param name The name of the plane
*/
Scalar netFlux(const std::string& name) const
{
const auto& planeResults = values(name);
return std::accumulate(planeResults.begin(), planeResults.end(), 0.0);
}
private:
std::map > planes_;
const Problem& problem_;
const GridVariables& gridVariables_;
const SolutionVector& sol_;
bool verbose_;
};
} //end namespace
#endif