// -*- 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 3 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 PoreNetworkDiscretization
* \brief Base class for the local geometry for porenetworks
*/
#ifndef DUMUX_DISCRETIZATION_PNM_FV_ELEMENT_GEOMETRY_HH
#define DUMUX_DISCRETIZATION_PNM_FV_ELEMENT_GEOMETRY_HH
#include
#include
#include
#include
namespace Dumux::PoreNetwork {
/*!
* \ingroup PoreNetworkDiscretization
* \brief Base class for the local geometry for porenetworks
* \tparam GG the finite volume grid geometry type
* \tparam enableFVGridGeometryCache if the grid geometry is cached or not
*/
template
class PNMFVElementGeometry;
//! specialization in case the FVElementGeometries are stored
template
class PNMFVElementGeometry
{
using GridView = typename GG::GridView;
static constexpr int dim = GridView::dimension;
static constexpr int dimWorld = GridView::dimensionworld;
using GridIndexType = typename IndexTraits::GridIndex;
using LocalIndexType = typename IndexTraits::LocalIndex;
using Element = typename GridView::template Codim<0>::Entity;
using CoordScalar = typename GridView::ctype;
using FeLocalBasis = typename GG::FeCache::FiniteElementType::Traits::LocalBasisType;
public:
//! export type of subcontrol volume
using SubControlVolume = typename GG::SubControlVolume;
//! export type of subcontrol volume face
using SubControlVolumeFace = typename GG::SubControlVolumeFace;
//! export type of finite volume grid geometry
using GridGeometry = GG;
//! the maximum number of scvs per element
static constexpr std::size_t maxNumElementScvs = 2;
//! Constructor
PNMFVElementGeometry(const GridGeometry& gridGeometry)
: gridGeometryPtr_(&gridGeometry) {}
//! Get a sub control volume with a local scv index
const SubControlVolume& scv(LocalIndexType scvIdx) const
{
return gridGeometry().scvs(eIdx_)[scvIdx];
}
//! Get a sub control volume face with a local scvf index
const SubControlVolumeFace& scvf(LocalIndexType scvfIdx) const
{
return gridGeometry().scvfs(eIdx_)[scvfIdx];
}
//! iterator range for sub control volumes. Iterates over
//! all scvs of the bound element.
//! This is a free function found by means of ADL
//! To iterate over all sub control volumes of this FVElementGeometry use
//! for (auto&& scv : scvs(fvGeometry))
friend inline auto scvs(const PNMFVElementGeometry& fvGeometry)
{
const auto& g = fvGeometry.gridGeometry();
using Iter = typename std::decay_t::const_iterator;
return Dune::IteratorRange(g.scvs(fvGeometry.eIdx_).begin(), g.scvs(fvGeometry.eIdx_).end());
}
//! iterator range for sub control volumes faces. Iterates over
//! all scvfs of the bound element.
//! This is a free function found by means of ADL
//! To iterate over all sub control volume faces of this FVElementGeometry use
//! for (auto&& scvf : scvfs(fvGeometry))
friend inline auto scvfs(const PNMFVElementGeometry& fvGeometry)
{
const auto& g = fvGeometry.gridGeometry();
using Iter = typename std::decay_t::const_iterator;
return Dune::IteratorRange(g.scvfs(fvGeometry.eIdx_).begin(), g.scvfs(fvGeometry.eIdx_).end());
}
//! Get a local finite element basis
const FeLocalBasis& feLocalBasis() const
{
return gridGeometry().feCache().get(element_->type()).localBasis();
}
//! The total number of sub control volumes
std::size_t numScv() const
{
return gridGeometry().scvs(eIdx_).size();
}
//! The total number of sub control volume faces
std::size_t numScvf() const
{
return gridGeometry().scvfs(eIdx_).size();
}
//! this function is for compatibility reasons with cc methods
//! The box stencil is always element-local so bind and bindElement
//! are identical.
void bind(const Element& element)
{
this->bindElement(element);
}
//! Binding of an element, has to be called before using the fvgeometries
//! Prepares all the volume variables within the element
//! For compatibility reasons with the FVGeometry cache being disabled
void bindElement(const Element& element)
{
element_ = element;
eIdx_ = gridGeometry().elementMapper().index(element);
}
//! Returns true if bind/bindElement has already been called
bool isBound() const
{ return static_cast(element_); }
//! The bound element
const Element& element() const
{ return *element_; }
//! The global finite volume geometry we are a restriction of
const GridGeometry& gridGeometry() const
{ return *gridGeometryPtr_; }
//! Returns whether one of the geometry's scvfs lies on a boundary
bool hasBoundaryScvf() const
{ return gridGeometry().hasBoundaryScvf(eIdx_); }
private:
std::optional element_;
const GridGeometry* gridGeometryPtr_;
GridIndexType eIdx_;
};
//! specialization in case the FVElementGeometries are not stored
template
class PNMFVElementGeometry
{
using GridView = typename GG::GridView;
static constexpr int dim = GridView::dimension;
static constexpr int dimWorld = GridView::dimensionworld;
using GridIndexType = typename IndexTraits::GridIndex;
using LocalIndexType = typename IndexTraits::LocalIndex;
using Element = typename GridView::template Codim<0>::Entity;
using CoordScalar = typename GridView::ctype;
using FeLocalBasis = typename GG::FeCache::FiniteElementType::Traits::LocalBasisType;
public:
//! export type of subcontrol volume
using SubControlVolume = typename GG::SubControlVolume;
//! export type of subcontrol volume face
using SubControlVolumeFace = typename GG::SubControlVolumeFace;
//! export type of finite volume grid geometry
using GridGeometry = GG;
//! the maximum number of scvs per element
static constexpr std::size_t maxNumElementScvs = 2;
//! Constructor
PNMFVElementGeometry(const GridGeometry& gridGeometry)
: gridGeometryPtr_(&gridGeometry) {}
//! Get a sub control volume with a local scv index
const SubControlVolume& scv(LocalIndexType scvIdx) const
{
return scvs_[scvIdx];
}
//! Get a sub control volume face with a local scvf index
const SubControlVolumeFace& scvf(LocalIndexType scvfIdx) const
{
return scvfs_[0];
}
//! iterator range for sub control volumes. Iterates over
//! all scvs of the bound element.
//! This is a free function found by means of ADL
//! To iterate over all sub control volumes of this FVElementGeometry use
//! for (auto&& scv : scvs(fvGeometry))
friend inline auto scvs(const PNMFVElementGeometry& fvGeometry)
{
using Iter = typename std::decay_t::const_iterator;
return Dune::IteratorRange(fvGeometry.scvs_.begin(), fvGeometry.scvs_.end());
}
//! iterator range for sub control volumes faces. Iterates over
//! all scvfs of the bound element.
//! This is a free function found by means of ADL
//! To iterate over all sub control volume faces of this FVElementGeometry use
//! for (auto&& scvf : scvfs(fvGeometry))
friend inline auto scvfs(const PNMFVElementGeometry& fvGeometry)
{
using Iter = typename std::decay_t::const_iterator;
return Dune::IteratorRange(fvGeometry.scvfs_.begin(), fvGeometry.scvfs_.end());
}
//! Get a local finite element basis
const FeLocalBasis& feLocalBasis() const
{
return gridGeometry().feCache().get(element_->type()).localBasis();
}
//! The total number of sub control volumes
std::size_t numScv() const
{
return scvs_.size();
}
//! The total number of sub control volume faces
std::size_t numScvf() const
{
return scvfs_.size();
}
//! this function is for compatibility reasons with cc methods
//! The box stencil is always element-local so bind and bindElement
//! are identical.
void bind(const Element& element)
{
this->bindElement(element);
}
//! Binding of an element, has to be called before using the fvgeometries
//! Prepares all the volume variables within the element
//! For compatibility reasons with the FVGeometry cache being disabled
void bindElement(const Element& element)
{
element_ = element;
eIdx_ = gridGeometry().elementMapper().index(element);
makeElementGeometries(element);
}
//! Returns true if bind/bindElement has already been called
bool isBound() const
{ return static_cast(element_); }
//! The bound element
const Element& element() const
{ return *element_; }
//! The global finite volume geometry we are a restriction of
const GridGeometry& gridGeometry() const
{ return *gridGeometryPtr_; }
//! Returns whether one of the geometry's scvfs lies on a boundary
bool hasBoundaryScvf() const
{ return hasBoundaryScvf_; }
private:
void makeElementGeometries(const Element& element)
{
hasBoundaryScvf_ = false;
// get the element geometry
auto elementGeometry = element.geometry();
// construct the sub control volumes
for (LocalIndexType scvLocalIdx = 0; scvLocalIdx < elementGeometry.corners(); ++scvLocalIdx)
{
// get asssociated dof index
const auto dofIdxGlobal = gridGeometry().vertexMapper().subIndex(element, scvLocalIdx, dim);
// get the corners
auto corners = std::array{elementGeometry.corner(scvLocalIdx), elementGeometry.center()};
// get the fractional volume asssociated with the scv
const auto volume = gridGeometry().poreVolume(dofIdxGlobal) / gridGeometry().coordinationNumber(dofIdxGlobal);
// add scv to the local container
scvs_[scvLocalIdx] = SubControlVolume(dofIdxGlobal,
scvLocalIdx,
eIdx_,
std::move(corners),
volume);
if (gridGeometry().poreLabel(dofIdxGlobal) > 0)
hasBoundaryScvf_ = true;
}
// construct the inner sub control volume face
auto unitOuterNormal = elementGeometry.corner(1) - elementGeometry.corner(0);
unitOuterNormal /= unitOuterNormal.two_norm();
LocalIndexType scvfLocalIdx = 0;
scvfs_[0] = SubControlVolumeFace(elementGeometry.center(),
std::move(unitOuterNormal),
gridGeometry().throatCrossSectionalArea(gridGeometry().elementMapper().index(element)),
scvfLocalIdx++,
std::array({0, 1}));
}
//! The bound element
std::optional element_;
GridIndexType eIdx_;
//! The global geometry this is a restriction of
const GridGeometry* gridGeometryPtr_;
//! vectors to store the geometries locally after binding an element
std::array scvs_;
std::array scvfs_;
bool hasBoundaryScvf_ = false;
};
} // end namespace Dumux::PoreNetwork
#endif