// -*- 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
* \brief The free flow sub problem
*/
#ifndef DUMUX_STOKES_SUBPROBLEM_HH
#define DUMUX_STOKES_SUBPROBLEM_HH
#include
#include
namespace Dumux {
/*!
* \brief The free flow sub problem
*/
template
class FreeFlowSubProblem : public NavierStokesProblem
{
using ParentType = NavierStokesProblem;
using GridView = typename GetPropType::GridView;
using Scalar = GetPropType;
using Indices = typename GetPropType::Indices;
using BoundaryTypes = GetPropType;
using FVGridGeometry = GetPropType;
using FVElementGeometry = typename FVGridGeometry::LocalView;
using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
using Element = typename GridView::template Codim<0>::Entity;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
using PrimaryVariables = GetPropType;
using NumEqVector = GetPropType;
using FluidSystem = GetPropType;
using CouplingManager = GetPropType;
public:
FreeFlowSubProblem(std::shared_ptr fvGridGeometry, std::shared_ptr couplingManager)
: ParentType(fvGridGeometry, "Stokes"), eps_(1e-6), couplingManager_(couplingManager)
{
deltaP_ = getParamFromGroup(this->paramGroup(), "Problem.PressureDifference");
}
/*!
* \name Problem parameters
*/
// \{
/*!
* \brief Return the temperature within the domain in [K].
*
* This problem assumes a temperature of 10 degrees Celsius.
*/
Scalar temperature() const
{ return 273.15 + 10; } // 10°C
/*!
* \brief Return the sources within the domain.
*
* \param globalPos The global position
*/
NumEqVector sourceAtPos(const GlobalPosition &globalPos) const
{ return NumEqVector(0.0); }
// \}
/*!
* \name Boundary conditions
*/
// \{
/*!
* \brief Specifies which kind of boundary condition should be
* used for which equation on a given boundary segment.
*
* \param element The finite element
* \param scvf The sub control volume face
*/
BoundaryTypes boundaryTypes(const Element& element,
const SubControlVolumeFace& scvf) const
{
BoundaryTypes values;
const auto& globalPos = scvf.dofPosition();
// TODO: dumux-course-task 1.A
// Change the boundary conditions here as described in the exercise
if(onUpperBoundary_(globalPos))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
}
// left/right wall
if (onRightBoundary_(globalPos) || (onLeftBoundary_(globalPos)))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
}
// coupling interface
if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values.setCouplingNeumann(Indices::conti0EqIdx);
values.setCouplingNeumann(Indices::momentumYBalanceIdx);
// TODO: dumux-course-task 1.B
// Replace Dirichlet BC with Beavers-Joseph-Saffman slip condition for the tangential momentum balance
values.setDirichlet(Indices::velocityXIdx); // assume no slip on interface
// TODO: dumux-course-task 1.C
// set the Beaver-Joseph-Saffman slip condition for the tangential momentum balance equation,
// consider orientation of face automatically
}
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Dirichlet control volume.
*
* \param globalPos The global position
*/
PrimaryVariables dirichletAtPos(const GlobalPosition& globalPos) const
{
PrimaryVariables values(0.0);
values = initialAtPos(globalPos);
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Neumann control volume.
*
* \param element The element for which the Neumann boundary condition is set
* \param fvGeomentry The fvGeometry
* \param elemVolVars The element volume variables
* \param elemFaceVars The element face variables
* \param scvf The boundary sub control volume face
*/
template
NumEqVector neumann(const Element& element,
const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
const ElementFaceVariables& elemFaceVars,
const SubControlVolumeFace& scvf) const
{
NumEqVector values(0.0);
if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values[Indices::conti0EqIdx] = couplingManager().couplingData().massCouplingCondition(element, fvGeometry, elemVolVars, elemFaceVars, scvf);
values[Indices::momentumYBalanceIdx] = couplingManager().couplingData().momentumCouplingCondition(element, fvGeometry, elemVolVars, elemFaceVars, scvf);
}
return values;
}
// \}
//! Set the coupling manager
void setCouplingManager(std::shared_ptr cm)
{ couplingManager_ = cm; }
//! Get the coupling manager
const CouplingManager& couplingManager() const
{ return *couplingManager_; }
/*!
* \name Volume terms
*/
// \{
/*!
* \brief Evaluate the initial value for a control volume.
*
* \param globalPos The global position
*/
PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
{
PrimaryVariables values(0.0);
values[Indices::velocityYIdx] = -1e-6 * globalPos[0] * (this->gridGeometry().bBoxMax()[0] - globalPos[0]);
// TODO: dumux-course-task 1.A
// Set fixed pressures on the left and right boundary
return values;
}
/*!
* \brief Returns the intrinsic permeability of required as input parameter for the Beavers-Joseph-Saffman boundary condition
*/
Scalar permeability(const Element& element, const SubControlVolumeFace& scvf) const
{
return couplingManager().couplingData().darcyPermeability(element, scvf);
}
/*!
* \brief Returns the alpha value required as input parameter for the Beavers-Joseph-Saffman boundary condition
*/
Scalar alphaBJ(const SubControlVolumeFace& scvf) const
{
return couplingManager().problem(CouplingManager::darcyIdx).spatialParams().beaversJosephCoeffAtPos(scvf.center());
}
/*!
* \brief calculate the analytical velocity in x direction based on Beavers & Joseph (1967)
*/
void calculateAnalyticalVelocityX() const
{
analyticalVelocityX_.resize(this->gridGeometry().gridView().size(0));
using std::sqrt;
const Scalar dPdX = -deltaP_ / (this->gridGeometry().bBoxMax()[0] - this->gridGeometry().bBoxMin()[0]);
static const Scalar mu = FluidSystem::viscosity(temperature(), 1e5);
static const Scalar alpha = getParam("Darcy.SpatialParams.AlphaBeaversJoseph");
static const Scalar K = getParam("Darcy.SpatialParams.Permeability");
static const Scalar sqrtK = sqrt(K);
const Scalar sigma = (this->gridGeometry().bBoxMax()[1] - this->gridGeometry().bBoxMin()[1])/sqrtK;
const Scalar uB = -K/(2.0*mu) * ((sigma*sigma + 2.0*alpha*sigma) / (1.0 + alpha*sigma)) * dPdX;
for (const auto& element : elements(this->gridGeometry().gridView()))
{
const auto eIdx = this->gridGeometry().gridView().indexSet().index(element);
const Scalar y = element.geometry().center()[1] - this->gridGeometry().bBoxMin()[1];
const Scalar u = uB*(1.0 + alpha/sqrtK*y) + 1.0/(2.0*mu) * (y*y + 2*alpha*y*sqrtK) * dPdX;
analyticalVelocityX_[eIdx] = u;
}
}
/*!
* \brief Get the analytical velocity in x direction
*/
const std::vector& getAnalyticalVelocityX() const
{
if(analyticalVelocityX_.empty())
calculateAnalyticalVelocityX();
return analyticalVelocityX_;
}
// \}
private:
bool onLeftBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] < this->gridGeometry().bBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[0] > this->gridGeometry().bBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] < this->gridGeometry().bBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition &globalPos) const
{ return globalPos[1] > this->gridGeometry().bBoxMax()[1] - eps_; }
Scalar eps_;
Scalar deltaP_;
std::shared_ptr couplingManager_;
mutable std::vector analyticalVelocityX_;
};
} //end namespace Dumux
#endif