Commit c40e1cc0 authored by Dennis Gläser's avatar Dennis Gläser Committed by Timo Koch
Browse files

[mpfa] do not allow mixed BC

The treatment of mixed BC is questionable for cc methods. Not allowing
for it enables us to not have to store n interaction volume seeds at the boundary.
parent 651643f9
......@@ -278,10 +278,8 @@ public:
{ return boundaryInfo_[eqIdx].isDirichlet; }
/*!
* \brief Returns true if an equation is used to specify a
* \brief Returns true if all equations are used to specify a
* Dirichlet condition.
*
* \param eqIdx The index of the equation
*/
bool hasOnlyDirichlet() const
{
......@@ -312,6 +310,18 @@ public:
bool isNeumann(unsigned eqIdx) const
{ return boundaryInfo_[eqIdx].isNeumann; }
/*!
* \brief Returns true if all equations are used to specify a
* Neumann condition.
*/
bool hasOnlyNeumann() const
{
return std::all_of(boundaryInfo_.begin(),
boundaryInfo_.end(),
[](const BoundaryInfo& b){ return b.isNeumann; }
);
}
/*!
* \brief Returns true if some equation is used to specify a
* Neumann condition.
......
......@@ -119,7 +119,7 @@ public:
Stencil stencil;
if(problem.model().globalFvGeometry().scvfTouchesBoundary(scvf))
{
const auto& ivSeed = problem.model().globalFvGeometry().boundaryInteractionVolumeSeed(scvf, /*dummy*/0);
const auto& ivSeed = problem.model().globalFvGeometry().boundaryInteractionVolumeSeed(scvf);
const auto& localScvSeeds = ivSeed.scvSeeds();
stencil.reserve(localScvSeeds.size());
......
......@@ -78,13 +78,13 @@ public:
// update the flux var caches for this scvf
if (problem.model().globalFvGeometry().scvfTouchesBoundary(scvf))
{
// we assume phaseIdx = eqIdx here for purely advective problems
for (unsigned int eqIdx = 0; eqIdx < numEq; ++eqIdx)
{
const auto& boundarySeed = problem.model().globalFvGeometry().boundaryInteractionVolumeSeed(scvf, eqIdx);
const auto& boundarySeed = problem.model().globalFvGeometry().boundaryInteractionVolumeSeed(scvf);
BoundaryInteractionVolume iv(boundarySeed, problem, fvGeometry, elemVolVars);
iv.solveLocalSystem(permFunction);
// we assume phaseIdx = eqIdx here for purely advective problems
for (unsigned int eqIdx = 0; eqIdx < numEq; ++eqIdx)
{
// lambda function defining the upwind factor of the advective flux
auto advectionUpwindFunction = [eqIdx](const VolumeVariables& volVars) { return volVars.density(eqIdx)/volVars.viscosity(eqIdx); };
iv.assembleNeumannFluxes(advectionUpwindFunction, eqIdx);
......
......@@ -107,8 +107,8 @@ public:
{ return globalInteractionVolumeSeeds_.seed(scvf); }
//! Get the boundary interaction volume seed corresponding to an scvf
const BoundaryInteractionVolumeSeed& boundaryInteractionVolumeSeed(const SubControlVolumeFace& scvf, const LocalIndexType eqIdx) const
{ return globalInteractionVolumeSeeds_.boundarySeed(scvf, eqIdx); }
const BoundaryInteractionVolumeSeed& boundaryInteractionVolumeSeed(const SubControlVolumeFace& scvf) const
{ return globalInteractionVolumeSeeds_.boundarySeed(scvf); }
//! Returns whether or not a scvf touches the boundary (has to be called before getting an interaction volume)
bool scvfTouchesBoundary(const SubControlVolumeFace& scvf) const
......
......@@ -74,18 +74,13 @@ public:
const InteractionVolumeSeed& seed(const SubControlVolumeFace& scvf) const
{ return seeds_[scvfIndexMap_[scvf.index()]]; }
const BoundaryInteractionVolumeSeed& boundarySeed(const SubControlVolumeFace& scvf, const LocalIndexType eqIdx) const
{
assert(boundarySeeds_[scvfIndexMap_[scvf.index()]].size() > eqIdx);
return boundarySeeds_[scvfIndexMap_[scvf.index()]][eqIdx];
}
const BoundaryInteractionVolumeSeed& boundarySeed(const SubControlVolumeFace& scvf) const
{ return boundarySeeds_[scvfIndexMap_[scvf.index()]]; }
private:
void initializeBoundarySeeds_()
{
auto numBoundaryScvf = problem_().model().globalFvGeometry().numBoundaryScvf();
boundarySeeds_.reserve(numBoundaryScvf);
boundarySeeds_.reserve(problem_().model().globalFvGeometry().numBoundaryScvf());
IndexType boundarySeedIndex = 0;
for (const auto& element : elements(gridView_))
{
......@@ -97,19 +92,16 @@ private:
if (scvfIndexMap_[scvf.index()] != -1 || !scvf.boundary())
continue;
// container to store the interaction volume seeds
std::vector<BoundaryInteractionVolumeSeed> seedVector;
seedVector.reserve(numEq);
for (LocalIndexType eqIdx = 0; eqIdx < numEq; ++eqIdx)
seedVector.emplace_back(Helper::makeBoundaryInteractionVolumeSeed(problem_(), element, fvGeometry, scvf, eqIdx));
// the boundary interaction volume seed
auto seed = Helper::makeBoundaryInteractionVolumeSeed(problem_(), element, fvGeometry, scvf);
// update the index map entries for the global scv faces in the interaction volume
for (const auto& localScvfSeed : seedVector[0].scvfSeeds())
for (const auto& localScvfSeed : seed.scvfSeeds())
for (const auto scvfIdxGlobal : localScvfSeed.globalScvfIndices())
scvfIndexMap_[scvfIdxGlobal] = boundarySeedIndex;
// store interaction volume and increment counter
boundarySeeds_.emplace_back(std::move(seedVector));
boundarySeeds_.emplace_back(std::move(seed));
boundarySeedIndex++;
}
}
......@@ -120,13 +112,13 @@ private:
void initializeInteriorSeeds_()
{
auto numScvf = problem_().model().globalFvGeometry().numScvf();
seeds_.reserve(numScvf);
const auto& globalFvGeometry = problem_().model().globalFvGeometry();
seeds_.reserve(globalFvGeometry.numScvf() - globalFvGeometry.numBoundaryScvf());
IndexType seedIndex = 0;
for (const auto& element : elements(gridView_))
{
auto fvGeometry = localView(problem_().model().globalFvGeometry());
auto fvGeometry = localView(globalFvGeometry);
fvGeometry.bind(element);
for (const auto& scvf : scvfs(fvGeometry))
{
......@@ -158,7 +150,7 @@ private:
GridView gridView_;
std::vector<IndexType> scvfIndexMap_;
std::vector<InteractionVolumeSeed> seeds_;
std::vector<std::vector<BoundaryInteractionVolumeSeed>> boundarySeeds_;
std::vector<BoundaryInteractionVolumeSeed> boundarySeeds_;
};
} // end namespace
......
......@@ -95,25 +95,6 @@ public:
volumeVariables_[scvf.outsideScvIdx()].update(dirichletPriVars, problem, element, insideScv);
}
else if (bcTypes.hasDirichlet())
{
const auto insideScvIdx = scvf.insideScvIdx();
const auto& insideScv = fvGeometry.scv(insideScvIdx);
const auto dirichletPriVars = problem.dirichlet(element, scvf);
PrimaryVariables priVars(0.0);
for (unsigned int eqIdx = 0; eqIdx < GET_PROP_VALUE(TypeTag, NumEq); ++eqIdx)
{
auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
if (bcTypes.isDirichlet(eqIdx))
priVars[pvIdx] = dirichletPriVars[pvIdx];
else
priVars[pvIdx] = volumeVariables_[scvf.insideScvIdx()].priVar(pvIdx);
}
volumeVariables_[scvf.outsideScvIdx()].update(priVars, problem, element, insideScv);
}
else
{
volumeVariables_[scvf.outsideScvIdx()] = volumeVariables_[scvf.insideScvIdx()];
......
......@@ -245,20 +245,22 @@ public:
// Returns the MpfaFaceType of an scv face
static MpfaFaceTypes getMpfaFaceType(const Problem& problem,
const Element& element,
const SubControlVolumeFace& scvf,
const LocalIndexType eqIdx)
const SubControlVolumeFace& scvf)
{
if (!scvf.boundary())
return MpfaFaceTypes::interior;
auto bcTypes = problem.boundaryTypes(element, scvf);
if (bcTypes.isNeumann(eqIdx))
if (bcTypes.hasOnlyNeumann())
return MpfaFaceTypes::neumann;
if (bcTypes.isDirichlet(eqIdx))
if (bcTypes.hasOnlyDirichlet())
return MpfaFaceTypes::dirichlet;
if (bcTypes.isOutflow(eqIdx))
// throw for outflow or mixed boundary conditions
if (bcTypes.hasOutflow())
DUNE_THROW(Dune::NotImplemented, "outflow BC for mpfa schemes");
if (bcTypes.hasDirichlet() && bcTypes.hasNeumann())
DUNE_THROW(Dune::InvalidStateException, "Mixed BC are not allowed for cellcentered schemes");
DUNE_THROW(Dune::InvalidStateException, "unknown boundary condition type");
}
......
......@@ -71,20 +71,19 @@ public:
std::vector<ScvSeed> scvSeeds;
std::vector<ScvfSeed> scvfSeeds;
fillEntitySeeds_(scvSeeds, scvfSeeds, problem, element, fvGeometry, scvf, /*dummy*/0);
fillEntitySeeds_(scvSeeds, scvfSeeds, problem, element, fvGeometry, scvf);
return InteractionVolumeSeed(std::move(scvSeeds), std::move(scvfSeeds), false);
}
static InteractionVolumeSeed makeBoundaryInteractionVolumeSeed(const Problem& problem,
const Element& element,
const FVElementGeometry& fvGeometry,
const SubControlVolumeFace& scvf,
const LocalIndexType eqIdx)
const SubControlVolumeFace& scvf)
{
std::vector<ScvSeed> scvSeeds;
std::vector<ScvfSeed> scvfSeeds;
fillEntitySeeds_(scvSeeds, scvfSeeds, problem, element, fvGeometry, scvf, eqIdx);
fillEntitySeeds_(scvSeeds, scvfSeeds, problem, element, fvGeometry, scvf);
return InteractionVolumeSeed(std::move(scvSeeds), std::move(scvfSeeds), true);
}
......@@ -94,8 +93,7 @@ private:
const Problem& problem,
const Element& element,
const FVElementGeometry& fvGeometry,
const SubControlVolumeFace& scvf,
const LocalIndexType eqIdx)
const SubControlVolumeFace& scvf)
{
// Check whether or not we are touching the boundary here
bool onBoundary = problem.model().globalFvGeometry().scvfTouchesBoundary(scvf);
......@@ -107,7 +105,7 @@ private:
auto scvIdx0 = scvf.insideScvIdx();
// rotate counter clockwise and create the entities
performRotation_(problem, scvfVector, scvSeeds, scvfSeeds, scvIdx0, eqIdx);
performRotation_(problem, scvfVector, scvSeeds, scvfSeeds, scvIdx0);
if (onBoundary)
{
......@@ -115,7 +113,7 @@ private:
LocalIndexType storeIdx = scvfSeeds.size();
// clockwise rotation until hitting the boundary again
performRotation_(problem, scvfVector, scvSeeds, scvfSeeds, scvIdx0, eqIdx, /*clockwise*/true);
performRotation_(problem, scvfVector, scvSeeds, scvfSeeds, scvIdx0, /*clockwise*/true);
// Finish by creating the first scv
scvSeeds.emplace(scvSeeds.begin(), ScvSeed(GlobalIndexSet({scvfVector[0]->index(), scvfVector[1]->index()}),
......@@ -136,7 +134,6 @@ private:
std::vector<ScvSeed>& scvSeeds,
std::vector<ScvfSeed>& scvfSeeds,
const GlobalIndexType scvIdx0,
const LocalIndexType eqIdx,
const bool clockWise = false)
{
// extract the actual local indices from the containers
......@@ -162,7 +159,7 @@ private:
// the current element inside of the scv face
auto insideElement = problem.model().globalFvGeometry().element(insideGlobalScvIdx);
auto faceType = Implementation::getMpfaFaceType(problem, insideElement, curScvf, eqIdx);
auto faceType = Implementation::getMpfaFaceType(problem, insideElement, curScvf);
// if the face touches the boundary, create a boundary scvf entity
if (curScvf.boundary())
......@@ -287,8 +284,7 @@ public:
static InteractionVolumeSeed makeBoundaryInteractionVolumeSeed(const Problem& problem,
const Element& element,
const FVElementGeometry& fvGeometry,
const SubControlVolumeFace& scvf,
const LocalIndexType eqIdx)
const SubControlVolumeFace& scvf)
{
std::vector<ScvSeed> scvSeeds;
std::vector<ScvfSeed> scvfSeeds;
......@@ -301,7 +297,7 @@ public:
auto vIdxGlobal = scvf.vertexIndex();
// create the scv entity seeds
fillEntitySeeds_(scvSeeds, scvfSeeds, problem, element, fvGeometry, scvf, eqIdx, vIdxGlobal);
fillEntitySeeds_(scvSeeds, scvfSeeds, problem, element, fvGeometry, scvf, vIdxGlobal);
// shrink containers to necessary size
scvSeeds.shrink_to_fit();
......@@ -317,7 +313,6 @@ private:
const Element& element,
const FVElementGeometry& fvGeometry,
const SubControlVolumeFace& scvf,
const LocalIndexType eqIdx,
const GlobalIndexType vIdxGlobal)
{
// Get the three scv faces in the scv
......@@ -347,7 +342,7 @@ private:
actualScvSeed.setLocalScvfIndex(coordDir, scvfSeeds.size());
// create the scvf seed
auto faceType = Implementation::getMpfaFaceType(problem, element, *scvfVector[coordDir], eqIdx);
auto faceType = Implementation::getMpfaFaceType(problem, element, *scvfVector[coordDir]);
scvfSeeds.emplace_back( actualScvf,
LocalIndexSet({actualLocalScvIdx}),
GlobalIndexSet({scvfVector[coordDir]->index()}),
......@@ -388,13 +383,13 @@ private:
const auto& outsideScvf = *outsideScvfVector[commonFaceLocalIdx];
// create scvf seed
auto faceType = Implementation::getMpfaFaceType(problem, element, actualScvf, eqIdx);
auto faceType = Implementation::getMpfaFaceType(problem, element, actualScvf);
LocalIndexSet scvIndicesLocal({actualLocalScvIdx, static_cast<LocalIndexType>(scvSeeds.size())});
GlobalIndexSet scvfIndicesGlobal({globalScvfIndex, outsideScvf.index()});
scvfSeeds.emplace_back(actualScvf, std::move(scvIndicesLocal), std::move(scvfIndicesGlobal), faceType);
// make outside scv by recursion
fillEntitySeeds_(scvSeeds, scvfSeeds, problem, outsideElement, outsideFvGeometry, outsideScvf, eqIdx, vIdxGlobal);
fillEntitySeeds_(scvSeeds, scvfSeeds, problem, outsideElement, outsideFvGeometry, outsideScvf, vIdxGlobal);
}
// we have to find out if it is necessary to create a new scvf
else
......@@ -434,7 +429,7 @@ private:
const auto& outsideScvf = *outsideScvfVector[commonFaceLocalIdx];
// some data on the face
auto faceType = Implementation::getMpfaFaceType(problem, element, *scvfVector[coordDir], eqIdx);
auto faceType = Implementation::getMpfaFaceType(problem, element, *scvfVector[coordDir]);
LocalIndexSet scvIndicesLocal( {actualLocalScvIdx, outsideLocalScvIdx} );
GlobalIndexSet scvfIndicesGlobal( {globalScvfIndex, outsideScvf.index()} );
scvfSeeds.emplace_back(*scvfVector[coordDir], std::move(scvIndicesLocal), std::move(scvfIndicesGlobal), faceType);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment