// -*- 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_FREEFLOW1P2C_SUBPROBLEM_HH
#define DUMUX_FREEFLOW1P2C_SUBPROBLEM_HH
#if EXNUMBER >= 1
#include
#else
#include
#endif
#include
#include
#include
namespace Dumux {
/*!
* \brief The free-flow sub problem
*/
template
#if EXNUMBER >= 1
class FreeFlowSubProblem : public RANSProblem
{
using ParentType = RANSProblem;
#else
class FreeFlowSubProblem : public NavierStokesProblem
{
using ParentType = NavierStokesProblem;
#endif
using GridView = typename GetPropType::GridView;
using Scalar = GetPropType;
using FluidSystem = 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 ElementVolumeVariables = typename GetPropType::LocalView;
using ElementFaceVariables = typename GetPropType::LocalView;
using FluidState = GetPropType;
using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
using PrimaryVariables = GetPropType;
using NumEqVector = GetPropType;
using CouplingManager = GetPropType;
using TimeLoopPtr = std::shared_ptr>;
using DiffusionCoefficientAveragingType = typename StokesDarcyCouplingOptions::DiffusionCoefficientAveragingType;
static constexpr bool useMoles = GetPropType::useMoles();
public:
FreeFlowSubProblem(std::shared_ptr fvGridGeometry, std::shared_ptr couplingManager)
: ParentType(fvGridGeometry, "Stokes"), eps_(1e-6), couplingManager_(couplingManager)
{
refVelocity_ = getParamFromGroup(this->paramGroup(), "Problem.RefVelocity");
refPressure_ = getParamFromGroup(this->paramGroup(), "Problem.RefPressure");
refMoleFrac_ = getParamFromGroup(this->paramGroup(), "Problem.refMoleFrac");
refTemperature_ = getParamFromGroup(this->paramGroup(), "Problem.RefTemperature");
diffCoeffAvgType_ = StokesDarcyCouplingOptions::stringToEnum(DiffusionCoefficientAveragingType{},
getParamFromGroup(this->paramGroup(), "Problem.InterfaceDiffusionCoefficientAvg"));
}
/*!
* \name Problem parameters
*/
// \{
/*!
* \brief Return the temperature within the domain in [K].
*/
Scalar temperature() const
{ return refTemperature_; }
/*!
* \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.center();
if (onLeftBoundary_(globalPos))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
values.setDirichlet(Indices::conti0EqIdx + 1);
values.setDirichlet(Indices::energyEqIdx);
}
if (onLowerBoundary_(globalPos))
{
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
values.setNeumann(Indices::conti0EqIdx);
values.setNeumann(Indices::conti0EqIdx + 1);
values.setNeumann(Indices::energyEqIdx);
}
if (onUpperBoundary_(globalPos))
{
#if EXNUMBER >=2
values.setAllSymmetry();
#else
values.setDirichlet(Indices::velocityXIdx);
values.setDirichlet(Indices::velocityYIdx);
values.setNeumann(Indices::conti0EqIdx);
values.setNeumann(Indices::conti0EqIdx + 1);
values.setNeumann(Indices::energyEqIdx);
#endif
}
if (onRightBoundary_(globalPos))
{
values.setDirichlet(Indices::pressureIdx);
values.setOutflow(Indices::conti0EqIdx + 1);
values.setOutflow(Indices::energyEqIdx);
}
if (couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values.setCouplingNeumann(Indices::conti0EqIdx);
values.setCouplingNeumann(Indices::conti0EqIdx + 1);
values.setCouplingNeumann(Indices::energyEqIdx);
values.setCouplingNeumann(Indices::momentumYBalanceIdx);
values.setBeaversJoseph(Indices::momentumXBalanceIdx);
}
return values;
}
/*!
* \brief Evaluate the boundary conditions for a Dirichlet control volume.
*
* \param element The element
* \param scvf The subcontrolvolume face
*/
PrimaryVariables dirichletAtPos(const GlobalPosition& pos) const
{
PrimaryVariables values(0.0);
values = initialAtPos(pos);
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
*/
NumEqVector neumann(const Element& element,
const FVElementGeometry& fvGeometry,
const ElementVolumeVariables& elemVolVars,
const ElementFaceVariables& elemFaceVars,
const SubControlVolumeFace& scvf) const
{
PrimaryVariables values(0.0);
if(couplingManager().isCoupledEntity(CouplingManager::stokesIdx, scvf))
{
values[Indices::momentumYBalanceIdx] = couplingManager().couplingData().momentumCouplingCondition(element, fvGeometry, elemVolVars, elemFaceVars, scvf);
const auto massFlux = couplingManager().couplingData().massCouplingCondition(element, fvGeometry, elemVolVars, elemFaceVars, scvf, diffCoeffAvgType_);
values[Indices::conti0EqIdx] = massFlux[0];
values[Indices::conti0EqIdx + 1] = massFlux[1];
values[Indices::energyEqIdx] = couplingManager().couplingData().energyCouplingCondition(element, fvGeometry, elemVolVars, elemFaceVars, scvf, diffCoeffAvgType_);
}
return values;
}
// \}
/*!
* \brief Set the coupling manager
*/
void setCouplingManager(std::shared_ptr cm)
{ couplingManager_ = cm; }
/*!
* \brief Get the coupling manager
*/
const CouplingManager& couplingManager() const
{ return *couplingManager_; }
#if EXNUMBER >= 2
bool isOnWallAtPos(const GlobalPosition& globalPos) const
{
return (onLowerBoundary_(globalPos));
}
#elif EXNUMBER >= 1
bool isOnWallAtPos(const GlobalPosition& globalPos) const
{
return (onLowerBoundary_(globalPos) || onUpperBoundary_(globalPos));
}
#endif
/*!
* \name Volume terms
*/
// \{
/*!
* \brief Evaluate the initial value for a control volume.
*
* \param globalPos The global position
*/
PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
{
FluidState fluidState;
updateFluidStateForBC_(fluidState, refTemperature(), refPressure(), refMoleFrac());
const Scalar density = FluidSystem::density(fluidState, 0);
PrimaryVariables values(0.0);
values[Indices::pressureIdx] = refPressure() + density*this->gravity()[1]*(globalPos[1] - this->gridGeometry().bBoxMin()[1]);
values[Indices::conti0EqIdx + 1] = refMoleFrac();
values[Indices::velocityXIdx] = refVelocity();
values[Indices::temperatureIdx] = refTemperature();
#if EXNUMBER >= 2
if(onLowerBoundary_(globalPos))
values[Indices::velocityXIdx] = 0.0;
#else
if(onUpperBoundary_(globalPos) || onLowerBoundary_(globalPos))
values[Indices::velocityXIdx] = 0.0;
#endif
return values;
}
//! \brief Returns the reference velocity.
const Scalar refVelocity() const
{ return refVelocity_ ;}
//! \brief Returns the reference pressure.
const Scalar refPressure() const
{ return refPressure_; }
//! \brief Returns the reference mass fraction.
const Scalar refMoleFrac() const
{ return refMoleFrac_; }
//! \brief Returns the reference temperature.
const Scalar refTemperature() const
{ return refTemperature_; }
void setTimeLoop(TimeLoopPtr timeLoop)
{ timeLoop_ = timeLoop; }
/*!
* \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().problem(CouplingManager::darcyIdx).spatialParams().permeabilityAtPos(scvf.center());
}
/*!
* \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());
}
// \}
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_; }
//! \brief updates the fluid state to obtain required quantities for IC/BC
void updateFluidStateForBC_(FluidState& fluidState, const Scalar temperature,
const Scalar pressure, const Scalar moleFraction) const
{
fluidState.setTemperature(temperature);
fluidState.setPressure(0, pressure);
fluidState.setSaturation(0, 1.0);
fluidState.setMoleFraction(0, 1, moleFraction);
fluidState.setMoleFraction(0, 0, 1.0 - moleFraction);
typename FluidSystem::ParameterCache paramCache;
paramCache.updatePhase(fluidState, 0);
const Scalar density = FluidSystem::density(fluidState, paramCache, 0);
fluidState.setDensity(0, density);
const Scalar molarDensity = FluidSystem::molarDensity(fluidState, paramCache, 0);
fluidState.setMolarDensity(0, molarDensity);
const Scalar enthalpy = FluidSystem::enthalpy(fluidState, paramCache, 0);
fluidState.setEnthalpy(0, enthalpy);
}
// the height of the free-flow domain
const Scalar height_() const
{ return this->gridGeometry().bBoxMax()[1] - this->gridGeometry().bBoxMin()[1]; }
Scalar eps_;
Scalar refVelocity_;
Scalar refPressure_;
Scalar refMoleFrac_;
Scalar refTemperature_;
TimeLoopPtr timeLoop_;
std::shared_ptr couplingManager_;
DiffusionCoefficientAveragingType diffCoeffAvgType_;
};
} //end namespace Dumux
#endif