Import opm-models

This commit is contained in:
Arne Morten Kvarving
2024-09-02 10:55:19 +02:00
368 changed files with 121393 additions and 0 deletions

286
examples/art2dgf.cpp Normal file
View File

@@ -0,0 +1,286 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <memory>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>
namespace Ewoms {
/*!
* \brief Reads in mesh files in the ART format.
*
* This file format is used to specify grids with fractures.
*/
struct Art2DGF
{
/*!
* \brief Create the Grid
*/
static void convert( const std::string& artFileName,
std::ostream& dgfFile,
const unsigned precision = 16 )
{
using Scalar = double;
using GlobalPosition = Dune::FieldVector< Scalar, 2 >;
enum ParseMode { Vertex, Edge, Element, Finished };
std::vector< std::pair<GlobalPosition, unsigned> > vertexPos;
std::vector<std::pair<unsigned, unsigned> > edges;
std::vector<std::pair<unsigned, unsigned> > fractureEdges;
std::vector<std::vector<unsigned> > elements;
std::ifstream inStream(artFileName);
if (!inStream.is_open()) {
throw std::runtime_error("File '"+artFileName
+"' does not exist or is not readable");
}
std::string curLine;
ParseMode curParseMode = Vertex;
while (inStream) {
std::getline(inStream, curLine);
// remove comments
auto commentPos = curLine.find("%");
if (commentPos != curLine.npos) {
curLine = curLine.substr(0, commentPos);
}
// remove leading whitespace
unsigned numLeadingSpaces = 0;
while (curLine.size() > numLeadingSpaces
&& std::isspace(curLine[numLeadingSpaces]))
++numLeadingSpaces;
curLine = curLine.substr(numLeadingSpaces,
curLine.size() - numLeadingSpaces);
// remove trailing whitespace
unsigned numTrailingSpaces = 0;
while (curLine.size() > numTrailingSpaces
&& std::isspace(curLine[curLine.size() - numTrailingSpaces]))
++numTrailingSpaces;
curLine = curLine.substr(0, curLine.size() - numTrailingSpaces);
// a section of the file is finished, go to the next one
if (curLine == "$") {
if (curParseMode == Vertex)
curParseMode = Edge;
else if (curParseMode == Edge)
curParseMode = Element;
else if (curParseMode == Element)
curParseMode = Finished;
continue;
}
// skip empty lines
if (curLine.empty())
continue;
if (curParseMode == Vertex) {
GlobalPosition coord;
std::istringstream iss(curLine);
// parse only the first two numbers as the vertex
// coordinate. the last number is the Z coordinate
// which we ignore (so far)
iss >> coord[0] >> coord[1];
vertexPos.push_back( std::make_pair( coord, 0 ) );
}
else if (curParseMode == Edge) {
// read an edge and update the fracture mapper
// read the data attached to the edge
std::istringstream iss(curLine);
int dataVal;
std::string tmp;
iss >> dataVal;
iss >> tmp;
assert(tmp == ":");
// read the vertex indices of an edge
std::vector<unsigned int> vertIndices;
while (iss) {
unsigned int tmp2;
iss >> tmp2;
if (!iss)
break;
vertIndices.push_back(tmp2);
assert(tmp2 < vertexPos.size());
}
// an edge always has two indices!
assert(vertIndices.size() == 2);
std::pair<unsigned, unsigned> edge(vertIndices[0], vertIndices[1]);
edges.push_back(edge);
// add the edge to the fracture mapper if it is a fracture
if (dataVal < 0) {
fractureEdges.push_back(edge);
vertexPos[ edge.first ].second = 1;
vertexPos[ edge.second ].second = 1;
}
}
else if (curParseMode == Element) {
// skip the data attached to an element
std::istringstream iss(curLine);
int dataVal;
std::string tmp;
iss >> dataVal;
iss >> tmp;
assert(tmp == ":");
// read the edge indices of an element
std::vector<unsigned> edgeIndices;
while (iss) {
unsigned tmp2;
iss >> tmp2;
if (!iss)
break;
edgeIndices.push_back(tmp2);
assert(tmp2 < edges.size());
}
// so far, we only support triangles
assert(edgeIndices.size() == 3);
// extract the vertex indices of the element
std::vector<unsigned> vertIndices;
for (unsigned i = 0; i < 3; ++i) {
bool haveFirstVertex = false;
for (unsigned j = 0; j < vertIndices.size(); ++j) {
assert(edgeIndices[i] < edges.size());
if (vertIndices[j] == edges[edgeIndices[i]].first) {
haveFirstVertex = true;
break;
}
}
if (!haveFirstVertex)
vertIndices.push_back(edges[edgeIndices[i]].first);
bool haveSecondVertex = false;
for (unsigned j = 0; j < vertIndices.size(); ++j) {
assert(edgeIndices[i] < edges.size());
if (vertIndices[j] == edges[edgeIndices[i]].second) {
haveSecondVertex = true;
break;
}
}
if (!haveSecondVertex)
vertIndices.push_back(edges[edgeIndices[i]].second);
}
// check whether the element's vertices are given in
// mathematically positive direction. if not, swap the
// first two.
Dune::FieldMatrix<Scalar, 2, 2> mat;
mat[0] = vertexPos[vertIndices[1]].first;
mat[0] -= vertexPos[vertIndices[0]].first;
mat[1] = vertexPos[vertIndices[2]].first;
mat[1] -= vertexPos[vertIndices[0]].first;
assert(std::abs(mat.determinant()) > 1e-50);
if (mat.determinant() < 0)
std::swap(vertIndices[2], vertIndices[1]);
elements.push_back( vertIndices );
}
else if (curParseMode == Finished) {
assert(curLine.size() == 0);
}
}
dgfFile << "DGF" << std::endl << std::endl;
dgfFile << "GridParameter" << std::endl
<< "overlap 1" << std::endl
<< "closure green" << std::endl
<< "#" << std::endl << std::endl;
dgfFile << "Vertex" << std::endl;
const bool hasFractures = fractureEdges.size() > 0;
if( hasFractures )
{
dgfFile << "parameters 1" << std::endl;
}
dgfFile << std::scientific;
dgfFile.precision( precision );
const size_t vxSize = vertexPos.size();
for( size_t i=0; i<vxSize; ++i)
{
dgfFile << vertexPos[ i ].first;
if( hasFractures )
{
dgfFile << " " << vertexPos[ i ].second;
}
dgfFile << std::endl;
}
dgfFile << "#" << std::endl << std::endl;
dgfFile << "Simplex" << std::endl;
const size_t elSize = elements.size();
for( size_t i=0; i<elSize; ++i )
{
const size_t elVx = elements[ i ].size();
for( size_t j=0; j<elVx; ++j )
dgfFile << elements[ i ][ j ] << " ";
dgfFile << std::endl;
}
dgfFile << "#" << std::endl << std::endl;
dgfFile << "BoundaryDomain" << std::endl;
dgfFile << "default 1" << std::endl;
dgfFile << "#" << std::endl << std::endl;
dgfFile << "#" << std::endl;
}
};
} // namespace Ewoms
int main( int argc, char** argv )
{
if (argc != 2) {
std::cout << "Converts a grid file from the ART file format to DGF (Dune grid format)\n"
<< "\n"
<< "Usage: " << argv[0] << " ART_FILENAME\n"
<< "\n"
<< "The result will be written to the file $ART_FILENAME.dgf\n";
return 1;
}
std::string filename( argv[ 1 ] );
std::string dgfname( filename );
dgfname += ".dgf";
std::cout << "Converting ART file \"" << filename << "\" to DGF file \"" << dgfname << "\"\n";
std::ofstream dgfFile( dgfname );
Ewoms::Art2DGF::convert( filename, dgfFile );
return 0;
}

View File

@@ -0,0 +1,62 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Box problem with two phases and multiple components.
* Solved with a PTFlash two phase solver.
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include "problems/co2ptflashproblem.hh"
namespace Opm::Properties {
namespace TTag {
struct CO2PTEcfvProblem {
using InheritsFrom = std::tuple<CO2PTBaseProblem, FlashModel>;
};
}
template <class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::CO2PTEcfvProblem>
{
using type = TTag::EcfvDiscretization;
};
template <class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::CO2PTEcfvProblem>
{
using type = TTag::AutoDiffLocalLinearizer;
};
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::CO2PTEcfvProblem;
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,85 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the isothermal compositional model based on flash
* calculations.
*/
#include "config.h"
#if HAVE_QUAD
#include <opm/material/common/quad.hpp>
#endif
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/flash/flashmodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/co2injectionflash.hh"
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionFlashEcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, FlashModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionFlashEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
// use automatic differentiation for this simulator
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::Co2InjectionFlashEcfvProblem>
{ using type = TTag::AutoDiffLocalLinearizer; };
// use the flash solver adapted to the CO2 injection problem
template<class TypeTag>
struct FlashSolver<TypeTag, TTag::Co2InjectionFlashEcfvProblem>
{ using type = Opm::Co2InjectionFlash<GetPropType<TypeTag, Properties::Scalar>,
GetPropType<TypeTag, Properties::FluidSystem>>; };
// the flash model has serious problems with the numerical
// precision. if quadruple precision math is available, we use it,
// else we increase the tolerance of the Newton solver
#if HAVE_QUAD
template<class TypeTag>
struct Scalar<TypeTag, TTag::Co2InjectionFlashEcfvProblem>
{ using type = quad; };
#endif
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionFlashEcfvProblem;
#if ! HAVE_QUAD
Opm::Co2InjectionTolerance = 1e-5;
#endif
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,87 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the non-isothermal compositional model based on flash
* calculations.
*/
#include "config.h"
// this must be included before the vanguard
#include <opm/material/common/quad.hpp>
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/flash/flashmodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/co2injectionflash.hh"
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionFlashNiEcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, FlashModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionFlashNiEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::Co2InjectionFlashNiEcfvProblem>
{ static constexpr bool value = true; };
//! Use automatic differentiation to linearize the system of PDEs
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::Co2InjectionFlashNiEcfvProblem>
{ using type = TTag::AutoDiffLocalLinearizer; };
// use the CO2 injection problem adapted flash solver
template<class TypeTag>
struct FlashSolver<TypeTag, TTag::Co2InjectionFlashNiEcfvProblem>
{ using type = Opm::Co2InjectionFlash<GetPropType<TypeTag, Properties::Scalar>,
GetPropType<TypeTag, Properties::FluidSystem>>; };
// the flash model has serious problems with the numerical
// precision. if quadruple precision math is available, we use it,
// else we increase the tolerance of the Newton solver
#if HAVE_QUAD
template<class TypeTag>
struct Scalar<TypeTag, TTag::Co2InjectionFlashNiEcfvProblem>
{ using type = quad; };
#endif
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionFlashNiEcfvProblem;
#if ! HAVE_QUAD
Opm::Co2InjectionTolerance = 1e-5;
#endif
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,83 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the non-isothermal compositional model based on flash
* calculations.
*/
#include "config.h"
// this must be included before the vanguard
#include <opm/material/common/quad.hpp>
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/flash/flashmodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include "problems/co2injectionflash.hh"
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionFlashNiVcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, FlashModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionFlashNiVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::Co2InjectionFlashNiVcfvProblem>
{ static constexpr bool value = true; };
// use the CO2 injection problem adapted flash solver
template<class TypeTag>
struct FlashSolver<TypeTag, TTag::Co2InjectionFlashNiVcfvProblem>
{ using type = Opm::Co2InjectionFlash<GetPropType<TypeTag, Properties::Scalar>,
GetPropType<TypeTag, Properties::FluidSystem>>; };
// the flash model has serious problems with the numerical
// precision. if quadruple precision math is available, we use it,
// else we increase the tolerance of the Newton solver
#if HAVE_QUAD
template<class TypeTag>
struct Scalar<TypeTag, TTag::Co2InjectionFlashNiVcfvProblem>
{ using type = quad; };
#endif
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using VcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionFlashNiVcfvProblem;
#if ! HAVE_QUAD
Opm::Co2InjectionTolerance = 1e-5;
#endif
return Opm::start<VcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,79 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the isothermal compositional model based on flash
* calculations.
*/
#include "config.h"
#if HAVE_QUAD
#include <opm/material/common/quad.hpp>
#endif
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/flash/flashmodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include "problems/co2injectionflash.hh"
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionFlashVcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, FlashModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionFlashVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
// use the flash solver adapted to the CO2 injection problem
template<class TypeTag>
struct FlashSolver<TypeTag, TTag::Co2InjectionFlashVcfvProblem>
{ using type = Opm::Co2InjectionFlash<GetPropType<TypeTag, Properties::Scalar>,
GetPropType<TypeTag, Properties::FluidSystem>>; };
// the flash model has serious problems with the numerical
// precision. if quadruple precision math is available, we use it,
// else we increase the tolerance of the Newton solver
#if HAVE_QUAD
template<class TypeTag>
struct Scalar<TypeTag, TTag::Co2InjectionFlashVcfvProblem>
{ using type = quad; };
#endif
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using VcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionFlashVcfvProblem;
#if ! HAVE_QUAD
Opm::Co2InjectionTolerance = 1e-5;
#endif
return Opm::start<VcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,60 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the isothermal immiscible model using the CO2 injection
* example problem
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
namespace TTag {
struct Co2InjectionImmiscibleEcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, ImmiscibleModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionImmiscibleEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
} // namespace Opm::Properties
////////////////////////
// the main function
////////////////////////
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionImmiscibleEcfvProblem;
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,68 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Simulation of the injection problem using the VCVF discretization
* assuming immisicibility and with energy enabled.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionImmiscibleNiEcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, ImmiscibleModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionImmiscibleNiEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::Co2InjectionImmiscibleNiEcfvProblem>
{ static constexpr bool value = true; };
//! Use automatic differentiation to linearize the system of PDEs
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::Co2InjectionImmiscibleNiEcfvProblem>
{ using type = TTag::AutoDiffLocalLinearizer; };
} // namespace Opm::Properties
////////////////////////
// the main function
////////////////////////
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionImmiscibleNiEcfvProblem;
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,63 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Simulation of the injection problem using the VCVF discretization
* assuming immisicibility and with energy enabled.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
namespace TTag {
struct Co2InjectionImmiscibleNiVcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, ImmiscibleModel>; };
} // namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionImmiscibleNiVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::Co2InjectionImmiscibleNiVcfvProblem>
{ static constexpr bool value = true; };
} // namespace Opm::Properties
////////////////////////
// the main function
////////////////////////
int main(int argc, char **argv)
{
using VcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionImmiscibleNiVcfvProblem;
return Opm::start<VcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,60 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the isothermal immiscible model using the CO2 injection
* example problem
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
namespace TTag {
struct Co2InjectionImmiscibleVcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, ImmiscibleModel>; };
} // namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionImmiscibleVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
} // namespace Opm::Properties
////////////////////////
// the main function
////////////////////////
int main(int argc, char **argv)
{
using VcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionImmiscibleVcfvProblem;
return Opm::start<VcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,57 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the isothermal VCVF discretization based on non-linear
* complementarity problems.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/ncp/ncpmodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionNcpEcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, NcpModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionNcpEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionNcpEcfvProblem;
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,66 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the non-isothermal VCVF discretization based on non-linear
* complementarity problems.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/ncp/ncpmodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionNcpNiEcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, NcpModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionNcpNiEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::Co2InjectionNcpNiEcfvProblem>
{ static constexpr bool value = true; };
//! Use automatic differentiation to linearize the system of PDEs
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::Co2InjectionNcpNiEcfvProblem>
{ using type = TTag::AutoDiffLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionNcpNiEcfvProblem;
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,60 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the non-isothermal VCVF discretization based on non-linear
* complementarity problems.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/ncp/ncpmodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionNcpNiVcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, NcpModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionNcpNiVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::Co2InjectionNcpNiVcfvProblem>
{ static constexpr bool value = true; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using VcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionNcpNiVcfvProblem;
return Opm::start<VcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,58 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the isothermal VCVF discretization based on non-linear
* complementarity problems.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/ncp/ncpmodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionNcpVcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, NcpModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionNcpVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using VcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionNcpVcfvProblem;
return Opm::start<VcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,57 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the isothermal primary variable switching model
* using the ECVF discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionPvsEcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, PvsModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionPvsEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionPvsEcfvProblem;
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,65 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the non-isothermal primary variable switching VCVF
* discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionPvsNiEcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, PvsModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionPvsNiEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::Co2InjectionPvsNiEcfvProblem>
{ static constexpr bool value = true; };
//! Use automatic differentiation to linearize the system of PDEs
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::Co2InjectionPvsNiEcfvProblem>
{ using type = TTag::AutoDiffLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using EcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionPvsNiEcfvProblem;
return Opm::start<EcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,61 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the non-isothermal primary variable switching model
* using the VCVF discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionPvsNiVcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, PvsModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionPvsNiVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::Co2InjectionPvsNiVcfvProblem>
{ static constexpr bool value = true; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using VcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionPvsNiVcfvProblem;
return Opm::start<VcfvProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,58 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the isothermal primary variable switching model using the VCVF
* discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include "problems/co2injectionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct Co2InjectionPvsVcfvProblem
{ using InheritsFrom = std::tuple<Co2InjectionBaseProblem, PvsModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Co2InjectionPvsVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using VcfvProblemTypeTag = Opm::Properties::TTag::Co2InjectionPvsVcfvProblem;
return Opm::start<VcfvProblemTypeTag>(argc, argv);
}

52
examples/cuvette_pvs.cpp Normal file
View File

@@ -0,0 +1,52 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief test for the 3p3cni VCVF discretization
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/cuvetteproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct CuvetteProblem
{ using InheritsFrom = std::tuple<CuvetteBaseProblem, PvsModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::CuvetteProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,48 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Forchheimer velocity model
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/flash/flashmodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/diffusionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct DiffusionProblem { using InheritsFrom = std::tuple<DiffusionBaseProblem, FlashModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::DiffusionProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,49 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Forchheimer velocity model
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/ncp/ncpmodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/diffusionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct DiffusionProblem { using InheritsFrom = std::tuple<DiffusionBaseProblem, NcpModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::DiffusionProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,48 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Forchheimer velocity model
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/diffusionproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct DiffusionProblem { using InheritsFrom = std::tuple<DiffusionBaseProblem, PvsModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::DiffusionProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,52 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Problem featuring a saturation overshoot.
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/fingerproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct FingerProblemEcfv { using InheritsFrom = std::tuple<FingerBaseProblem, ImmiscibleTwoPhaseModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::FingerProblemEcfv> { using type = TTag::EcfvDiscretization; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::FingerProblemEcfv;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,52 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Problem featuring a saturation overshoot.
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/fingerproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct FingerProblemVcfv { using InheritsFrom = std::tuple<FingerBaseProblem, ImmiscibleTwoPhaseModel>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::FingerProblemVcfv> { using type = TTag::VcfvDiscretization; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::FingerProblemVcfv;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,39 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Two-phase problem test with fractures.
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/fractureproblem.hh"
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::FractureProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,51 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the immisicible VCVF discretization with only a single phase
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include "problems/groundwaterproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct GroundWaterProblem
{ using InheritsFrom = std::tuple<GroundWaterBaseProblem, ImmiscibleSinglePhaseModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::GroundWaterProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,50 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief test for the primary variable switching VCVF discretization
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/infiltrationproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct InfiltrationProblem
{ using InheritsFrom = std::tuple<InfiltrationBaseProblem, PvsModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::InfiltrationProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,40 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Two-phase test for the immiscible model which uses the element-centered finite
* volume discretization in conjunction with automatic differentiation
*/
#include "config.h"
#include "lens_immiscible_ecfv_ad.hh"
#include <opm/models/utils/start.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::LensProblemEcfvAd;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,57 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Two-phase test for the immiscible model which uses the element-centered finite
* volume discretization in conjunction with automatic differentiation
*/
#ifndef EWOMS_LENS_IMMISCIBLE_ECFV_AD_HH
#define EWOMS_LENS_IMMISCIBLE_ECFV_AD_HH
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include "problems/lensproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct LensProblemEcfvAd { using InheritsFrom = std::tuple<LensBaseProblem, ImmiscibleTwoPhaseModel>; };
} // end namespace TTag
// use the element centered finite volume spatial discretization
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::LensProblemEcfvAd> { using type = TTag::EcfvDiscretization; };
// use automatic differentiation for this simulator
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::LensProblemEcfvAd> { using type = TTag::AutoDiffLocalLinearizer; };
// this problem works fine if the linear solver uses single precision scalars
template<class TypeTag>
struct LinearSolverScalar<TypeTag, TTag::LensProblemEcfvAd> { using type = float; };
} // namespace Opm::Properties
#endif // EWOMS_LENS_IMMISCIBLE_ECFV_AD_HH

View File

@@ -0,0 +1,93 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Two-phase test for the immiscible model which uses the element-centered finite
* volume discretization in conjunction with automatic differentiation
*/
#include "config.h"
#include "lens_immiscible_ecfv_ad.hh"
#include <dune/grid/geometrygrid.hh>
#include <dune/grid/io/file/dgfparser/dgfgeogrid.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
namespace Opm::Properties {
// Use Dune-grid's GeometryGrid< YaspGrid >
template<class TypeTag>
struct Grid <TypeTag, TTag::LensProblemEcfvAd>
{
template< class ctype, unsigned int dim, unsigned int dimworld >
class IdentityCoordFct
: public Dune::AnalyticalCoordFunction
< ctype, dim, dimworld, IdentityCoordFct< ctype, dim, dimworld > >
{
using This = IdentityCoordFct< ctype, dim, dimworld >;
using Base = Dune::AnalyticalCoordFunction< ctype, dim, dimworld, This >;
public:
using DomainVector = typename Base :: DomainVector;
using RangeVector = typename Base :: RangeVector ;
template< typename... Args >
IdentityCoordFct( Args&... )
{}
RangeVector operator()(const DomainVector& x) const
{
RangeVector y;
evaluate( x, y );
return y;
}
void evaluate( const DomainVector &x, RangeVector &y ) const
{
y = 0;
for( unsigned int i = 0; i<dim; ++i )
y[ i ] = x[ i ];
}
};
using MyYaspGrid = Dune::YaspGrid< 2 >;
public:
using type = Dune::GeometryGrid< MyYaspGrid,
IdentityCoordFct< typename MyYaspGrid::ctype,
MyYaspGrid::dimension,
MyYaspGrid::dimensionworld+1> >;
};
} // namespace Opm::Properties
#include <opm/models/utils/start.hh>
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::LensProblemEcfvAd;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,49 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief This test is identical to the simulation of the lens problem that uses the
* element centered finite volume discretization in conjunction with automatic
* differentiation (lens_immiscible_ecfv_ad).
*
* The only difference is that it uses multiple compile units in order to ensure that
* eWoms code can be used within libraries that use the same type tag within multiple
* compile units. This file represents the first compile unit and just defines an startup
* function for the simulator.
*/
#include "config.h"
#include "lens_immiscible_ecfv_ad.hh"
#include <opm/models/utils/start.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
// fake forward declaration to prevent esoteric compiler warning
int mainCU1(int argc, char **argv);
int mainCU1(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::LensProblemEcfvAd;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,49 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief This test is identical to the simulation of the lens problem that uses the
* element centered finite volume discretization in conjunction with automatic
* differentiation (lens_immiscible_ecfv_ad).
*
* The only difference is that it uses multiple compile units in order to ensure that
* eWoms code can be used within libraries that use the same type tag within multiple
* compile units. This file represents the second compile unit and just defines an
* startup function for the simulator.
*/
#include "config.h"
#include "lens_immiscible_ecfv_ad.hh"
#include <opm/models/utils/start.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
// fake forward declaration to prevent esoteric compiler warning
int mainCU2(int argc, char **argv);
int mainCU2(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::LensProblemEcfvAd;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,41 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief This test is identical to the simulation of the lens problem that uses the
* element centered finite volume discretization in conjunction with automatic
* differentiation (lens_immiscible_ecfv_ad).
*
* The only difference is that it uses multiple compile units in order to ensure that
* eWoms code can be used within libraries that use the same type tag within multiple
* compile units. This file calls contains main() and just calls the main entry point
* defined by the first compile unit.
*/
int mainCU1(int argc, char **argv);
int mainCU2(int argc, char **argv);
int main(int argc, char **argv)
{
return mainCU1(argc, argv);
}

View File

@@ -0,0 +1,66 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Two-phase test for the immiscible model which uses the element-centered finite
* volume discretization with two-point-flux using the transmissibility module
* in conjunction with automatic differentiation
*/
#include "config.h"
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/lensproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct LensProblemEcfvAdTrans { using InheritsFrom = std::tuple<LensBaseProblem, ImmiscibleTwoPhaseModel>; };
} // end namespace TTag
// use automatic differentiation for this simulator
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::LensProblemEcfvAdTrans> { using type = TTag::AutoDiffLocalLinearizer; };
// use the element centered finite volume spatial discretization
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::LensProblemEcfvAdTrans> { using type = TTag::EcfvDiscretization; };
// Set the problem property
template <class TypeTag>
struct FluxModule<TypeTag, TTag::LensProblemEcfvAdTrans> {
using type = TransFluxModule<TypeTag>;
};
}
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::LensProblemEcfvAdTrans;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,60 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Two-phase test for the immiscible model which uses the
* vertex-centered finite volume discretization
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/lensproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct LensProblemVcfvAd { using InheritsFrom = std::tuple<LensBaseProblem, ImmiscibleTwoPhaseModel>; };
} // end namespace TTag
// use automatic differentiation for this simulator
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::LensProblemVcfvAd> { using type = TTag::AutoDiffLocalLinearizer; };
// use linear finite element gradients if dune-localfunctions is available
#if HAVE_DUNE_LOCALFUNCTIONS
template<class TypeTag>
struct UseP1FiniteElementGradients<TypeTag, TTag::LensProblemVcfvAd> { static constexpr bool value = true; };
#endif
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::LensProblemVcfvAd;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,60 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Two-phase test for the immiscible model which uses the
* vertex-centered finite volume discretization
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/lensproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct LensProblemVcfvFd { using InheritsFrom = std::tuple<LensBaseProblem, ImmiscibleTwoPhaseModel>; };
} // end namespace TTag
// use the finite difference methodfor this simulator
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::LensProblemVcfvFd> { using type = TTag::FiniteDifferenceLocalLinearizer; };
// use linear finite element gradients if dune-localfunctions is available
#if HAVE_DUNE_LOCALFUNCTIONS
template<class TypeTag>
struct UseP1FiniteElementGradients<TypeTag, TTag::LensProblemVcfvFd> { static constexpr bool value = true; };
#endif
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::LensProblemVcfvFd;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,61 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Richards model using the ECFV discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/richardslensproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct RichardsLensEcfvProblem
{ using InheritsFrom = std::tuple<RichardsLensProblem>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::RichardsLensEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
//! Use automatic differentiation to linearize the system of PDEs
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::RichardsLensEcfvProblem>
{ using type = TTag::AutoDiffLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::RichardsLensEcfvProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,57 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Richards model using the VCFV discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/richardslensproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct RichardsLensVcfvProblem
{ using InheritsFrom = std::tuple<RichardsLensProblem>; };
} // end namespace TTag
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::RichardsLensVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::RichardsLensVcfvProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,52 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*
* \file
*
* \brief Test for the immiscible multi-phase VCVF discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include "problems/obstacleproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct ObstacleProblem
{ using InheritsFrom = std::tuple<ObstacleBaseProblem, ImmiscibleModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::ObstacleProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

53
examples/obstacle_ncp.cpp Normal file
View File

@@ -0,0 +1,53 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the compositional NCP VCVF discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/ncp/ncpmodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/obstacleproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct ObstacleProblem
{ using InheritsFrom = std::tuple<ObstacleBaseProblem, NcpModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::ObstacleProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

55
examples/obstacle_pvs.cpp Normal file
View File

@@ -0,0 +1,55 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*
* \file
*
* \brief Test for the isothermal primary variable switching model
* using "obstacle" problem and the VCVF discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/obstacleproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct ObstacleProblem
{ using InheritsFrom = std::tuple<ObstacleBaseProblem, PvsModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::ObstacleProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

53
examples/outflow_pvs.cpp Normal file
View File

@@ -0,0 +1,53 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief test for the compositional PVS VCVF discretization
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/outflowproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct OutflowProblem
{ using InheritsFrom = std::tuple<OutflowBaseProblem, PvsModel>; };
} // end namespace TTag
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::OutflowProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,55 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Forchheimer velocity model
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include "problems/powerinjectionproblem.hh"
namespace Opm::Properties {
namespace TTag {
struct PowerInjectionDarcyAdProblem
{ using InheritsFrom = std::tuple<PowerInjectionBaseProblem, ImmiscibleTwoPhaseModel>; };
} // namespace TTag
template<class TypeTag>
struct FluxModule<TypeTag, TTag::PowerInjectionDarcyAdProblem> { using type = Opm::DarcyFluxModule<TypeTag>; };
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::PowerInjectionDarcyAdProblem> { using type = TTag::AutoDiffLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::PowerInjectionDarcyAdProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,55 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Forchheimer velocity model
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/powerinjectionproblem.hh"
namespace Opm::Properties {
namespace TTag {
struct PowerInjectionDarcyFdProblem
{ using InheritsFrom = std::tuple<PowerInjectionBaseProblem, ImmiscibleTwoPhaseModel>; };
} // namespace TTag
template<class TypeTag>
struct FluxModule<TypeTag, TTag::PowerInjectionDarcyFdProblem> { using type = Opm::DarcyFluxModule<TypeTag>; };
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::PowerInjectionDarcyFdProblem> { using type = TTag::FiniteDifferenceLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::PowerInjectionDarcyFdProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,55 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Forchheimer velocity model
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include "problems/powerinjectionproblem.hh"
namespace Opm::Properties {
namespace TTag {
struct PowerInjectionForchheimerAdProblem
{ using InheritsFrom = std::tuple<PowerInjectionBaseProblem, ImmiscibleTwoPhaseModel>; };
} // namespace TTag
template<class TypeTag>
struct FluxModule<TypeTag, TTag::PowerInjectionForchheimerAdProblem> { using type = Opm::ForchheimerFluxModule<TypeTag>; };
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::PowerInjectionForchheimerAdProblem> { using type = TTag::AutoDiffLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::PowerInjectionForchheimerAdProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,55 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the Forchheimer velocity model
*/
#include "config.h"
#include <opm/models/utils/start.hh>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/powerinjectionproblem.hh"
namespace Opm::Properties {
namespace TTag {
struct PowerInjectionForchheimerFdProblem
{ using InheritsFrom = std::tuple<PowerInjectionBaseProblem, ImmiscibleTwoPhaseModel>; };
} // namespace TTag
template<class TypeTag>
struct FluxModule<TypeTag, TTag::PowerInjectionForchheimerFdProblem> { using type = Opm::ForchheimerFluxModule<TypeTag>; };
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::PowerInjectionForchheimerFdProblem> { using type = TTag::FiniteDifferenceLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::PowerInjectionForchheimerFdProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,66 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::Co2InjectionFlash
*/
#ifndef EWOMS_CO2_INJECTION_FLASH_HH
#define EWOMS_CO2_INJECTION_FLASH_HH
#include <opm/material/constraintsolvers/NcpFlash.hpp>
namespace Opm {
/*!
* \brief Flash solver used by the CO2 injection problem.
*
* This class is just the NCP flash solver with the guessInitial()
* method that is adapted to the pressure regime of the CO2 injection
* problem.
*/
template <class Scalar, class FluidSystem>
class Co2InjectionFlash : public Opm::NcpFlash<Scalar, FluidSystem>
{
using ParentType = Opm::NcpFlash<Scalar, FluidSystem>;
enum { numPhases = FluidSystem::numPhases };
public:
/*!
* \brief Guess initial values for all quantities.
*/
template <class FluidState, class ComponentVector>
static void guessInitial(FluidState& fluidState, const ComponentVector& globalMolarities)
{
ParentType::guessInitial(fluidState, globalMolarities);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
// pressure. use something close to the reservoir pressure as initial guess
fluidState.setPressure(phaseIdx, 100e5);
}
}
};
} // namespace Opm
#endif // EWOMS_CO2_INJECTION_FLASH_HH

View File

@@ -0,0 +1,648 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::Co2InjectionProblem
*/
#ifndef EWOMS_CO2_INJECTION_PROBLEM_HH
#define EWOMS_CO2_INJECTION_PROBLEM_HH
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/simulators/linalg/parallelamgbackend.hh>
#include <opm/material/fluidsystems/H2ON2FluidSystem.hpp>
#include <opm/material/fluidsystems/BrineCO2FluidSystem.hpp>
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
#include <opm/material/constraintsolvers/ComputeFromReferencePhase.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/RegularizedBrooksCorey.hpp>
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/thermal/SomertonThermalConductionLaw.hpp>
#include <opm/material/thermal/ConstantSolidHeatCapLaw.hpp>
#include <opm/material/binarycoefficients/Brine_CO2.hpp>
#include <opm/material/common/UniformTabulated2DFunction.hpp>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <sstream>
#include <iostream>
#include <string>
namespace Opm {
//! \cond SKIP_THIS
template <class TypeTag>
class Co2InjectionProblem;
//! \endcond
}
namespace Opm::Properties {
namespace TTag {
struct Co2InjectionBaseProblem {};
}
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::Co2InjectionBaseProblem> { using type = Dune::YaspGrid<2>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::Co2InjectionBaseProblem>
{ using type = Opm::Co2InjectionProblem<TypeTag>; };
// Set fluid configuration
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::Co2InjectionBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::BrineCO2FluidSystem<Scalar>;
//using type = Opm::H2ON2FluidSystem<Scalar, /*useComplexRelations=*/false>;
};
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::Co2InjectionBaseProblem>
{
private:
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { liquidPhaseIdx = FluidSystem::liquidPhaseIdx };
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::liquidPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::gasPhaseIdx>;
// define the material law which is parameterized by effective
// saturations
using EffMaterialLaw = Opm::RegularizedBrooksCorey<Traits>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::EffToAbsLaw<EffMaterialLaw>;
};
// Set the thermal conduction law
template<class TypeTag>
struct ThermalConductionLaw<TypeTag, TTag::Co2InjectionBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::SomertonThermalConductionLaw<FluidSystem, Scalar>;
};
// set the energy storage law for the solid phase
template<class TypeTag>
struct SolidEnergyLaw<TypeTag, TTag::Co2InjectionBaseProblem>
{ using type = Opm::ConstantSolidHeatCapLaw<GetPropType<TypeTag, Properties::Scalar>>; };
// Use the algebraic multi-grid linear solver for this problem
template<class TypeTag>
struct LinearSolverSplice<TypeTag, TTag::Co2InjectionBaseProblem> { using type = TTag::ParallelAmgLinearSolver; };
} // namespace Opm::Properties
namespace Opm::Parameters {
struct FluidSystemNumPressure { static constexpr unsigned value = 100; };
struct FluidSystemNumTemperature { static constexpr unsigned value = 100; };
template<class Scalar>
struct FluidSystemPressureHigh { static constexpr Scalar value = 4e7; };
template<class Scalar>
struct FluidSystemPressureLow { static constexpr Scalar value = 3e7; };
template<class Scalar>
struct FluidSystemTemperatureHigh { static constexpr Scalar value = 500.0; };
template<class Scalar>
struct FluidSystemTemperatureLow { static constexpr Scalar value = 290.0; };
template<class Scalar>
struct MaxDepth { static constexpr Scalar value = 2500.0; };
struct SimulationName { static constexpr auto value = "co2injection"; };
template<class Scalar>
struct Temperature { static constexpr Scalar value = 293.15; };
} // namespace Opm::Parameters
namespace Opm {
double Co2InjectionTolerance = 1e-8;
/*!
* \ingroup TestProblems
*
* \brief Problem where \f$CO_2\f$ is injected under a low permeable
* layer at a depth of 2700m.
*
* The domain is sized 60m times 40m and consists of two layers, one
* which is moderately permeable (\f$K = 10^{-12}\;m^2\f$) for \f$ y >
* 22\; m\f$ and one with a lower intrinsic permeablility (\f$
* K=10^{-13}\;m^2\f$) in the rest of the domain.
*
* \f$CO_2\f$ gets injected by means of a forced-flow boundary
* condition into water-filled aquifer, which is situated 2700m below
* sea level, at the lower-right boundary (\f$5m<y<15m\f$) and
* migrates upwards due to buoyancy. It accumulates and eventually
* enters the lower permeable aquitard.
*
* The boundary conditions applied by this problem are no-flow
* conditions on the top bottom and right boundaries and a free-flow
* boundary condition on the left. For the free-flow condition,
* hydrostatic pressure is assumed.
*/
template <class TypeTag>
class Co2InjectionProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Evaluation = GetPropType<TypeTag, Properties::Evaluation>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { dim = GridView::dimension };
enum { dimWorld = GridView::dimensionworld };
// copy some indices for convenience
using Indices = GetPropType<TypeTag, Properties::Indices>;
enum { numPhases = FluidSystem::numPhases };
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
enum { liquidPhaseIdx = FluidSystem::liquidPhaseIdx };
enum { CO2Idx = FluidSystem::CO2Idx };
enum { BrineIdx = FluidSystem::BrineIdx };
enum { conti0EqIdx = Indices::conti0EqIdx };
enum { contiCO2EqIdx = conti0EqIdx + CO2Idx };
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Model = GetPropType<TypeTag, Properties::Model>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using ThermalConductionLaw = GetPropType<TypeTag, Properties::ThermalConductionLaw>;
using SolidEnergyLawParams = GetPropType<TypeTag, Properties::SolidEnergyLawParams>;
using ThermalConductionLawParams = typename ThermalConductionLaw::Params;
using Toolbox = Opm::MathToolbox<Evaluation>;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
Co2InjectionProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
eps_ = 1e-6;
temperatureLow_ = Parameters::Get<Parameters::FluidSystemTemperatureLow<Scalar>>();
temperatureHigh_ = Parameters::Get<Parameters::FluidSystemTemperatureHigh<Scalar>>();
nTemperature_ = Parameters::Get<Parameters::FluidSystemNumTemperature>();
pressureLow_ = Parameters::Get<Parameters::FluidSystemPressureLow<Scalar>>();
pressureHigh_ = Parameters::Get<Parameters::FluidSystemPressureHigh<Scalar>>();
nPressure_ = Parameters::Get<Parameters::FluidSystemNumPressure>();
maxDepth_ = Parameters::Get<Parameters::MaxDepth<Scalar>>();
temperature_ = Parameters::Get<Parameters::Temperature<Scalar>>();
// initialize the tables of the fluid system
// FluidSystem::init();
FluidSystem::init(/*Tmin=*/temperatureLow_,
/*Tmax=*/temperatureHigh_,
/*nT=*/nTemperature_,
/*pmin=*/pressureLow_,
/*pmax=*/pressureHigh_,
/*np=*/nPressure_);
fineLayerBottom_ = 22.0;
// intrinsic permeabilities
fineK_ = this->toDimMatrix_(1e-13);
coarseK_ = this->toDimMatrix_(1e-12);
// porosities
finePorosity_ = 0.3;
coarsePorosity_ = 0.3;
// residual saturations
fineMaterialParams_.setResidualSaturation(liquidPhaseIdx, 0.2);
fineMaterialParams_.setResidualSaturation(gasPhaseIdx, 0.0);
coarseMaterialParams_.setResidualSaturation(liquidPhaseIdx, 0.2);
coarseMaterialParams_.setResidualSaturation(gasPhaseIdx, 0.0);
// parameters for the Brooks-Corey law
fineMaterialParams_.setEntryPressure(1e4);
coarseMaterialParams_.setEntryPressure(5e3);
fineMaterialParams_.setLambda(2.0);
coarseMaterialParams_.setLambda(2.0);
fineMaterialParams_.finalize();
coarseMaterialParams_.finalize();
// parameters for the somerton law thermal conduction
computeThermalCondParams_(fineThermalCondParams_, finePorosity_);
computeThermalCondParams_(coarseThermalCondParams_, coarsePorosity_);
// assume constant heat capacity and granite
solidEnergyLawParams_.setSolidHeatCapacity(790.0 // specific heat capacity of granite [J / (kg K)]
* 2700.0); // density of granite [kg/m^3]
solidEnergyLawParams_.finalize();
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::Register<Parameters::FluidSystemTemperatureLow<Scalar>>
("The lower temperature [K] for tabulation of the fluid system");
Parameters::Register<Parameters::FluidSystemTemperatureHigh<Scalar>>
("The upper temperature [K] for tabulation of the fluid system");
Parameters::Register<Parameters::FluidSystemNumTemperature>
("The number of intervals between the lower and upper temperature");
Parameters::Register<Parameters::FluidSystemPressureLow<Scalar>>
("The lower pressure [Pa] for tabulation of the fluid system");
Parameters::Register<Parameters::FluidSystemPressureHigh<Scalar>>
("The upper pressure [Pa] for tabulation of the fluid system");
Parameters::Register<Parameters::FluidSystemNumPressure>
("The number of intervals between the lower and upper pressure");
Parameters::Register<Parameters::Temperature<Scalar>>
("The temperature [K] in the reservoir");
Parameters::Register<Parameters::MaxDepth<Scalar>>
("The maximum depth [m] of the reservoir");
Parameters::Register<Parameters::SimulationName>
("The name of the simulation used for the output files");
Parameters::SetDefault<Parameters::GridFile>("data/co2injection.dgf");
Parameters::SetDefault<Parameters::EndTime<Scalar>>(1e4);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(250);
Parameters::SetDefault<Parameters::NewtonTolerance<Scalar>>(Scalar{Co2InjectionTolerance});
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \name Problem parameters
*/
//! \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << Parameters::Get<Parameters::SimulationName>()
<< "_" << Model::name();
if (getPropValue<TypeTag, Properties::EnableEnergy>())
oss << "_ni";
oss << "_" << Model::discretizationName();
return oss.str();
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
Scalar tol = this->model().newtonMethod().tolerance()*1e5;
this->model().checkConservativeness(tol);
// Calculate storage terms
PrimaryVariables storageL, storageG;
this->model().globalPhaseStorage(storageL, /*phaseIdx=*/0);
this->model().globalPhaseStorage(storageG, /*phaseIdx=*/1);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: liquid=[" << storageL << "]"
<< " gas=[" << storageG << "]\n" << std::flush;
}
#endif // NDEBUG
}
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
const auto& pos = context.pos(spaceIdx, timeIdx);
if (inHighTemperatureRegion_(pos))
return temperature_ + 100;
return temperature_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& context, unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineK_;
return coarseK_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return finePorosity_;
return coarsePorosity_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams(const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineMaterialParams_;
return coarseMaterialParams_;
}
/*!
* \brief Return the parameters for the heat storage law of the rock
*
* In this case, we assume the rock-matrix to be granite.
*/
template <class Context>
const SolidEnergyLawParams&
solidEnergyLawParams(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return solidEnergyLawParams_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::thermalConductionParams
*/
template <class Context>
const ThermalConductionLawParams &
thermalConductionLawParams(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineThermalCondParams_;
return coarseThermalCondParams_;
}
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const auto& pos = context.pos(spaceIdx, timeIdx);
if (onLeftBoundary_(pos)) {
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
fs.checkDefined();
// impose an freeflow boundary condition
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
}
else if (onInlet_(pos)) {
RateVector massRate(0.0);
massRate[contiCO2EqIdx] = -1e-3; // [kg/(m^3 s)]
using FluidState = Opm::ImmiscibleFluidState<Scalar, FluidSystem>;
FluidState fs;
fs.setSaturation(gasPhaseIdx, 1.0);
const auto& pg =
context.intensiveQuantities(spaceIdx, timeIdx).fluidState().pressure(gasPhaseIdx);
fs.setPressure(gasPhaseIdx, Toolbox::value(pg));
fs.setTemperature(temperature(context, spaceIdx, timeIdx));
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updatePhase(fs, gasPhaseIdx);
Scalar h = FluidSystem::template enthalpy<FluidState, Scalar>(fs, paramCache, gasPhaseIdx);
// impose an forced inflow boundary condition for pure CO2
values.setMassRate(massRate);
values.setEnthalpyRate(massRate[contiCO2EqIdx] * h);
}
else
// no flow on top and bottom
values.setNoFlow();
}
// \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx,
unsigned timeIdx) const
{
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
// const auto& matParams = this->materialLawParams(context, spaceIdx,
// timeIdx);
// values.assignMassConservative(fs, matParams, /*inEquilibrium=*/true);
values.assignNaive(fs);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
template <class Context, class FluidState>
void initialFluidState_(FluidState& fs,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
//////
// set temperature
//////
fs.setTemperature(temperature(context, spaceIdx, timeIdx));
//////
// set saturations
//////
fs.setSaturation(FluidSystem::liquidPhaseIdx, 1.0);
fs.setSaturation(FluidSystem::gasPhaseIdx, 0.0);
//////
// set pressures
//////
Scalar densityL = FluidSystem::Brine::liquidDensity(temperature_, Scalar(1e5));
Scalar depth = maxDepth_ - pos[dim - 1];
Scalar pl = 1e5 - densityL * this->gravity()[dim - 1] * depth;
Scalar pC[numPhases];
const auto& matParams = this->materialLawParams(context, spaceIdx, timeIdx);
MaterialLaw::capillaryPressures(pC, matParams, fs);
fs.setPressure(liquidPhaseIdx, pl + (pC[liquidPhaseIdx] - pC[liquidPhaseIdx]));
fs.setPressure(gasPhaseIdx, pl + (pC[gasPhaseIdx] - pC[liquidPhaseIdx]));
//////
// set composition of the liquid phase
//////
fs.setMoleFraction(liquidPhaseIdx, CO2Idx, 0.005);
fs.setMoleFraction(liquidPhaseIdx, BrineIdx,
1.0 - fs.moleFraction(liquidPhaseIdx, CO2Idx));
typename FluidSystem::template ParameterCache<Scalar> paramCache;
using CFRP = Opm::ComputeFromReferencePhase<Scalar, FluidSystem>;
CFRP::solve(fs, paramCache,
/*refPhaseIdx=*/liquidPhaseIdx,
/*setViscosity=*/true,
/*setEnthalpy=*/true);
}
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
bool onInlet_(const GlobalPosition& pos) const
{ return onRightBoundary_(pos) && (5 < pos[1]) && (pos[1] < 15); }
bool inHighTemperatureRegion_(const GlobalPosition& pos) const
{ return (pos[0] > 20) && (pos[0] < 30) && (pos[1] > 5) && (pos[1] < 35); }
void computeThermalCondParams_(ThermalConductionLawParams& params, Scalar poro)
{
Scalar lambdaWater = 0.6;
Scalar lambdaGranite = 2.8;
Scalar lambdaWet = std::pow(lambdaGranite, (1 - poro))
* std::pow(lambdaWater, poro);
Scalar lambdaDry = std::pow(lambdaGranite, (1 - poro));
params.setFullySaturatedLambda(gasPhaseIdx, lambdaDry);
params.setFullySaturatedLambda(liquidPhaseIdx, lambdaWet);
params.setVacuumLambda(lambdaDry);
}
bool isFineMaterial_(const GlobalPosition& pos) const
{ return pos[dim - 1] > fineLayerBottom_; }
DimMatrix fineK_;
DimMatrix coarseK_;
Scalar fineLayerBottom_;
Scalar finePorosity_;
Scalar coarsePorosity_;
MaterialLawParams fineMaterialParams_;
MaterialLawParams coarseMaterialParams_;
ThermalConductionLawParams fineThermalCondParams_;
ThermalConductionLawParams coarseThermalCondParams_;
SolidEnergyLawParams solidEnergyLawParams_;
Scalar temperature_;
Scalar maxDepth_;
Scalar eps_;
unsigned nTemperature_;
unsigned nPressure_;
Scalar pressureLow_, pressureHigh_;
Scalar temperatureLow_, temperatureHigh_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,520 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::co2ptflashproblem
*/
#ifndef OPM_CO2PTFLASH_PROBLEM_HH
#define OPM_CO2PTFLASH_PROBLEM_HH
#include <opm/common/Exceptions.hpp>
#include <opm/material/components/SimpleCO2.hpp>
#include <opm/material/components/C10.hpp>
#include <opm/material/components/C1.hpp>
#include <opm/material/fluidmatrixinteractions/RegularizedBrooksCorey.hpp>
#include <opm/material/fluidmatrixinteractions/BrooksCorey.hpp>
#include <opm/material/constraintsolvers/PTFlash.hpp>
#include <opm/material/fluidsystems/GenericOilGasFluidSystem.hpp>
#include <opm/material/common/Valgrind.hpp>
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include <opm/models/ptflash/flashmodel.hh>
#include <opm/models/io/structuredgridvanguard.hh>
#include <opm/models/utils/propertysystem.hh>
#include <opm/models/utils/start.hh>
#include <opm/simulators/linalg/parallelistlbackend.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <sstream>
#include <string>
namespace Opm {
template <class TypeTag>
class CO2PTProblem;
} // namespace Opm */
namespace Opm::Properties {
namespace TTag {
struct CO2PTBaseProblem {};
} // end namespace TTag
template <class TypeTag, class MyTypeTag>
struct NumComp { using type = UndefinedProperty; };
template <class TypeTag>
struct NumComp<TypeTag, TTag::CO2PTBaseProblem> {
static constexpr int value = 3;
};
// Set the grid type: --->2D
template <class TypeTag>
struct Grid<TypeTag, TTag::CO2PTBaseProblem> { using type = Dune::YaspGrid</*dim=*/2>; };
// Set the problem property
template <class TypeTag>
struct Problem<TypeTag, TTag::CO2PTBaseProblem>
{ using type = Opm::CO2PTProblem<TypeTag>; };
// Set flash solver
template <class TypeTag>
struct FlashSolver<TypeTag, TTag::CO2PTBaseProblem> {
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Evaluation = GetPropType<TypeTag, Properties::Evaluation>;
public:
using type = Opm::PTFlash<Scalar, FluidSystem>;
};
// Set fluid configuration
template <class TypeTag>
struct FluidSystem<TypeTag, TTag::CO2PTBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
static constexpr int num_comp = getPropValue<TypeTag, Properties::NumComp>();
public:
using type = Opm::GenericOilGasFluidSystem<Scalar, num_comp>;
};
// Set the material Law
template <class TypeTag>
struct MaterialLaw<TypeTag, TTag::CO2PTBaseProblem> {
private:
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
// /*wettingPhaseIdx=*/FluidSystem::waterPhaseIdx, // TODO
/*nonWettingPhaseIdx=*/FluidSystem::oilPhaseIdx,
/*gasPhaseIdx=*/FluidSystem::gasPhaseIdx>;
// define the material law which is parameterized by effective saturation
using EffMaterialLaw = Opm::NullMaterial<Traits>;
//using EffMaterialLaw = Opm::BrooksCorey<Traits>;
public:
using type = EffMaterialLaw;
};
// mesh grid
template <class TypeTag>
struct Vanguard<TypeTag, TTag::CO2PTBaseProblem> {
using type = Opm::StructuredGridVanguard<TypeTag>;
};
template <class TypeTag>
struct EnableEnergy<TypeTag, TTag::CO2PTBaseProblem> {
static constexpr bool value = false;
};
} // namespace Opm::Properties
namespace Opm::Parameters {
// this is kinds of telling the report step length
template<class Scalar>
struct EpisodeLength { static constexpr Scalar value = 0.1 * 60. * 60.; };
template<class Scalar>
struct Initialpressure { static constexpr Scalar value = 75e5; };
struct SimulationName { static constexpr auto value = "co2_ptflash"; };
// set the defaults for the problem specific properties
template<class Scalar>
struct Temperature { static constexpr Scalar value = 423.25; };
} // namespace Opm::Parameters
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief 3 component simple testproblem with ["CO2", "C1", "C10"]
*
*/
template <class TypeTag>
class CO2PTProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Evaluation = GetPropType<TypeTag, Properties::Evaluation>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { dim = GridView::dimension };
enum { dimWorld = GridView::dimensionworld };
using Indices = GetPropType<TypeTag, Properties::Indices>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Model = GetPropType<TypeTag, Properties::Model>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using Toolbox = Opm::MathToolbox<Evaluation>;
using CoordScalar = typename GridView::ctype;
enum { numPhases = FluidSystem::numPhases };
enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
enum { conti0EqIdx = Indices::conti0EqIdx };
enum { numComponents = getPropValue<TypeTag, Properties::NumComponents>() };
enum { enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>() };
enum { enableDiffusion = getPropValue<TypeTag, Properties::EnableDiffusion>() };
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
using DimVector = Dune::FieldVector<Scalar, dimWorld>;
using ComponentVector = Dune::FieldVector<Evaluation, numComponents>;
using FlashSolver = GetPropType<TypeTag, Properties::FlashSolver>;
public:
using FluidState = Opm::CompositionalFluidState<Evaluation, FluidSystem, enableEnergy>;
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
explicit CO2PTProblem(Simulator& simulator)
: ParentType(simulator)
{
const Scalar epi_len = Parameters::Get<Parameters::EpisodeLength<Scalar>>();
simulator.setEpisodeLength(epi_len);
FluidSystem::init();
using CompParm = typename FluidSystem::ComponentParam;
using CO2 = Opm::SimpleCO2<Scalar>;
using C1 = Opm::C1<Scalar>;
using C10 = Opm::C10<Scalar>;
FluidSystem::addComponent(CompParm {CO2::name(), CO2::molarMass(), CO2::criticalTemperature(),
CO2::criticalPressure(), CO2::criticalVolume(), CO2::acentricFactor()});
FluidSystem::addComponent(CompParm {C1::name(), C1::molarMass(), C1::criticalTemperature(),
C1::criticalPressure(), C1::criticalVolume(), C1::acentricFactor()});
FluidSystem::addComponent(CompParm{C10::name(), C10::molarMass(), C10::criticalTemperature(),
C10::criticalPressure(), C10::criticalVolume(), C10::acentricFactor()});
// FluidSystem::add
}
void initPetrophysics()
{
temperature_ = Parameters::Get<Parameters::Temperature<Scalar>>();
K_ = this->toDimMatrix_(9.869232667160131e-14);
porosity_ = 0.1;
}
template <class Context>
const DimVector&
gravity([[maybe_unused]]const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{
return gravity();
}
const DimVector& gravity() const
{
return gravity_;
}
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
// initialize fixed parameters; temperature, permeability, porosity
initPetrophysics();
}
/*!
* \copydoc co2ptflashproblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::Register<Parameters::Temperature<Scalar>>
("The temperature [K] in the reservoir");
Parameters::Register<Parameters::Initialpressure<Scalar>>
("The initial pressure [Pa s] in the reservoir");
Parameters::Register<Parameters::SimulationName>
("The name of the simulation used for the output files");
Parameters::Register<Parameters::EpisodeLength<Scalar>>
("Time interval [s] for episode length");
Parameters::SetDefault<Parameters::CellsX>(30);
Parameters::SetDefault<Parameters::DomainSizeX<Scalar>>(300.0);
if constexpr (dim > 1) {
Parameters::SetDefault<Parameters::CellsY>(1);
Parameters::SetDefault<Parameters::DomainSizeY<Scalar>>(1.0);
}
if constexpr (dim == 3) {
Parameters::SetDefault<Parameters::CellsZ>(1);
Parameters::SetDefault<Parameters::DomainSizeZ<Scalar>>(1.0);
}
Parameters::SetDefault<Parameters::EndTime<Scalar>>(60. * 60.);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(0.1 * 60. * 60.);
Parameters::SetDefault<Parameters::NewtonMaxIterations>(30);
Parameters::SetDefault<Parameters::NewtonTargetIterations>(6);
Parameters::SetDefault<Parameters::NewtonTolerance<Scalar>>(1e-3);
Parameters::SetDefault<Parameters::VtkWriteFilterVelocities>(true);
Parameters::SetDefault<Parameters::VtkWriteFugacityCoeffs>(true);
Parameters::SetDefault<Parameters::VtkWritePotentialGradients>(true);
Parameters::SetDefault<Parameters::VtkWriteTotalMassFractions>(true);
Parameters::SetDefault<Parameters::VtkWriteTotalMoleFractions>(true);
Parameters::SetDefault<Parameters::VtkWriteEquilibriumConstants>(true);
Parameters::SetDefault<Parameters::VtkWriteLiquidMoleFractions>(true);
Parameters::SetDefault<Parameters::LinearSolverAbsTolerance<Scalar>>(0.0);
Parameters::SetDefault<Parameters::LinearSolverTolerance<Scalar>>(1e-3);
}
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << Parameters::Get<Parameters::SimulationName>();
return oss.str();
}
// This method must be overridden for the simulator to continue with
// a new episode. We just start a new episode with the same length as
// the old one.
void endEpisode()
{
Scalar epi_len = Parameters::Get<Parameters::EpisodeLength<Scalar>>();
this->simulator().startNextEpisode(epi_len);
}
// only write output when episodes change, aka. report steps, and
// include the initial timestep too
bool shouldWriteOutput()
{
return this->simulator().episodeWillBeOver() || (this->simulator().timeStepIndex() == -1);
}
// we don't care about doing restarts from every fifth timestep, it
// will just slow us down
bool shouldWriteRestartFile()
{
return false;
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
Scalar tol = this->model().newtonMethod().tolerance() * 1e5;
this->model().checkConservativeness(tol);
// Calculate storage terms
PrimaryVariables storageO, storageW;
this->model().globalPhaseStorage(storageO, oilPhaseIdx);
// Calculate storage terms
PrimaryVariables storageL, storageG;
this->model().globalPhaseStorage(storageL, /*phaseIdx=*/0);
this->model().globalPhaseStorage(storageG, /*phaseIdx=*/1);
// Write mass balance information for rank 0
// if (this->gridView().comm().rank() == 0) {
// std::cout << "Storage: liquid=[" << storageL << "]"
// << " gas=[" << storageG << "]\n" << std::flush;
// }
}
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
Opm::CompositionalFluidState<Evaluation, FluidSystem> fs;
initialFluidState(fs, context, spaceIdx, timeIdx);
values.assignNaive(fs);
}
// Constant temperature
template <class Context>
Scalar temperature([[maybe_unused]] const Context& context, [[maybe_unused]] unsigned spaceIdx, [[maybe_unused]] unsigned timeIdx) const
{
return temperature_;
}
// Constant permeability
template <class Context>
const DimMatrix& intrinsicPermeability([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{
return K_;
}
// Constant porosity
template <class Context>
Scalar porosity([[maybe_unused]] const Context& context, [[maybe_unused]] unsigned spaceIdx, [[maybe_unused]] unsigned timeIdx) const
{
int spatialIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
int inj = 0;
int prod = Parameters::Get<Parameters::CellsX>() - 1;
if (spatialIdx == inj || spatialIdx == prod) {
return 1.0;
} else {
return porosity_;
}
}
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{
return this->mat_;
}
// No flow (introduce fake wells instead)
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ values.setNoFlow(); }
// No source terms
template <class Context>
void source(RateVector& source_rate,
[[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{
source_rate = Scalar(0.0);
}
private:
/*!
* \copydoc FvBaseProblem::initial
*/
template <class FluidState, class Context>
void initialFluidState(FluidState& fs, const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
// z0 = [0.5, 0.3, 0.2]
// zi = [0.99, 0.01-1e-3, 1e-3]
// p0 = 75e5
// T0 = 423.25
int inj = 0;
int prod = Parameters::Get<Parameters::CellsX>() - 1;
int spatialIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
ComponentVector comp;
comp[0] = Evaluation::createVariable(0.5, 1);
comp[1] = Evaluation::createVariable(0.3, 2);
comp[2] = 1. - comp[0] - comp[1];
if (spatialIdx == inj) {
comp[0] = Evaluation::createVariable(0.99, 1);
comp[1] = Evaluation::createVariable(0.01 - 1e-3, 2);
comp[2] = 1. - comp[0] - comp[1];
}
ComponentVector sat;
sat[0] = 1.0;
sat[1] = 1.0 - sat[0];
Scalar p0 = Parameters::Get<Parameters::Initialpressure<Scalar>>();
//\Note, for an AD variable, if we multiply it with 2, the derivative will also be scalced with 2,
//\Note, so we should not do it.
if (spatialIdx == inj) {
p0 *= 2.0;
}
if (spatialIdx == prod) {
p0 *= 0.5;
}
Evaluation p_init = Evaluation::createVariable(p0, 0);
fs.setPressure(FluidSystem::oilPhaseIdx, p_init);
fs.setPressure(FluidSystem::gasPhaseIdx, p_init);
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
fs.setMoleFraction(FluidSystem::oilPhaseIdx, compIdx, comp[compIdx]);
fs.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, comp[compIdx]);
}
// It is used here only for calculate the z
fs.setSaturation(FluidSystem::oilPhaseIdx, sat[0]);
fs.setSaturation(FluidSystem::gasPhaseIdx, sat[1]);
fs.setTemperature(temperature_);
// ParameterCache paramCache;
{
typename FluidSystem::template ParameterCache<Evaluation> paramCache;
paramCache.updatePhase(fs, FluidSystem::oilPhaseIdx);
paramCache.updatePhase(fs, FluidSystem::gasPhaseIdx);
fs.setDensity(FluidSystem::oilPhaseIdx, FluidSystem::density(fs, paramCache, FluidSystem::oilPhaseIdx));
fs.setDensity(FluidSystem::gasPhaseIdx, FluidSystem::density(fs, paramCache, FluidSystem::gasPhaseIdx));
fs.setViscosity(FluidSystem::oilPhaseIdx, FluidSystem::viscosity(fs, paramCache, FluidSystem::oilPhaseIdx));
fs.setViscosity(FluidSystem::gasPhaseIdx, FluidSystem::viscosity(fs, paramCache, FluidSystem::gasPhaseIdx));
}
// Set initial K and L
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) {
const Evaluation Ktmp = fs.wilsonK_(compIdx);
fs.setKvalue(compIdx, Ktmp);
}
const Evaluation& Ltmp = -1.0;
fs.setLvalue(Ltmp);
}
DimMatrix K_;
Scalar porosity_;
Scalar temperature_;
MaterialLawParams mat_;
DimVector gravity_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,642 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::CuvetteProblem
*/
#ifndef EWOMS_CUVETTE_PROBLEM_HH
#define EWOMS_CUVETTE_PROBLEM_HH
#include <opm/models/pvs/pvsproperties.hh>
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
#include <opm/material/fluidsystems/H2OAirMesityleneFluidSystem.hpp>
#include <opm/material/fluidmatrixinteractions/ThreePhaseParkerVanGenuchten.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/thermal/ConstantSolidHeatCapLaw.hpp>
#include <opm/material/thermal/SomertonThermalConductionLaw.hpp>
#include <opm/material/constraintsolvers/MiscibleMultiPhaseComposition.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/common/Valgrind.hpp>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <string>
namespace Opm {
template <class TypeTag>
class CuvetteProblem;
}
namespace Opm::Properties {
// create a new type tag for the cuvette steam injection problem
namespace TTag {
struct CuvetteBaseProblem {};
}
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::CuvetteBaseProblem> { using type = Dune::YaspGrid<2>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::CuvetteBaseProblem> { using type = Opm::CuvetteProblem<TypeTag>; };
// Set the fluid system
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::CuvetteBaseProblem>
{ using type = Opm::H2OAirMesityleneFluidSystem<GetPropType<TypeTag, Properties::Scalar>>; };
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::CuvetteBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Traits = Opm::ThreePhaseMaterialTraits<
Scalar,
/*wettingPhaseIdx=*/FluidSystem::waterPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::naplPhaseIdx,
/*gasPhaseIdx=*/FluidSystem::gasPhaseIdx>;
public:
using type = Opm::ThreePhaseParkerVanGenuchten<Traits>;
};
// set the energy storage law for the solid phase
template<class TypeTag>
struct SolidEnergyLaw<TypeTag, TTag::CuvetteBaseProblem>
{ using type = Opm::ConstantSolidHeatCapLaw<GetPropType<TypeTag, Properties::Scalar>>; };
// Set the thermal conduction law
template<class TypeTag>
struct ThermalConductionLaw<TypeTag, TTag::CuvetteBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::SomertonThermalConductionLaw<FluidSystem, Scalar>;
};
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief Non-isothermal three-phase gas injection problem where a hot gas
* is injected into a unsaturated porous medium with a residually
* trapped NAPL contamination.
*
* The domain is a quasi-two-dimensional container (cuvette). Its
* dimensions are 1.5 m x 0.74 m. The top and bottom boundaries are
* closed, the right boundary is a free-flow boundary allowing fluids
* to escape. From the left, an injection of a hot water-air mixture
* is injected. The set-up is aimed at remediating an initial NAPL
* (Non-Aquoeus Phase Liquid) contamination in the domain. The
* contamination is initially placed partly into the ambient coarse
* sand and partly into a fine sand lens.
*
* This simulation can be varied through assigning different boundary conditions
* at the left boundary as described in Class (2001):
* Theorie und numerische Modellierung nichtisothermer Mehrphasenprozesse in
* NAPL-kontaminierten poroesen Medien, Dissertation, Eigenverlag des Instituts
* fuer Wasserbau
*
* To see the basic effect and the differences to scenarios with pure
* steam or pure air injection, it is sufficient to simulate this
* problem to about 2-3 hours simulation time. Complete remediation
* of the domain requires much longer (about 10 days simulated time).
*/
template <class TypeTag>
class CuvetteProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using ThermalConductionLawParams = GetPropType<TypeTag, Properties::ThermalConductionLawParams>;
using SolidEnergyLawParams = GetPropType<TypeTag, Properties::SolidEnergyLawParams>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Model = GetPropType<TypeTag, Properties::Model>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
// copy some indices for convenience
using Indices = GetPropType<TypeTag, Properties::Indices>;
enum { numPhases = FluidSystem::numPhases };
enum { numComponents = FluidSystem::numComponents };
enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
enum { naplPhaseIdx = FluidSystem::naplPhaseIdx };
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
enum { H2OIdx = FluidSystem::H2OIdx };
enum { airIdx = FluidSystem::airIdx };
enum { NAPLIdx = FluidSystem::NAPLIdx };
enum { conti0EqIdx = Indices::conti0EqIdx };
// Grid and world dimension
enum { dimWorld = GridView::dimensionworld };
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
CuvetteProblem(Simulator& simulator)
: ParentType(simulator)
, eps_(1e-6)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
if (Opm::Valgrind::IsRunning())
FluidSystem::init(/*minT=*/283.15, /*maxT=*/500.0, /*nT=*/20,
/*minp=*/0.8e5, /*maxp=*/2e5, /*np=*/10);
else
FluidSystem::init(/*minT=*/283.15, /*maxT=*/500.0, /*nT=*/200,
/*minp=*/0.8e5, /*maxp=*/2e5, /*np=*/100);
// intrinsic permeabilities
fineK_ = this->toDimMatrix_(6.28e-12);
coarseK_ = this->toDimMatrix_(9.14e-10);
// porosities
finePorosity_ = 0.42;
coarsePorosity_ = 0.42;
// parameters for the capillary pressure law
#if 1
// three-phase Parker -- van Genuchten law
fineMaterialParams_.setVgAlpha(0.0005);
coarseMaterialParams_.setVgAlpha(0.005);
fineMaterialParams_.setVgN(4.0);
coarseMaterialParams_.setVgN(4.0);
coarseMaterialParams_.setkrRegardsSnr(true);
fineMaterialParams_.setkrRegardsSnr(true);
// residual saturations
fineMaterialParams_.setSwr(0.1201);
fineMaterialParams_.setSwrx(0.1201);
fineMaterialParams_.setSnr(0.0701);
fineMaterialParams_.setSgr(0.0101);
coarseMaterialParams_.setSwr(0.1201);
coarseMaterialParams_.setSwrx(0.1201);
coarseMaterialParams_.setSnr(0.0701);
coarseMaterialParams_.setSgr(0.0101);
#else
// linear material law
fineMaterialParams_.setPcMinSat(gasPhaseIdx, 0);
fineMaterialParams_.setPcMaxSat(gasPhaseIdx, 0);
fineMaterialParams_.setPcMinSat(naplPhaseIdx, 0);
fineMaterialParams_.setPcMaxSat(naplPhaseIdx, -1000);
fineMaterialParams_.setPcMinSat(waterPhaseIdx, 0);
fineMaterialParams_.setPcMaxSat(waterPhaseIdx, -10000);
coarseMaterialParams_.setPcMinSat(gasPhaseIdx, 0);
coarseMaterialParams_.setPcMaxSat(gasPhaseIdx, 0);
coarseMaterialParams_.setPcMinSat(naplPhaseIdx, 0);
coarseMaterialParams_.setPcMaxSat(naplPhaseIdx, -100);
coarseMaterialParams_.setPcMinSat(waterPhaseIdx, 0);
coarseMaterialParams_.setPcMaxSat(waterPhaseIdx, -1000);
// residual saturations
fineMaterialParams_.setResidSat(waterPhaseIdx, 0.1201);
fineMaterialParams_.setResidSat(naplPhaseIdx, 0.0701);
fineMaterialParams_.setResidSat(gasPhaseIdx, 0.0101);
coarseMaterialParams_.setResidSat(waterPhaseIdx, 0.1201);
coarseMaterialParams_.setResidSat(naplPhaseIdx, 0.0701);
coarseMaterialParams_.setResidSat(gasPhaseIdx, 0.0101);
#endif
fineMaterialParams_.finalize();
coarseMaterialParams_.finalize();
// initialize parameters for the thermal conduction law
computeThermalCondParams_(thermalCondParams_, finePorosity_);
// assume constant volumetric heat capacity and granite
solidEnergyLawParams_.setSolidHeatCapacity(790.0 // specific heat capacity of granite [J / (kg K)]
* 2700.0); // density of granite [kg/m^3]
solidEnergyLawParams_.finalize();
initInjectFluidState_();
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::GridFile>("./data/cuvette_11x4.dgf");
Parameters::SetDefault<Parameters::EndTime<Scalar>>(100.0);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(1.0);
Parameters::SetDefault<Parameters::MaxTimeStepSize<Scalar>>(600.0);
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \name Auxiliary methods
*/
//! \{
/*!
* \copydoc FvBaseProblem::shouldWriteRestartFile
*
* This problem writes a restart file after every time step.
*/
bool shouldWriteRestartFile() const
{ return true; }
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{ return std::string("cuvette_") + Model::name(); }
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
//! \}
/*!
* \name Soil parameters
*/
//! \{
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return 293.15; /* [K] */ }
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& context, unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineK_;
return coarseK_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return finePorosity_;
else
return coarsePorosity_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams(const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineMaterialParams_;
else
return coarseMaterialParams_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::thermalConductionParams
*/
template <class Context>
const ThermalConductionLawParams &
thermalConductionParams(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return thermalCondParams_; }
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const auto& pos = context.pos(spaceIdx, timeIdx);
if (onRightBoundary_(pos)) {
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
values.setNoFlow();
}
else if (onLeftBoundary_(pos)) {
// injection
RateVector molarRate;
// inject with the same composition as the gas phase of
// the injection fluid state
Scalar molarInjectionRate = 0.3435; // [mol/(m^2 s)]
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
molarRate[conti0EqIdx + compIdx] =
-molarInjectionRate
* injectFluidState_.moleFraction(gasPhaseIdx, compIdx);
// calculate the total mass injection rate [kg / (m^2 s)
Scalar massInjectionRate =
molarInjectionRate
* injectFluidState_.averageMolarMass(gasPhaseIdx);
// set the boundary rate vector [J / (m^2 s)]
values.setMolarRate(molarRate);
values.setEnthalpyRate(-injectFluidState_.enthalpy(gasPhaseIdx) * massInjectionRate);
}
else
values.setNoFlow();
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx,
unsigned timeIdx) const
{
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
const auto& matParams = materialLawParams(context, spaceIdx, timeIdx);
values.assignMassConservative(fs, matParams, /*inEquilibrium=*/false);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition& pos) const
{ return pos[1] < eps_; }
bool onUpperBoundary_(const GlobalPosition& pos) const
{ return pos[1] > this->boundingBoxMax()[1] - eps_; }
bool isContaminated_(const GlobalPosition& pos) const
{
return (0.20 <= pos[0]) && (pos[0] <= 0.80) && (0.4 <= pos[1])
&& (pos[1] <= 0.65);
}
bool isFineMaterial_(const GlobalPosition& pos) const
{
if (0.13 <= pos[0] && 1.20 >= pos[0] && 0.32 <= pos[1] && pos[1] <= 0.57)
return true;
else if (pos[1] <= 0.15 && 1.20 <= pos[0])
return true;
else
return false;
}
template <class FluidState, class Context>
void initialFluidState_(FluidState& fs, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
fs.setTemperature(293.0 /*[K]*/);
Scalar pw = 1e5;
if (isContaminated_(pos)) {
fs.setSaturation(waterPhaseIdx, 0.12);
fs.setSaturation(naplPhaseIdx, 0.07);
fs.setSaturation(gasPhaseIdx, 1 - 0.12 - 0.07);
// set the capillary pressures
const auto& matParams = materialLawParams(context, spaceIdx, timeIdx);
Scalar pc[numPhases];
MaterialLaw::capillaryPressures(pc, matParams, fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
fs.setPressure(phaseIdx, pw + (pc[phaseIdx] - pc[waterPhaseIdx]));
// compute the phase compositions
using MMPC = Opm::MiscibleMultiPhaseComposition<Scalar, FluidSystem>;
typename FluidSystem::template ParameterCache<Scalar> paramCache;
MMPC::solve(fs, paramCache, /*setViscosity=*/true, /*setEnthalpy=*/true);
}
else {
fs.setSaturation(waterPhaseIdx, 0.12);
fs.setSaturation(gasPhaseIdx, 1 - fs.saturation(waterPhaseIdx));
fs.setSaturation(naplPhaseIdx, 0);
// set the capillary pressures
const auto& matParams = materialLawParams(context, spaceIdx, timeIdx);
Scalar pc[numPhases];
MaterialLaw::capillaryPressures(pc, matParams, fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
fs.setPressure(phaseIdx, pw + (pc[phaseIdx] - pc[waterPhaseIdx]));
// compute the phase compositions
using MMPC = Opm::MiscibleMultiPhaseComposition<Scalar, FluidSystem>;
typename FluidSystem::template ParameterCache<Scalar> paramCache;
MMPC::solve(fs, paramCache, /*setViscosity=*/true, /*setEnthalpy=*/true);
// set the contaminant mole fractions to zero. this is a little bit hacky...
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
fs.setMoleFraction(phaseIdx, NAPLIdx, 0.0);
if (phaseIdx == naplPhaseIdx)
continue;
Scalar sumx = 0;
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
sumx += fs.moleFraction(phaseIdx, compIdx);
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
fs.setMoleFraction(phaseIdx, compIdx,
fs.moleFraction(phaseIdx, compIdx) / sumx);
}
}
}
void computeThermalCondParams_(ThermalConductionLawParams& params, Scalar poro)
{
Scalar lambdaGranite = 2.8; // [W / (K m)]
// create a Fluid state which has all phases present
Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
fs.setTemperature(293.15);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
fs.setPressure(phaseIdx, 1.0135e5);
}
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
Scalar rho = FluidSystem::density(fs, paramCache, phaseIdx);
fs.setDensity(phaseIdx, rho);
}
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
Scalar lambdaSaturated;
if (FluidSystem::isLiquid(phaseIdx)) {
Scalar lambdaFluid = FluidSystem::thermalConductivity(fs, paramCache, phaseIdx);
lambdaSaturated =
std::pow(lambdaGranite, (1 - poro))
+
std::pow(lambdaFluid, poro);
}
else
lambdaSaturated = std::pow(lambdaGranite, (1 - poro));
params.setFullySaturatedLambda(phaseIdx, lambdaSaturated);
if (!FluidSystem::isLiquid(phaseIdx))
params.setVacuumLambda(lambdaSaturated);
}
}
void initInjectFluidState_()
{
injectFluidState_.setTemperature(383.0); // [K]
injectFluidState_.setPressure(gasPhaseIdx, 1e5); // [Pa]
injectFluidState_.setSaturation(gasPhaseIdx, 1.0); // [-]
Scalar xgH2O = 0.417;
injectFluidState_.setMoleFraction(gasPhaseIdx, H2OIdx, xgH2O); // [-]
injectFluidState_.setMoleFraction(gasPhaseIdx, airIdx, 1 - xgH2O); // [-]
injectFluidState_.setMoleFraction(gasPhaseIdx, NAPLIdx, 0.0); // [-]
// set the specific enthalpy of the gas phase
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updatePhase(injectFluidState_, gasPhaseIdx);
Scalar h = FluidSystem::enthalpy(injectFluidState_, paramCache, gasPhaseIdx);
injectFluidState_.setEnthalpy(gasPhaseIdx, h);
}
DimMatrix fineK_;
DimMatrix coarseK_;
Scalar finePorosity_;
Scalar coarsePorosity_;
MaterialLawParams fineMaterialParams_;
MaterialLawParams coarseMaterialParams_;
ThermalConductionLawParams thermalCondParams_;
SolidEnergyLawParams solidEnergyLawParams_;
Opm::CompositionalFluidState<Scalar, FluidSystem> injectFluidState_;
const Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,385 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::DiffusionProblem
*/
#ifndef EWOMS_POWER_INJECTION_PROBLEM_HH
#define EWOMS_POWER_INJECTION_PROBLEM_HH
#include <opm/models/ncp/ncpproperties.hh>
#include <opm/models/io/cubegridvanguard.hh>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/fluidsystems/H2ON2FluidSystem.hpp>
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
#include <opm/material/constraintsolvers/ComputeFromReferencePhase.hpp>
#include <dune/grid/yaspgrid.hh>
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <sstream>
#include <string>
namespace Opm {
template <class TypeTag>
class DiffusionProblem;
}
namespace Opm::Properties {
namespace TTag {
struct DiffusionBaseProblem {};
} // namespace TTag
// Set the grid implementation to be used
template<class TypeTag>
struct Grid<TypeTag, TTag::DiffusionBaseProblem> { using type = Dune::YaspGrid</*dim=*/1>; };
// set the Vanguard property
template<class TypeTag>
struct Vanguard<TypeTag, TTag::DiffusionBaseProblem> { using type = Opm::CubeGridVanguard<TypeTag>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::DiffusionBaseProblem> { using type = Opm::DiffusionProblem<TypeTag>; };
// Set the fluid system
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::DiffusionBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::H2ON2FluidSystem<Scalar>;
};
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::DiffusionBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
static_assert(FluidSystem::numPhases == 2,
"A fluid system with two phases is required "
"for this problem!");
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::liquidPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::gasPhaseIdx>;
public:
using type = Opm::LinearMaterial<Traits>;
};
// Enable molecular diffusion for this problem
template<class TypeTag>
struct EnableDiffusion<TypeTag, TTag::DiffusionBaseProblem> { static constexpr bool value = true; };
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
* \brief 1D problem which is driven by molecular diffusion.
*
* The domain is one meter long and completely filled with gas and
* closed on all boundaries. Its left half exhibits a slightly higher
* water concentration than the right one. After a while, the
* concentration of water will be equilibrate due to molecular
* diffusion.
*/
template <class TypeTag>
class DiffusionProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Model = GetPropType<TypeTag, Properties::Model>;
enum {
// number of phases
numPhases = FluidSystem::numPhases,
// phase indices
liquidPhaseIdx = FluidSystem::liquidPhaseIdx,
gasPhaseIdx = FluidSystem::gasPhaseIdx,
// component indices
H2OIdx = FluidSystem::H2OIdx,
N2Idx = FluidSystem::N2Idx,
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
DiffusionProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
FluidSystem::init();
temperature_ = 273.15 + 20.0;
materialParams_.finalize();
K_ = this->toDimMatrix_(1e-12); // [m^2]
setupInitialFluidStates_();
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::CellsX>(250);
if constexpr (dim > 1) {
Parameters::SetDefault<Parameters::CellsY>(1);
}
if constexpr (dim == 3) {
Parameters::SetDefault<Parameters::CellsZ>(1);
}
Parameters::SetDefault<Parameters::EndTime<Scalar>>(1e6);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(1000);
}
/*!
* \name Auxiliary methods
*/
//! \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{ return std::string("diffusion_") + Model::name(); }
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
//! \}
/*!
* \name Soil parameters
*/
//! \{
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return K_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return 0.35; }
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams&
materialLawParams(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return materialParams_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return temperature_; }
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*
* This problem sets no-flow boundaries everywhere.
*/
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ values.setNoFlow(); }
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const auto& pos = context.pos(spaceIdx, timeIdx);
if (onLeftSide_(pos))
values.assignNaive(leftInitialFluidState_);
else
values.assignNaive(rightInitialFluidState_);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool onLeftSide_(const GlobalPosition& pos) const
{ return pos[0] < (this->boundingBoxMin()[0] + this->boundingBoxMax()[0]) / 2; }
void setupInitialFluidStates_()
{
// create the initial fluid state for the left half of the domain
leftInitialFluidState_.setTemperature(temperature_);
Scalar Sl = 0.0;
leftInitialFluidState_.setSaturation(liquidPhaseIdx, Sl);
leftInitialFluidState_.setSaturation(gasPhaseIdx, 1 - Sl);
Scalar p = 1e5;
leftInitialFluidState_.setPressure(liquidPhaseIdx, p);
leftInitialFluidState_.setPressure(gasPhaseIdx, p);
Scalar xH2O = 0.01;
leftInitialFluidState_.setMoleFraction(gasPhaseIdx, H2OIdx, xH2O);
leftInitialFluidState_.setMoleFraction(gasPhaseIdx, N2Idx, 1 - xH2O);
using CFRP = Opm::ComputeFromReferencePhase<Scalar, FluidSystem>;
typename FluidSystem::template ParameterCache<Scalar> paramCache;
CFRP::solve(leftInitialFluidState_, paramCache, gasPhaseIdx,
/*setViscosity=*/false, /*setEnthalpy=*/false);
// create the initial fluid state for the right half of the domain
rightInitialFluidState_.assign(leftInitialFluidState_);
xH2O = 0.0;
rightInitialFluidState_.setMoleFraction(gasPhaseIdx, H2OIdx, xH2O);
rightInitialFluidState_.setMoleFraction(gasPhaseIdx, N2Idx, 1 - xH2O);
CFRP::solve(rightInitialFluidState_, paramCache, gasPhaseIdx,
/*setViscosity=*/false, /*setEnthalpy=*/false);
}
DimMatrix K_;
MaterialLawParams materialParams_;
Opm::CompositionalFluidState<Scalar, FluidSystem> leftInitialFluidState_;
Opm::CompositionalFluidState<Scalar, FluidSystem> rightInitialFluidState_;
Scalar temperature_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,562 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::FingerProblem
*/
#ifndef EWOMS_FINGER_PROBLEM_HH
#define EWOMS_FINGER_PROBLEM_HH
#if HAVE_DUNE_ALUGRID
#include <dune/alugrid/grid.hh>
#endif
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <dune/common/version.hh>
#include <dune/grid/utility/persistentcontainer.hh>
#include <opm/material/components/Air.hpp>
#include <opm/material/components/SimpleH2O.hpp>
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/fluidmatrixinteractions/ParkerLenhard.hpp>
#include <opm/material/fluidmatrixinteractions/RegularizedVanGenuchten.hpp>
#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
#include <opm/material/fluidsystems/TwoPhaseImmiscibleFluidSystem.hpp>
#include <opm/models/common/multiphasebaseparameters.hh>
#include <opm/models/discretization/common/fvbasefdlocallinearizer.hh>
#include <opm/models/discretization/common/restrictprolong.hh>
#include <opm/models/immiscible/immiscibleproperties.hh>
#include <opm/models/io/structuredgridvanguard.hh>
#include <string>
namespace Opm {
template <class TypeTag>
class FingerProblem;
} // namespace Opm
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct FingerBaseProblem { using InheritsFrom = std::tuple<StructuredGridVanguard>; };
} // end namespace TTag
#if HAVE_DUNE_ALUGRID
// use dune-alugrid if available
template<class TypeTag>
struct Grid<TypeTag, TTag::FingerBaseProblem>
{ using type = Dune::ALUGrid</*dim=*/2,
/*dimWorld=*/2,
Dune::cube,
Dune::nonconforming>; };
#endif
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::FingerBaseProblem> { using type = Opm::FingerProblem<TypeTag>; };
// Set the wetting phase
template<class TypeTag>
struct WettingPhase<TypeTag, TTag::FingerBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::LiquidPhase<Scalar, Opm::SimpleH2O<Scalar> >;
};
// Set the non-wetting phase
template<class TypeTag>
struct NonwettingPhase<TypeTag, TTag::FingerBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::GasPhase<Scalar, Opm::Air<Scalar> >;
};
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::FingerBaseProblem>
{
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::wettingPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::nonWettingPhaseIdx>;
// use the parker-lenhard hysteresis law
using ParkerLenhard = Opm::ParkerLenhard<Traits>;
using type = ParkerLenhard;
};
// Enable constraints
template<class TypeTag>
struct EnableConstraints<TypeTag, TTag::FingerBaseProblem> { static constexpr int value = true; };
} // namespace Opm::Properties
namespace Opm::Parameters {
template<class Scalar>
struct InitialWaterSaturation { static constexpr Scalar value = 0.01; };
} // namespace Opm::Parameters
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief Two-phase problem featuring some gravity-driven saturation
* fingers.
*
* The domain of this problem is sized 10cm times 1m and is initially
* dry. Water is then injected at three locations on the top of the
* domain which leads to gravity fingering. The boundary conditions
* used are no-flow for the left and right and top of the domain and
* free-flow at the bottom. This problem uses the Parker-Lenhard
* hystersis model which might lead to non-monotonic saturation in the
* fingers if the right material parameters is chosen and the spatial
* discretization is fine enough.
*/
template <class TypeTag>
class FingerProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
//!\cond SKIP_THIS
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using Indices = GetPropType<TypeTag, Properties::Indices>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using WettingPhase = GetPropType<TypeTag, Properties::WettingPhase>;
using NonwettingPhase = GetPropType<TypeTag, Properties::NonwettingPhase>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Constraints = GetPropType<TypeTag, Properties::Constraints>;
using Model = GetPropType<TypeTag, Properties::Model>;
enum {
// number of phases
numPhases = FluidSystem::numPhases,
// phase indices
wettingPhaseIdx = FluidSystem::wettingPhaseIdx,
nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx,
// equation indices
contiWettingEqIdx = Indices::conti0EqIdx + wettingPhaseIdx,
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
using ElementContext = GetPropType<TypeTag, Properties::ElementContext>;
using Stencil = GetPropType<TypeTag, Properties::Stencil> ;
enum { codim = Stencil::Entity::codimension };
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using ParkerLenhard = typename GetProp<TypeTag, Properties::MaterialLaw>::ParkerLenhard;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
using Grid = typename GridView :: Grid;
using MaterialLawParamsContainer = Dune::PersistentContainer< Grid, std::shared_ptr< MaterialLawParams > > ;
//!\endcond
public:
using RestrictProlongOperator = CopyRestrictProlong< Grid, MaterialLawParamsContainer >;
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
FingerProblem(Simulator& simulator)
: ParentType(simulator),
materialParams_( simulator.vanguard().grid(), codim )
{
}
/*!
* \name Auxiliary methods
*/
//! \{
/*!
* \brief \copydoc FvBaseProblem::restrictProlongOperator
*/
RestrictProlongOperator restrictProlongOperator()
{
return RestrictProlongOperator( materialParams_ );
}
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{ return
std::string("finger") +
"_" + Model::name() +
"_" + Model::discretizationName() +
(this->model().enableGridAdaptation()?"_adaptive":"");
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::Register<Parameters::InitialWaterSaturation<Scalar>>
("The initial saturation in the domain [] of the wetting phase");
Parameters::SetDefault<Parameters::CellsX>(20);
Parameters::SetDefault<Parameters::DomainSizeX<Scalar>>(0.1);
if constexpr (dim > 1) {
Parameters::SetDefault<Parameters::CellsY>(70);
Parameters::SetDefault<Parameters::DomainSizeY<Scalar>>(0.3);
}
if constexpr (dim == 3) {
Parameters::SetDefault<Parameters::CellsZ>(1);
Parameters::SetDefault<Parameters::DomainSizeZ<Scalar>>(0.1);
}
// Use forward differences
Parameters::SetDefault<Parameters::NumericDifferenceMethod>(+1);
Parameters::SetDefault<Parameters::EndTime<Scalar>>(215);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(10);
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \copydoc FvBaseProblem::finishInit()
*/
void finishInit()
{
ParentType::finishInit();
eps_ = 3e-6;
temperature_ = 273.15 + 20; // -> 20°C
FluidSystem::init();
// parameters for the Van Genuchten law of the main imbibition
// and the main drainage curves.
micParams_.setVgAlpha(0.0037);
micParams_.setVgN(4.7);
micParams_.finalize();
mdcParams_.setVgAlpha(0.0037);
mdcParams_.setVgN(4.7);
mdcParams_.finalize();
// initialize the material parameter objects of the individual
// finite volumes, resize will resize the container to the number of elements
materialParams_.resize();
for (auto it = materialParams_.begin(),
end = materialParams_.end(); it != end; ++it ) {
std::shared_ptr< MaterialLawParams >& materialParams = *it ;
if( ! materialParams )
{
materialParams.reset( new MaterialLawParams() );
materialParams->setMicParams(&micParams_);
materialParams->setMdcParams(&mdcParams_);
materialParams->setSwr(0.0);
materialParams->setSnr(0.1);
materialParams->finalize();
ParkerLenhard::reset(*materialParams);
}
}
K_ = this->toDimMatrix_(4.6e-10);
setupInitialFluidState_();
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
// checkConservativeness() does not include the effect of constraints, so we
// disable it for this problem...
//this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
// update the history of the hysteresis law
ElementContext elemCtx(this->simulator());
for (const auto& elem : elements(this->gridView())) {
elemCtx.updateAll(elem);
size_t numDofs = elemCtx.numDof(/*timeIdx=*/0);
for (unsigned scvIdx = 0; scvIdx < numDofs; ++scvIdx)
{
MaterialLawParams& materialParam = materialLawParams( elemCtx, scvIdx, /*timeIdx=*/0 );
const auto& fs = elemCtx.intensiveQuantities(scvIdx, /*timeIdx=*/0).fluidState();
ParkerLenhard::update(materialParam, fs);
}
}
}
//! \}
/*!
* \name Soil parameters
*/
//! \{
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& /*context*/, unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{ return temperature_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& /*context*/, unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{ return K_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& /*context*/, unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{ return 0.4; }
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
MaterialLawParams& materialLawParams(const Context& context,
unsigned spaceIdx, unsigned timeIdx)
{
const auto& entity = context.stencil(timeIdx).entity(spaceIdx);
assert(materialParams_[entity]);
return *materialParams_[entity];
}
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams(const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const auto& entity = context.stencil(timeIdx).entity( spaceIdx );
assert(materialParams_[entity]);
return *materialParams_[entity];
}
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (onLeftBoundary_(pos) || onRightBoundary_(pos) || onLowerBoundary_(pos))
values.setNoFlow();
else {
assert(onUpperBoundary_(pos));
values.setFreeFlow(context, spaceIdx, timeIdx, initialFluidState_);
}
// override the value for the liquid phase by forced
// imbibition of water on inlet boundary segments
if (onInlet_(pos)) {
values[contiWettingEqIdx] = -0.001; // [kg/(m^2 s)]
}
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values, const Context& /*context*/, unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{
// assign the primary variables
values.assignNaive(initialFluidState_);
}
/*!
* \copydoc FvBaseProblem::constraints
*/
template <class Context>
void constraints(Constraints& constraints, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (onUpperBoundary_(pos) && !onInlet_(pos)) {
constraints.setActive(true);
constraints.assignNaive(initialFluidState_);
}
else if (onLowerBoundary_(pos)) {
constraints.setActive(true);
constraints.assignNaive(initialFluidState_);
}
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate, const Context& /*context*/,
unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < this->boundingBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition& pos) const
{ return pos[1] < this->boundingBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition& pos) const
{ return pos[1] > this->boundingBoxMax()[1] - eps_; }
bool onInlet_(const GlobalPosition& pos) const
{
Scalar width = this->boundingBoxMax()[0] - this->boundingBoxMin()[0];
Scalar lambda = (this->boundingBoxMax()[0] - pos[0]) / width;
if (!onUpperBoundary_(pos))
return false;
Scalar xInject[] = { 0.25, 0.75 };
Scalar injectLen[] = { 0.1, 0.1 };
for (unsigned i = 0; i < sizeof(xInject) / sizeof(Scalar); ++i) {
if (xInject[i] - injectLen[i] / 2 < lambda
&& lambda < xInject[i] + injectLen[i] / 2)
return true;
}
return false;
}
void setupInitialFluidState_()
{
auto& fs = initialFluidState_;
fs.setPressure(wettingPhaseIdx, /*pressure=*/1e5);
Scalar Sw = Parameters::Get<Parameters::InitialWaterSaturation<Scalar>>();
fs.setSaturation(wettingPhaseIdx, Sw);
fs.setSaturation(nonWettingPhaseIdx, 1 - Sw);
fs.setTemperature(temperature_);
// set the absolute pressures
Scalar pn = 1e5;
fs.setPressure(nonWettingPhaseIdx, pn);
fs.setPressure(wettingPhaseIdx, pn);
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
fs.setDensity(phaseIdx, FluidSystem::density(fs, paramCache, phaseIdx));
fs.setViscosity(phaseIdx, FluidSystem::viscosity(fs, paramCache, phaseIdx));
}
}
DimMatrix K_;
typename MaterialLawParams::VanGenuchtenParams micParams_;
typename MaterialLawParams::VanGenuchtenParams mdcParams_;
MaterialLawParamsContainer materialParams_;
Opm::ImmiscibleFluidState<Scalar, FluidSystem> initialFluidState_;
Scalar temperature_;
Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,663 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::FractureProblem
*/
#ifndef EWOMS_FRACTURE_PROBLEM_HH
#define EWOMS_FRACTURE_PROBLEM_HH
#if HAVE_DUNE_ALUGRID
// avoid reordering of macro elements, otherwise this problem won't work
#define DISABLE_ALUGRID_SFC_ORDERING 1
#include <dune/alugrid/grid.hh>
#include <dune/alugrid/dgf.hh>
#else
#error "dune-alugrid not found!"
#endif
#include <opm/models/discretefracture/discretefracturemodel.hh>
#include <opm/models/io/dgfvanguard.hh>
#include <opm/material/fluidmatrixinteractions/RegularizedBrooksCorey.hpp>
#include <opm/material/fluidmatrixinteractions/RegularizedVanGenuchten.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/thermal/SomertonThermalConductionLaw.hpp>
#include <opm/material/thermal/ConstantSolidHeatCapLaw.hpp>
#include <opm/material/fluidsystems/TwoPhaseImmiscibleFluidSystem.hpp>
#include <opm/material/components/SimpleH2O.hpp>
#include <opm/material/components/Dnapl.hpp>
#include <dune/common/version.hh>
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <iostream>
#include <sstream>
#include <string>
namespace Opm {
template <class TypeTag>
class FractureProblem;
}
namespace Opm::Properties {
// Create a type tag for the problem
// Create new type tags
namespace TTag {
struct FractureProblem { using InheritsFrom = std::tuple<DiscreteFractureModel>; };
} // end namespace TTag
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::FractureProblem>
{ using type = Dune::ALUGrid</*dim=*/2, /*dimWorld=*/2, Dune::simplex, Dune::nonconforming>; };
// Set the Vanguard property
template<class TypeTag>
struct Vanguard<TypeTag, TTag::FractureProblem> { using type = Opm::DgfVanguard<TypeTag>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::FractureProblem> { using type = Opm::FractureProblem<TypeTag>; };
// Set the wetting phase
template<class TypeTag>
struct WettingPhase<TypeTag, TTag::FractureProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::LiquidPhase<Scalar, Opm::SimpleH2O<Scalar> >;
};
// Set the non-wetting phase
template<class TypeTag>
struct NonwettingPhase<TypeTag, TTag::FractureProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::LiquidPhase<Scalar, Opm::DNAPL<Scalar> >;
};
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::FractureProblem>
{
private:
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx };
enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx };
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::wettingPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::nonWettingPhaseIdx>;
// define the material law which is parameterized by effective
// saturations
using EffectiveLaw = Opm::RegularizedBrooksCorey<Traits>;
// using EffectiveLaw = RegularizedVanGenuchten<Traits>;
// using EffectiveLaw = LinearMaterial<Traits>;
public:
using type = Opm::EffToAbsLaw<EffectiveLaw>;
};
// Enable the energy equation
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::FractureProblem> { static constexpr bool value = true; };
// Set the thermal conduction law
template<class TypeTag>
struct ThermalConductionLaw<TypeTag, TTag::FractureProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::SomertonThermalConductionLaw<FluidSystem, Scalar>;
};
// set the energy storage law for the solid phase
template<class TypeTag>
struct SolidEnergyLaw<TypeTag, TTag::FractureProblem>
{ using type = Opm::ConstantSolidHeatCapLaw<GetPropType<TypeTag, Properties::Scalar>>; };
// For this problem, we use constraints to specify the left boundary
template<class TypeTag>
struct EnableConstraints<TypeTag, TTag::FractureProblem> { static constexpr bool value = true; };
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief Two-phase problem which involves fractures
*
* The domain is initially completely saturated by the oil phase,
* except for the left side, which is fully water saturated. Since the
* capillary pressure in the fractures is lower than in the rock
* matrix and the material is hydrophilic, water infiltrates through
* the fractures and gradually pushes the oil out on the right side,
* where the pressure is kept constant.
*/
template <class TypeTag>
class FractureProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using WettingPhase = GetPropType<TypeTag, Properties::WettingPhase>;
using NonwettingPhase = GetPropType<TypeTag, Properties::NonwettingPhase>;
using Constraints = GetPropType<TypeTag, Properties::Constraints>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using ThermalConductionLawParams = GetPropType<TypeTag, Properties::ThermalConductionLawParams>;
using SolidEnergyLawParams = GetPropType<TypeTag, Properties::SolidEnergyLawParams>;
using Model = GetPropType<TypeTag, Properties::Model>;
enum {
// phase indices
wettingPhaseIdx = MaterialLaw::wettingPhaseIdx,
nonWettingPhaseIdx = MaterialLaw::nonWettingPhaseIdx,
// number of phases
numPhases = FluidSystem::numPhases,
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
using FluidState = Opm::ImmiscibleFluidState<Scalar, FluidSystem>;
using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
template <int dim>
struct FaceLayout
{
bool contains(Dune::GeometryType gt)
{ return gt.dim() == dim - 1; }
};
using FaceMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GridView>;
using FractureMapper = Opm::FractureMapper<TypeTag>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
FractureProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
eps_ = 3e-6;
temperature_ = 273.15 + 20; // -> 20°C
matrixMaterialParams_.setResidualSaturation(wettingPhaseIdx, 0.0);
matrixMaterialParams_.setResidualSaturation(nonWettingPhaseIdx, 0.0);
fractureMaterialParams_.setResidualSaturation(wettingPhaseIdx, 0.0);
fractureMaterialParams_.setResidualSaturation(nonWettingPhaseIdx, 0.0);
#if 0 // linear
matrixMaterialParams_.setEntryPC(0.0);
matrixMaterialParams_.setMaxPC(2000.0);
fractureMaterialParams_.setEntryPC(0.0);
fractureMaterialParams_.setMaxPC(1000.0);
#endif
#if 1 // Brooks-Corey
matrixMaterialParams_.setEntryPressure(2000);
matrixMaterialParams_.setLambda(2.0);
matrixMaterialParams_.setPcLowSw(1e-1);
fractureMaterialParams_.setEntryPressure(1000);
fractureMaterialParams_.setLambda(2.0);
fractureMaterialParams_.setPcLowSw(5e-2);
#endif
#if 0 // van Genuchten
matrixMaterialParams_.setVgAlpha(0.0037);
matrixMaterialParams_.setVgN(4.7);
fractureMaterialParams_.setVgAlpha(0.0025);
fractureMaterialParams_.setVgN(4.7);
#endif
matrixMaterialParams_.finalize();
fractureMaterialParams_.finalize();
matrixK_ = this->toDimMatrix_(1e-15); // m^2
fractureK_ = this->toDimMatrix_(1e5 * 1e-15); // m^2
matrixPorosity_ = 0.10;
fracturePorosity_ = 0.25;
fractureWidth_ = 1e-3; // [m]
// initialize the energy-related parameters
initEnergyParams_(thermalConductionParams_, matrixPorosity_);
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::GridFile>("data/fracture.art.dgf");
Parameters::SetDefault<Parameters::EndTime<Scalar>>(3e3);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(100);
}
/*!
* \name Auxiliary methods
*/
//! \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << "fracture_" << Model::name();
return oss.str();
}
/*!
* \brief Called directly after the time integration.
*/
void endTimeStep()
{
#ifndef NDEBUG
// checkConservativeness() does not include the effect of constraints, so we
// disable it for this problem...
//this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return temperature_; }
// \}
/*!
* \name Soil parameters
*/
//! \{
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return matrixK_; }
/*!
* \brief Intrinsic permeability of fractures.
*
* \copydoc Doxygen::contextParams
*/
template <class Context>
const DimMatrix& fractureIntrinsicPermeability([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return fractureK_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return matrixPorosity_; }
/*!
* \brief The porosity inside the fractures.
*
* \copydoc Doxygen::contextParams
*/
template <class Context>
Scalar fracturePorosity([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return fracturePorosity_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return matrixMaterialParams_; }
/*!
* \brief The parameters for the material law inside the fractures.
*
* \copydoc Doxygen::contextParams
*/
template <class Context>
const MaterialLawParams& fractureMaterialLawParams([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return fractureMaterialParams_; }
/*!
* \brief Returns the object representating the fracture topology.
*/
const FractureMapper& fractureMapper() const
{ return this->simulator().vanguard().fractureMapper(); }
/*!
* \brief Returns the width of the fracture.
*
* \todo This method should get one face index instead of two
* vertex indices. This probably requires a new context
* class, though.
*
* \param context The execution context.
* \param spaceIdx1 The local index of the edge's first edge.
* \param spaceIdx2 The local index of the edge's second edge.
* \param timeIdx The index used by the time discretization.
*/
template <class Context>
Scalar fractureWidth([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx1,
[[maybe_unused]] unsigned spaceIdx2,
[[maybe_unused]] unsigned timeIdx) const
{ return fractureWidth_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::thermalConductionParams
*/
template <class Context>
const ThermalConductionLawParams&
thermalConductionLawParams([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return thermalConductionParams_; }
/*!
* \brief Return the parameters for the energy storage law of the rock
*
* In this case, we assume the rock-matrix to be granite.
*/
template <class Context>
const SolidEnergyLawParams&
solidEnergyLawParams([[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ return solidEnergyParams_; }
// \}
/*!
* \name Boundary conditions
*/
// \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (onRightBoundary_(pos)) {
// on the right boundary, we impose a free-flow
// (i.e. Dirichlet) condition
FluidState fluidState;
fluidState.setTemperature(temperature_);
fluidState.setSaturation(wettingPhaseIdx, 0.0);
fluidState.setSaturation(nonWettingPhaseIdx,
1.0 - fluidState.saturation(wettingPhaseIdx));
fluidState.setPressure(wettingPhaseIdx, 1e5);
fluidState.setPressure(nonWettingPhaseIdx, fluidState.pressure(wettingPhaseIdx));
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fluidState);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
fluidState.setDensity(phaseIdx,
FluidSystem::density(fluidState, paramCache, phaseIdx));
fluidState.setViscosity(phaseIdx,
FluidSystem::viscosity(fluidState, paramCache, phaseIdx));
}
// set a free flow (i.e. Dirichlet) boundary
values.setFreeFlow(context, spaceIdx, timeIdx, fluidState);
}
else
// for the upper, lower and left boundaries, use a no-flow
// condition (i.e. a Neumann 0 condition)
values.setNoFlow();
}
// \}
/*!
* \name Volumetric terms
*/
// \{
/*!
* \copydoc FvBaseProblem::constraints
*/
template <class Context>
void constraints(Constraints& constraints, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (!onLeftBoundary_(pos))
// only impose constraints adjacent to the left boundary
return;
unsigned globalIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
if (!fractureMapper().isFractureVertex(globalIdx)) {
// do not impose constraints if the finite volume does
// not contain fractures.
return;
}
// if the current finite volume is on the left boundary
// and features a fracture, specify the fracture fluid
// state.
FluidState fractureFluidState;
fractureFluidState.setTemperature(temperature_ + 10.0);
fractureFluidState.setSaturation(wettingPhaseIdx, 1.0);
fractureFluidState.setSaturation(nonWettingPhaseIdx,
1.0 - fractureFluidState.saturation(
wettingPhaseIdx));
Scalar pCFracture[numPhases];
MaterialLaw::capillaryPressures(pCFracture, fractureMaterialParams_,
fractureFluidState);
fractureFluidState.setPressure(wettingPhaseIdx, /*pressure=*/1.0e5);
fractureFluidState.setPressure(nonWettingPhaseIdx,
fractureFluidState.pressure(wettingPhaseIdx)
+ (pCFracture[nonWettingPhaseIdx]
- pCFracture[wettingPhaseIdx]));
constraints.setActive(true);
constraints.assignNaiveFromFracture(fractureFluidState,
matrixMaterialParams_);
}
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values,
[[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{
FluidState fluidState;
fluidState.setTemperature(temperature_);
fluidState.setPressure(FluidSystem::wettingPhaseIdx, /*pressure=*/1e5);
fluidState.setPressure(nonWettingPhaseIdx, fluidState.pressure(wettingPhaseIdx));
fluidState.setSaturation(wettingPhaseIdx, 0.0);
fluidState.setSaturation(nonWettingPhaseIdx,
1.0 - fluidState.saturation(wettingPhaseIdx));
values.assignNaive(fluidState);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
[[maybe_unused]] const Context& context,
[[maybe_unused]] unsigned spaceIdx,
[[maybe_unused]] unsigned timeIdx) const
{ rate = Scalar(0.0); }
// \}
private:
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < this->boundingBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition& pos) const
{ return pos[1] < this->boundingBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition& pos) const
{ return pos[1] > this->boundingBoxMax()[1] - eps_; }
void initEnergyParams_(ThermalConductionLawParams& params, Scalar poro)
{
// assume the volumetric heat capacity of granite
solidEnergyParams_.setSolidHeatCapacity(790.0 // specific heat capacity of granite [J / (kg K)]
* 2700.0); // density of granite [kg/m^3]
solidEnergyParams_.finalize();
Scalar lambdaGranite = 2.8; // [W / (K m)]
// create a Fluid state which has all phases present
Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
fs.setTemperature(293.15);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
fs.setPressure(phaseIdx, 1.0135e5);
}
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
Scalar rho = FluidSystem::density(fs, paramCache, phaseIdx);
fs.setDensity(phaseIdx, rho);
}
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
Scalar lambdaSaturated;
if (FluidSystem::isLiquid(phaseIdx)) {
Scalar lambdaFluid = FluidSystem::thermalConductivity(fs, paramCache, phaseIdx);
lambdaSaturated =
std::pow(lambdaGranite, (1 - poro))
+ std::pow(lambdaFluid, poro);
}
else
lambdaSaturated = std::pow(lambdaGranite, (1 - poro));
params.setFullySaturatedLambda(phaseIdx, lambdaSaturated);
}
Scalar lambdaVac = std::pow(lambdaGranite, (1 - poro));
params.setVacuumLambda(lambdaVac);
}
DimMatrix matrixK_;
DimMatrix fractureK_;
Scalar matrixPorosity_;
Scalar fracturePorosity_;
Scalar fractureWidth_;
MaterialLawParams fractureMaterialParams_;
MaterialLawParams matrixMaterialParams_;
ThermalConductionLawParams thermalConductionParams_;
SolidEnergyLawParams solidEnergyParams_;
Scalar temperature_;
Scalar eps_;
};
} // namespace Opm
#endif // EWOMS_FRACTURE_PROBLEM_HH

View File

@@ -0,0 +1,403 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::GroundWaterProblem
*/
#ifndef EWOMS_GROUND_WATER_PROBLEM_HH
#define EWOMS_GROUND_WATER_PROBLEM_HH
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <dune/common/version.hh>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <opm/material/components/SimpleH2O.hpp>
#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
#include <opm/material/fluidsystems/LiquidPhase.hpp>
#include <opm/models/common/multiphasebaseparameters.hh>
#include <opm/models/immiscible/immiscibleproperties.hh>
#include <opm/simulators/linalg/parallelistlbackend.hh>
#include <sstream>
#include <string>
namespace Opm {
template <class TypeTag>
class GroundWaterProblem;
}
namespace Opm::Properties {
namespace TTag {
struct GroundWaterBaseProblem {};
}
template<class TypeTag>
struct Fluid<TypeTag, TTag::GroundWaterBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::LiquidPhase<Scalar, Opm::SimpleH2O<Scalar> >;
};
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::GroundWaterBaseProblem> { using type = Dune::YaspGrid<2>; };
// struct Grid<TypeTag, TTag::GroundWaterBaseProblem> { using type = Dune::SGrid<2, 2>; };
template<class TypeTag>
struct Problem<TypeTag, TTag::GroundWaterBaseProblem>
{ using type = Opm::GroundWaterProblem<TypeTag>; };
// Use the conjugated gradient linear solver with the default preconditioner (i.e.,
// ILU-0) from dune-istl
template<class TypeTag>
struct LinearSolverSplice<TypeTag, TTag::GroundWaterBaseProblem> { using type = TTag::ParallelIstlLinearSolver; };
template<class TypeTag>
struct LinearSolverWrapper<TypeTag, TTag::GroundWaterBaseProblem>
{ using type = Opm::Linear::SolverWrapperConjugatedGradients<TypeTag>; };
} // namespace Opm::Properties
namespace Opm::Parameters {
template<class Scalar>
struct LensLowerLeftX { static constexpr Scalar value = 0.25; };
template<class Scalar>
struct LensLowerLeftY { static constexpr Scalar value = 0.25; };
template<class Scalar>
struct LensLowerLeftZ { static constexpr Scalar value = 0.25; };
template<class Scalar>
struct LensUpperRightX { static constexpr Scalar value = 0.75; };
template<class Scalar>
struct LensUpperRightY { static constexpr Scalar value = 0.75; };
template<class Scalar>
struct LensUpperRightZ { static constexpr Scalar value = 0.75; };
template<class Scalar>
struct Permeability { static constexpr Scalar value = 1e-10; };
template<class Scalar>
struct PermeabilityLens { static constexpr Scalar value = 1e-12; };
} // namespace Opm::Parameters
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief Test for the immisicible VCVF discretization with only a single phase
*
* This problem is inspired by groundwater flow. Don't expect it to be
* realistic, though: For two dimensions, the domain size is 1m times
* 1m. On the left and right of the domain, no-flow boundaries are
* used, while at the top and bottom free flow boundaries with a
* pressure of 2 bar and 1 bar are used. The center of the domain is
* occupied by a rectangular lens of lower permeability.
*/
template <class TypeTag>
class GroundWaterProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
// copy some indices for convenience
using Indices = GetPropType<TypeTag, Properties::Indices>;
enum {
numPhases = FluidSystem::numPhases,
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld,
// indices of the primary variables
pressure0Idx = Indices::pressure0Idx
};
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using Model = GetPropType<TypeTag, Properties::Model>;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
GroundWaterProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
eps_ = 1.0e-3;
lensLowerLeft_[0] = Parameters::Get<Parameters::LensLowerLeftX<Scalar>>();
if (dim > 1)
lensLowerLeft_[1] = Parameters::Get<Parameters::LensLowerLeftY<Scalar>>();
if (dim > 2)
lensLowerLeft_[2] = Parameters::Get<Parameters::LensLowerLeftY<Scalar>>();
lensUpperRight_[0] = Parameters::Get<Parameters::LensUpperRightX<Scalar>>();
if (dim > 1)
lensUpperRight_[1] = Parameters::Get<Parameters::LensUpperRightY<Scalar>>();
if (dim > 2)
lensUpperRight_[2] = Parameters::Get<Parameters::LensUpperRightY<Scalar>>();
intrinsicPerm_ = this->toDimMatrix_(Parameters::Get<Parameters::Permeability<Scalar>>());
intrinsicPermLens_ = this->toDimMatrix_(Parameters::Get<Parameters::PermeabilityLens<Scalar>>());
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::Register<Parameters::LensLowerLeftX<Scalar>>
("The x-coordinate of the lens' lower-left corner [m].");
Parameters::Register<Parameters::LensUpperRightX<Scalar>>
("The x-coordinate of the lens' upper-right corner [m].");
if (dimWorld > 1) {
Parameters::Register<Parameters::LensLowerLeftY<Scalar>>
("The y-coordinate of the lens' lower-left corner [m].");
Parameters::Register<Parameters::LensUpperRightY<Scalar>>
("The y-coordinate of the lens' upper-right corner [m].");
}
if (dimWorld > 2) {
Parameters::Register<Parameters::LensLowerLeftZ<Scalar>>
("The z-coordinate of the lens' lower-left corner [m].");
Parameters::Register<Parameters::LensUpperRightZ<Scalar>>
("The z-coordinate of the lens' upper-right corner [m].");
}
Parameters::Register<Parameters::Permeability<Scalar>>
("The intrinsic permeability [m^2] of the ambient material.");
Parameters::Register<Parameters::PermeabilityLens<Scalar>>
("The intrinsic permeability [m^2] of the lens.");
Parameters::SetDefault<Parameters::GridFile>("./data/groundwater_2d.dgf");
Parameters::SetDefault<Parameters::EndTime<Scalar>>(1.0);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(1.0);
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \name Problem parameters
*/
// \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << "groundwater_" << Model::name();
return oss.str();
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return 273.15 + 10; } // 10C
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return 0.4; }
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
if (isInLens_(context.pos(spaceIdx, timeIdx)))
return intrinsicPermLens_;
else
return intrinsicPerm_;
}
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& globalPos = context.pos(spaceIdx, timeIdx);
if (onLowerBoundary_(globalPos) || onUpperBoundary_(globalPos)) {
Scalar pressure;
Scalar T = temperature(context, spaceIdx, timeIdx);
if (onLowerBoundary_(globalPos))
pressure = 2e5;
else // on upper boundary
pressure = 1e5;
Opm::ImmiscibleFluidState<Scalar, FluidSystem,
/*storeEnthalpy=*/false> fs;
fs.setSaturation(/*phaseIdx=*/0, 1.0);
fs.setPressure(/*phaseIdx=*/0, pressure);
fs.setTemperature(T);
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
fs.setDensity(phaseIdx, FluidSystem::density(fs, paramCache, phaseIdx));
fs.setViscosity(phaseIdx, FluidSystem::viscosity(fs, paramCache, phaseIdx));
}
// impose an freeflow boundary condition
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
}
else {
// no flow boundary
values.setNoFlow();
}
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{
// const GlobalPosition& globalPos = context.pos(spaceIdx, timeIdx);
values[pressure0Idx] = 1.0e+5; // + 9.81*1.23*(20-globalPos[dim-1]);
}
/*!
* \copydoc FvBaseProblem::source
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool onLowerBoundary_(const GlobalPosition& pos) const
{ return pos[dim - 1] < eps_; }
bool onUpperBoundary_(const GlobalPosition& pos) const
{ return pos[dim - 1] > this->boundingBoxMax()[dim - 1] - eps_; }
bool isInLens_(const GlobalPosition& pos) const
{
return lensLowerLeft_[0] <= pos[0] && pos[0] <= lensUpperRight_[0]
&& lensLowerLeft_[1] <= pos[1] && pos[1] <= lensUpperRight_[1];
}
GlobalPosition lensLowerLeft_;
GlobalPosition lensUpperRight_;
DimMatrix intrinsicPerm_;
DimMatrix intrinsicPermLens_;
Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,476 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
* \copydoc Opm::InfiltrationProblem
*/
#ifndef EWOMS_INFILTRATION_PROBLEM_HH
#define EWOMS_INFILTRATION_PROBLEM_HH
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <dune/common/version.hh>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <opm/material/common/Valgrind.hpp>
#include <opm/material/constraintsolvers/ComputeFromReferencePhase.hpp>
#include <opm/material/fluidmatrixinteractions/ThreePhaseParkerVanGenuchten.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
#include <opm/material/fluidsystems/H2OAirMesityleneFluidSystem.hpp>
#include <opm/models/common/multiphasebaseparameters.hh>
#include <opm/models/discretization/common/fvbasefdlocallinearizer.hh>
#include <opm/models/pvs/pvsproperties.hh>
#include <sstream>
#include <string>
namespace Opm {
template <class TypeTag>
class InfiltrationProblem;
}
namespace Opm::Properties {
namespace TTag {
struct InfiltrationBaseProblem {};
}
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::InfiltrationBaseProblem> { using type = Dune::YaspGrid<2>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::InfiltrationBaseProblem> { using type = Opm::InfiltrationProblem<TypeTag>; };
// Set the fluid system
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::InfiltrationBaseProblem>
{ using type = Opm::H2OAirMesityleneFluidSystem<GetPropType<TypeTag, Properties::Scalar>>; };
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::InfiltrationBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Traits= Opm::ThreePhaseMaterialTraits<
Scalar,
/*wettingPhaseIdx=*/FluidSystem::waterPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::naplPhaseIdx,
/*gasPhaseIdx=*/FluidSystem::gasPhaseIdx>;
public:
using type = Opm::ThreePhaseParkerVanGenuchten<Traits>;
};
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
* \brief Isothermal NAPL infiltration problem where LNAPL
* contaminates the unsaturated and the saturated groundwater
* zone.
*
* The 2D domain of this test problem is 500 m long and 10 m deep,
* where the lower part represents a slightly inclined groundwater
* table, and the upper part is the vadose zone. A LNAPL (Non-Aqueous
* Phase Liquid which is lighter than water) infiltrates (modelled
* with a Neumann boundary condition) into the vadose zone. Upon
* reaching the water table, it spreads (since lighter than water) and
* migrates on top of the water table in the direction of the slope.
* On its way through the vadose zone, it leaves a trace of residually
* trapped immobile NAPL, which can in the following dissolve and
* evaporate slowly, and eventually be transported by advection and
* diffusion.
*
* Left and right boundaries are constant hydraulic head boundaries
* (Dirichlet), Top and bottom are Neumann boundaries, all no-flow
* except for the small infiltration zone in the upper left part.
*/
template <class TypeTag>
class InfiltrationProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Model = GetPropType<TypeTag, Properties::Model>;
// copy some indices for convenience
using Indices = GetPropType<TypeTag, Properties::Indices>;
enum {
// equation indices
conti0EqIdx = Indices::conti0EqIdx,
// number of phases/components
numPhases = FluidSystem::numPhases,
// component indices
NAPLIdx = FluidSystem::NAPLIdx,
H2OIdx = FluidSystem::H2OIdx,
airIdx = FluidSystem::airIdx,
// phase indices
waterPhaseIdx = FluidSystem::waterPhaseIdx,
gasPhaseIdx = FluidSystem::gasPhaseIdx,
naplPhaseIdx = FluidSystem::naplPhaseIdx,
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
InfiltrationProblem(Simulator& simulator)
: ParentType(simulator)
, eps_(1e-6)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
temperature_ = 273.15 + 10.0; // -> 10 degrees Celsius
FluidSystem::init(/*tempMin=*/temperature_ - 1,
/*tempMax=*/temperature_ + 1,
/*nTemp=*/3,
/*pressMin=*/0.8 * 1e5,
/*pressMax=*/3 * 1e5,
/*nPress=*/200);
// intrinsic permeabilities
fineK_ = this->toDimMatrix_(1e-11);
coarseK_ = this->toDimMatrix_(1e-11);
// porosities
porosity_ = 0.40;
// residual saturations
materialParams_.setSwr(0.12);
materialParams_.setSwrx(0.12);
materialParams_.setSnr(0.07);
materialParams_.setSgr(0.03);
// parameters for the three-phase van Genuchten law
materialParams_.setVgAlpha(0.0005);
materialParams_.setVgN(4.);
materialParams_.setkrRegardsSnr(false);
materialParams_.finalize();
materialParams_.checkDefined();
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::GridFile>("./data/infiltration_50x3.dgf");
Parameters::SetDefault<Parameters::NumericDifferenceMethod>(1);
Parameters::SetDefault<Parameters::EndTime<Scalar>>(6e3);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(60.0);
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \name Problem parameters
*/
//! \{
/*!
* \copydoc FvBaseProblem::shouldWriteRestartFile
*
* This problem writes a restart file after every time step.
*/
bool shouldWriteRestartFile() const
{ return true; }
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << "infiltration_" << Model::name();
return oss.str();
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return temperature_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix&
intrinsicPermeability(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineK_;
return coarseK_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return porosity_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams&
materialLawParams(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return materialParams_; }
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const auto& pos = context.pos(spaceIdx, timeIdx);
if (onLeftBoundary_(pos) || onRightBoundary_(pos)) {
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
}
else if (onInlet_(pos)) {
RateVector molarRate(0.0);
molarRate[conti0EqIdx + NAPLIdx] = -0.001;
values.setMolarRate(molarRate);
Opm::Valgrind::CheckDefined(values);
}
else
values.setNoFlow();
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
const auto& matParams = materialLawParams(context, spaceIdx, timeIdx);
values.assignMassConservative(fs, matParams, /*inEquilibrium=*/true);
Opm::Valgrind::CheckDefined(values);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition& pos) const
{ return pos[1] < eps_; }
bool onUpperBoundary_(const GlobalPosition& pos) const
{ return pos[1] > this->boundingBoxMax()[1] - eps_; }
bool onInlet_(const GlobalPosition& pos) const
{ return onUpperBoundary_(pos) && 50 < pos[0] && pos[0] < 75; }
template <class FluidState, class Context>
void initialFluidState_(FluidState& fs, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition pos = context.pos(spaceIdx, timeIdx);
Scalar y = pos[1];
Scalar x = pos[0];
Scalar densityW = 1000.0;
Scalar pc = 9.81 * densityW * (y - (5 - 5e-4 * x));
if (pc < 0.0)
pc = 0.0;
// set pressures
const auto& matParams = materialLawParams(context, spaceIdx, timeIdx);
Scalar Sw = matParams.Swr();
Scalar Swr = matParams.Swr();
Scalar Sgr = matParams.Sgr();
if (Sw < Swr)
Sw = Swr;
if (Sw > 1 - Sgr)
Sw = 1 - Sgr;
Scalar Sg = 1 - Sw;
Opm::Valgrind::CheckDefined(Sw);
Opm::Valgrind::CheckDefined(Sg);
fs.setSaturation(waterPhaseIdx, Sw);
fs.setSaturation(gasPhaseIdx, Sg);
fs.setSaturation(naplPhaseIdx, 0);
// set temperature of all phases
fs.setTemperature(temperature_);
// compute pressures
Scalar pcAll[numPhases];
Scalar pg = 1e5;
if (onLeftBoundary_(pos))
pg += 10e3;
MaterialLaw::capillaryPressures(pcAll, matParams, fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
fs.setPressure(phaseIdx, pg + (pcAll[phaseIdx] - pcAll[gasPhaseIdx]));
// set composition of gas phase
fs.setMoleFraction(gasPhaseIdx, H2OIdx, 1e-6);
fs.setMoleFraction(gasPhaseIdx, airIdx,
1 - fs.moleFraction(gasPhaseIdx, H2OIdx));
fs.setMoleFraction(gasPhaseIdx, NAPLIdx, 0);
using CFRP = Opm::ComputeFromReferencePhase<Scalar, FluidSystem>;
typename FluidSystem::template ParameterCache<Scalar> paramCache;
CFRP::solve(fs, paramCache, gasPhaseIdx,
/*setViscosity=*/true,
/*setEnthalpy=*/false);
fs.setMoleFraction(waterPhaseIdx, H2OIdx,
1 - fs.moleFraction(waterPhaseIdx, H2OIdx));
}
bool isFineMaterial_(const GlobalPosition& pos) const
{ return 70. <= pos[0] && pos[0] <= 85. && 7.0 <= pos[1] && pos[1] <= 7.50; }
DimMatrix fineK_;
DimMatrix coarseK_;
Scalar porosity_;
MaterialLawParams materialParams_;
Scalar temperature_;
Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,643 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::LensProblem
*/
#ifndef EWOMS_LENS_PROBLEM_HH
#define EWOMS_LENS_PROBLEM_HH
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <dune/common/version.hh>
#include <opm/material/components/Dnapl.hpp>
#include <opm/material/components/SimpleH2O.hpp>
#include <opm/material/fluidmatrixinteractions/RegularizedVanGenuchten.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
#include <opm/material/fluidsystems/TwoPhaseImmiscibleFluidSystem.hpp>
#include <opm/models/common/multiphasebaseparameters.hh>
#include <opm/models/common/transfluxmodule.hh>
#include <opm/models/discretization/common/fvbaseadlocallinearizer.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include <opm/models/immiscible/immiscibleproperties.hh>
#include <opm/models/io/structuredgridvanguard.hh>
#include <opm/models/io/vtkmultiphasemodule.hh>
#include <iostream>
#include <sstream>
#include <string>
namespace Opm {
template <class TypeTag>
class LensProblem;
}
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct LensBaseProblem { using InheritsFrom = std::tuple<StructuredGridVanguard>; };
} // end namespace TTag
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::LensBaseProblem> { using type = Opm::LensProblem<TypeTag>; };
// Use Dune-grid's YaspGrid
template<class TypeTag>
struct Grid<TypeTag, TTag::LensBaseProblem> { using type = Dune::YaspGrid<2>; };
// Set the wetting phase
template<class TypeTag>
struct WettingPhase<TypeTag, TTag::LensBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::LiquidPhase<Scalar, Opm::SimpleH2O<Scalar> >;
};
// Set the non-wetting phase
template<class TypeTag>
struct NonwettingPhase<TypeTag, TTag::LensBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::LiquidPhase<Scalar, Opm::DNAPL<Scalar> >;
};
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::LensBaseProblem>
{
private:
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx };
enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx };
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::wettingPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::nonWettingPhaseIdx>;
// define the material law which is parameterized by effective
// saturations
using EffectiveLaw = Opm::RegularizedVanGenuchten<Traits>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::EffToAbsLaw<EffectiveLaw>;
};
} // namespace Opm::Properties
namespace Opm::Parameters {
// define the properties specific for the lens problem
template<class Scalar>
struct LensLowerLeftX { static constexpr Scalar value = 1.0; };
template<class Scalar>
struct LensLowerLeftY { static constexpr Scalar value = 2.0; };
template<class Scalar>
struct LensLowerLeftZ { static constexpr Scalar value = 0.0; };
template<class Scalar>
struct LensUpperRightX { static constexpr Scalar value = 4.0; };
template<class Scalar>
struct LensUpperRightY { static constexpr Scalar value = 3.0; };
template<class Scalar>
struct LensUpperRightZ { static constexpr Scalar value = 1.0; };
} // namespace Opm::Parameters
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief Soil contamination problem where DNAPL infiltrates a fully
* water saturated medium.
*
* The domain is sized 6m times 4m and features a rectangular lens
* with low permeablility which spans from (1m, 2m) to (4m, 3m)
* and is surrounded by a medium with higher permability. Note that
* this problem is discretized using only two dimensions, so from the
* point of view of the model, the depth of the domain is implicitly
* assumed to be 1 m everywhere.
*
* On the top and the bottom of the domain no-flow boundary conditions
* are used, while free-flow conditions apply on the left and right
* boundaries; DNAPL is injected at the top boundary from 3m to 4m at
* a rate of 0.04 kg/(s m^2).
*
* At the boundary on the left, a free-flow condition using the
* hydrostatic pressure scaled by a factor of 1.125 is imposed, while
* on the right, it is just the hydrostatic pressure. The DNAPL
* saturation on both sides is zero.
*/
template <class TypeTag>
class LensProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using Indices = GetPropType<TypeTag, Properties::Indices>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using WettingPhase = GetPropType<TypeTag, Properties::WettingPhase>;
using NonwettingPhase = GetPropType<TypeTag, Properties::NonwettingPhase>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Model = GetPropType<TypeTag, Properties::Model>;
enum {
// number of phases
numPhases = FluidSystem::numPhases,
// phase indices
wettingPhaseIdx = FluidSystem::wettingPhaseIdx,
nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx,
// equation indices
contiNEqIdx = Indices::conti0EqIdx + nonWettingPhaseIdx,
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
LensProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
eps_ = 3e-6;
FluidSystem::init();
temperature_ = 273.15 + 20; // -> 20°C
lensLowerLeft_[0] = Parameters::Get<Parameters::LensLowerLeftX<Scalar>>();
lensLowerLeft_[1] = Parameters::Get<Parameters::LensLowerLeftY<Scalar>>();
lensUpperRight_[0] = Parameters::Get<Parameters::LensUpperRightX<Scalar>>();
lensUpperRight_[1] = Parameters::Get<Parameters::LensUpperRightY<Scalar>>();
if constexpr (dim == 3) {
lensLowerLeft_[2] = Parameters::Get<Parameters::LensLowerLeftZ<Scalar>>();
lensUpperRight_[2] = Parameters::Get<Parameters::LensUpperRightZ<Scalar>>();
}
// residual saturations
lensMaterialParams_.setResidualSaturation(wettingPhaseIdx, 0.18);
lensMaterialParams_.setResidualSaturation(nonWettingPhaseIdx, 0.0);
outerMaterialParams_.setResidualSaturation(wettingPhaseIdx, 0.05);
outerMaterialParams_.setResidualSaturation(nonWettingPhaseIdx, 0.0);
// parameters for the Van Genuchten law: alpha and n
lensMaterialParams_.setVgAlpha(0.00045);
lensMaterialParams_.setVgN(7.3);
outerMaterialParams_.setVgAlpha(0.0037);
outerMaterialParams_.setVgN(4.7);
lensMaterialParams_.finalize();
outerMaterialParams_.finalize();
lensK_ = this->toDimMatrix_(9.05e-12);
outerK_ = this->toDimMatrix_(4.6e-10);
if (dimWorld == 3) {
this->gravity_ = 0;
this->gravity_[1] = -9.81;
}
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::Register<Parameters::LensLowerLeftX<Scalar>>
("The x-coordinate of the lens' lower-left corner [m].");
Parameters::Register<Parameters::LensLowerLeftY<Scalar>>
("The y-coordinate of the lens' lower-left corner [m].");
Parameters::Register<Parameters::LensUpperRightX<Scalar>>
("The x-coordinate of the lens' upper-right corner [m].");
Parameters::Register<Parameters::LensUpperRightY<Scalar>>
("The y-coordinate of the lens' upper-right corner [m].");
if constexpr (dim == 3) {
Parameters::Register<Parameters::LensLowerLeftZ<Scalar>>
("The z-coordinate of the lens' lower-left corner [m].");
Parameters::Register<Parameters::LensUpperRightZ<Scalar>>
("The z-coordinate of the lens' upper-right corner [m].");
}
Parameters::SetDefault<Parameters::CellsX>(48);
Parameters::SetDefault<Parameters::CellsY>(32);
Parameters::SetDefault<Parameters::DomainSizeX<Scalar>>(6.0);
Parameters::SetDefault<Parameters::DomainSizeY<Scalar>>(4.0);
if constexpr (dim == 3) {
Parameters::SetDefault<Parameters::CellsZ>(16);
Parameters::SetDefault<Parameters::DomainSizeZ<Scalar>>(1.0);
}
// Use forward differences
using LLS = GetPropType<TypeTag, Properties::LocalLinearizerSplice>;
constexpr bool useFD = std::is_same_v<LLS, Properties::TTag::FiniteDifferenceLocalLinearizer>;
if constexpr (useFD) {
Parameters::SetDefault<Parameters::NumericDifferenceMethod>(+1);
}
Parameters::SetDefault<Parameters::EndTime<Scalar>>(30e3);
Parameters::SetDefault<Parameters::EnableIntensiveQuantityCache>(true);
Parameters::SetDefault<Parameters::EnableStorageCache>(true);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(250.0);
Parameters::SetDefault<Parameters::VtkWriteIntrinsicPermeabilities>(true);
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \copydoc FvBaseProblem::briefDescription
*/
static std::string briefDescription()
{
std::string thermal = "isothermal";
constexpr bool enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>();
if constexpr (enableEnergy)
thermal = "non-isothermal";
std::string deriv = "finite difference";
using LLS = GetPropType<TypeTag, Properties::LocalLinearizerSplice>;
constexpr bool useAutoDiff = std::is_same_v<LLS, Properties::TTag::AutoDiffLocalLinearizer>;
if constexpr (useAutoDiff) {
deriv = "automatic differentiation";
}
std::string disc = "vertex centered finite volume";
using D = GetPropType<TypeTag, Properties::Discretization>;
constexpr bool useEcfv = std::is_same<D, Opm::EcfvDiscretization<TypeTag>>::value;
if constexpr (useEcfv)
disc = "element centered finite volume";
return std::string("")+
"Ground remediation problem where a dense oil infiltrates "+
"an aquifer with an embedded low-permability lens. " +
"This is the binary for the "+thermal+" variant using "+deriv+
"and the "+disc+" discretization";
}
/*!
* \name Soil parameters
*/
//! \{
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& context, unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& globalPos = context.pos(spaceIdx, timeIdx);
if (isInLens_(globalPos))
return lensK_;
return outerK_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return 0.4; }
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams(const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& globalPos = context.pos(spaceIdx, timeIdx);
if (isInLens_(globalPos))
return lensMaterialParams_;
return outerMaterialParams_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return temperature_; }
//! \}
/*!
* \name Auxiliary methods
*/
//! \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
using LLS = GetPropType<TypeTag, Properties::LocalLinearizerSplice>;
constexpr bool useAutoDiff = std::is_same_v<LLS, Properties::TTag::AutoDiffLocalLinearizer>;
using FM = GetPropType<TypeTag, Properties::FluxModule>;
constexpr bool useTrans = std::is_same_v<FM, Opm::TransFluxModule<TypeTag>>;
std::ostringstream oss;
oss << "lens_" << Model::name()
<< "_" << Model::discretizationName()
<< "_" << (useAutoDiff?"ad":"fd");
if (useTrans)
oss << "_trans";
return oss.str();
}
/*!
* \copydoc FvBaseProblem::beginTimeStep
*/
void beginTimeStep()
{ }
/*!
* \copydoc FvBaseProblem::beginIteration
*/
void beginIteration()
{ }
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
//this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (onLeftBoundary_(pos) || onRightBoundary_(pos)) {
// free flow boundary. we assume incompressible fluids
Scalar densityW = WettingPhase::density(temperature_, /*pressure=*/Scalar(1e5));
Scalar densityN = NonwettingPhase::density(temperature_, /*pressure=*/Scalar(1e5));
Scalar T = temperature(context, spaceIdx, timeIdx);
Scalar pw, Sw;
// set wetting phase pressure and saturation
if (onLeftBoundary_(pos)) {
Scalar height = this->boundingBoxMax()[1] - this->boundingBoxMin()[1];
Scalar depth = this->boundingBoxMax()[1] - pos[1];
Scalar alpha = (1 + 1.5 / height);
// hydrostatic pressure scaled by alpha
pw = 1e5 - alpha * densityW * this->gravity()[1] * depth;
Sw = 1.0;
}
else {
Scalar depth = this->boundingBoxMax()[1] - pos[1];
// hydrostatic pressure
pw = 1e5 - densityW * this->gravity()[1] * depth;
Sw = 1.0;
}
// specify a full fluid state using pw and Sw
const MaterialLawParams& matParams = this->materialLawParams(context, spaceIdx, timeIdx);
Opm::ImmiscibleFluidState<Scalar, FluidSystem,
/*storeEnthalpy=*/false> fs;
fs.setSaturation(wettingPhaseIdx, Sw);
fs.setSaturation(nonWettingPhaseIdx, 1 - Sw);
fs.setTemperature(T);
Scalar pC[numPhases];
MaterialLaw::capillaryPressures(pC, matParams, fs);
fs.setPressure(wettingPhaseIdx, pw);
fs.setPressure(nonWettingPhaseIdx, pw + pC[nonWettingPhaseIdx] - pC[wettingPhaseIdx]);
fs.setDensity(wettingPhaseIdx, densityW);
fs.setDensity(nonWettingPhaseIdx, densityN);
fs.setViscosity(wettingPhaseIdx, WettingPhase::viscosity(temperature_, fs.pressure(wettingPhaseIdx)));
fs.setViscosity(nonWettingPhaseIdx, NonwettingPhase::viscosity(temperature_, fs.pressure(nonWettingPhaseIdx)));
// impose an freeflow boundary condition
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
}
else if (onInlet_(pos)) {
RateVector massRate(0.0);
massRate = 0.0;
massRate[contiNEqIdx] = -0.04; // kg / (m^2 * s)
// impose a forced flow boundary
values.setMassRate(massRate);
}
else {
// no flow boundary
values.setNoFlow();
}
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
Scalar depth = this->boundingBoxMax()[1] - pos[1];
Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
fs.setPressure(wettingPhaseIdx, /*pressure=*/1e5);
Scalar Sw = 1.0;
fs.setSaturation(wettingPhaseIdx, Sw);
fs.setSaturation(nonWettingPhaseIdx, 1 - Sw);
fs.setTemperature(temperature_);
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updatePhase(fs, wettingPhaseIdx);
Scalar densityW = FluidSystem::density(fs, paramCache, wettingPhaseIdx);
// hydrostatic pressure (assuming incompressibility)
Scalar pw = 1e5 - densityW * this->gravity()[1] * depth;
// calculate the capillary pressure
const MaterialLawParams& matParams = this->materialLawParams(context, spaceIdx, timeIdx);
Scalar pC[numPhases];
MaterialLaw::capillaryPressures(pC, matParams, fs);
// make a full fluid state
fs.setPressure(wettingPhaseIdx, pw);
fs.setPressure(nonWettingPhaseIdx, pw + (pC[wettingPhaseIdx] - pC[nonWettingPhaseIdx]));
// assign the primary variables
values.assignNaive(fs);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool isInLens_(const GlobalPosition& pos) const
{
for (unsigned i = 0; i < dim; ++i) {
if (pos[i] < lensLowerLeft_[i] - eps_ || pos[i] > lensUpperRight_[i]
+ eps_)
return false;
}
return true;
}
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < this->boundingBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition& pos) const
{ return pos[1] < this->boundingBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition& pos) const
{ return pos[1] > this->boundingBoxMax()[1] - eps_; }
bool onInlet_(const GlobalPosition& pos) const
{
Scalar width = this->boundingBoxMax()[0] - this->boundingBoxMin()[0];
Scalar lambda = (this->boundingBoxMax()[0] - pos[0]) / width;
return onUpperBoundary_(pos) && 0.5 < lambda && lambda < 2.0 / 3.0;
}
GlobalPosition lensLowerLeft_;
GlobalPosition lensUpperRight_;
DimMatrix lensK_;
DimMatrix outerK_;
MaterialLawParams lensMaterialParams_;
MaterialLawParams outerMaterialParams_;
Scalar temperature_;
Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,583 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::ObstacleProblem
*/
#ifndef EWOMS_OBSTACLE_PROBLEM_HH
#define EWOMS_OBSTACLE_PROBLEM_HH
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <dune/common/version.hh>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <opm/material/constraintsolvers/ComputeFromReferencePhase.hpp>
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/fluidmatrixinteractions/RegularizedBrooksCorey.hpp>
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
#include <opm/material/fluidsystems/H2ON2FluidSystem.hpp>
#include <opm/material/thermal/ConstantSolidHeatCapLaw.hpp>
#include <opm/material/thermal/SomertonThermalConductionLaw.hpp>
#include <opm/models/common/multiphasebaseparameters.hh>
#include <opm/models/ncp/ncpproperties.hh>
#include <iostream>
#include <sstream>
#include <string>
namespace Opm {
template <class TypeTag>
class ObstacleProblem;
}
namespace Opm::Properties {
namespace TTag {
struct ObstacleBaseProblem {};
}
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::ObstacleBaseProblem> { using type = Dune::YaspGrid<2>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::ObstacleBaseProblem> { using type = Opm::ObstacleProblem<TypeTag>; };
// Set fluid configuration
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::ObstacleBaseProblem>
{ using type = Opm::H2ON2FluidSystem<GetPropType<TypeTag, Properties::Scalar>>; };
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::ObstacleBaseProblem>
{
private:
// define the material law
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using MaterialTraits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::liquidPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::gasPhaseIdx>;
using EffMaterialLaw = Opm::LinearMaterial<MaterialTraits>;
public:
using type = Opm::EffToAbsLaw<EffMaterialLaw>;
};
// Set the thermal conduction law
template<class TypeTag>
struct ThermalConductionLaw<TypeTag, TTag::ObstacleBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::SomertonThermalConductionLaw<FluidSystem, Scalar>;
};
// set the energy storage law for the solid phase
template<class TypeTag>
struct SolidEnergyLaw<TypeTag, TTag::ObstacleBaseProblem>
{ using type = Opm::ConstantSolidHeatCapLaw<GetPropType<TypeTag, Properties::Scalar>>; };
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief Problem where liquid water is first stopped by a
* low-permeability lens and then seeps though it.
*
* Liquid water is injected by using of a free-flow condition on the
* lower right of the domain. This water level then raises until
* hydrostatic pressure is reached. On the left of the domain, a
* rectangular obstacle with \f$10^3\f$ lower permeability than the
* rest of the domain first stops the for a while until it seeps
* through it.
*
* The domain is sized 60m times 40m and consists of two media, a
* moderately permeable soil (\f$ K_0=10e-12 m^2\f$) and an obstacle
* at \f$[10; 20]m \times [0; 35]m \f$ with a lower permeablility of
* \f$ K_1=K_0/1000\f$.
*
* Initially the whole domain is filled by nitrogen, the temperature
* is \f$20^\circ C\f$ for the whole domain. The gas pressure is
* initially 1 bar, at the inlet of the liquid water on the right side
* it is 2 bar.
*
* The boundary is no-flow except on the lower 10 meters of the left
* and the right boundary where a free flow condition is assumed.
*/
template <class TypeTag>
class ObstacleProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using ThermalConductionLawParams = GetPropType<TypeTag, Properties::ThermalConductionLawParams>;
using SolidEnergyLawParams = GetPropType<TypeTag, Properties::SolidEnergyLawParams>;
enum {
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld,
numPhases = getPropValue<TypeTag, Properties::NumPhases>(),
gasPhaseIdx = FluidSystem::gasPhaseIdx,
liquidPhaseIdx = FluidSystem::liquidPhaseIdx,
H2OIdx = FluidSystem::H2OIdx,
N2Idx = FluidSystem::N2Idx
};
using GlobalPosition = Dune::FieldVector<typename GridView::ctype, dimWorld>;
using PhaseVector = Dune::FieldVector<Scalar, numPhases>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Model = GetPropType<TypeTag, Properties::Model>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
ObstacleProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
eps_ = 1e-6;
temperature_ = 273.15 + 25; // -> 25°C
// initialize the tables of the fluid system
Scalar Tmin = temperature_ - 1.0;
Scalar Tmax = temperature_ + 1.0;
unsigned nT = 3;
Scalar pmin = 1.0e5 * 0.75;
Scalar pmax = 2.0e5 * 1.25;
unsigned np = 1000;
FluidSystem::init(Tmin, Tmax, nT, pmin, pmax, np);
// intrinsic permeabilities
coarseK_ = this->toDimMatrix_(1e-12);
fineK_ = this->toDimMatrix_(1e-15);
// the porosity
finePorosity_ = 0.3;
coarsePorosity_ = 0.3;
// residual saturations
fineMaterialParams_.setResidualSaturation(liquidPhaseIdx, 0.0);
fineMaterialParams_.setResidualSaturation(gasPhaseIdx, 0.0);
coarseMaterialParams_.setResidualSaturation(liquidPhaseIdx, 0.0);
coarseMaterialParams_.setResidualSaturation(gasPhaseIdx, 0.0);
// parameters for the linear law, i.e. minimum and maximum
// pressures
fineMaterialParams_.setPcMinSat(liquidPhaseIdx, 0.0);
fineMaterialParams_.setPcMaxSat(liquidPhaseIdx, 0.0);
coarseMaterialParams_.setPcMinSat(liquidPhaseIdx, 0.0);
coarseMaterialParams_.setPcMaxSat(liquidPhaseIdx, 0.0);
/*
// entry pressures for Brooks-Corey
fineMaterialParams_.setEntryPressure(5e3);
coarseMaterialParams_.setEntryPressure(1e3);
// Brooks-Corey shape parameters
fineMaterialParams_.setLambda(2);
coarseMaterialParams_.setLambda(2);
*/
fineMaterialParams_.finalize();
coarseMaterialParams_.finalize();
// parameters for the somerton law of thermal conduction
computeThermalCondParams_(fineThermalCondParams_, finePorosity_);
computeThermalCondParams_(coarseThermalCondParams_, coarsePorosity_);
// assume constant volumetric heat capacity and granite
solidEnergyLawParams_.setSolidHeatCapacity(790.0 // specific heat capacity of granite [J / (kg K)]
* 2700.0); // density of granite [kg/m^3]
solidEnergyLawParams_.finalize();
initFluidStates_();
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::GridFile>("./data/obstacle_24x16.dgf");
Parameters::SetDefault<Parameters::EndTime<Scalar>>(1e4);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(250);
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
this->model().checkConservativeness();
// Calculate storage terms of the individual phases
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
PrimaryVariables phaseStorage;
this->model().globalPhaseStorage(phaseStorage, phaseIdx);
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage in " << FluidSystem::phaseName(phaseIdx)
<< "Phase: [" << phaseStorage << "]"
<< "\n" << std::flush;
}
}
// Calculate total storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage total: [" << storage << "]"
<< "\n" << std::flush;
}
#endif // NDEBUG
}
/*!
* \name Problem parameters
*/
//! \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << "obstacle"
<< "_" << Model::name();
return oss.str();
}
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*
* This problem simply assumes a constant temperature.
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return temperature_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix&
intrinsicPermeability(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
if (isFineMaterial_(context.pos(spaceIdx, timeIdx)))
return fineK_;
return coarseK_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return finePorosity_;
else
return coarsePorosity_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams&
materialLawParams(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineMaterialParams_;
else
return coarseMaterialParams_;
}
/*!
* \brief Return the parameters for the energy storage law of the rock
*
* In this case, we assume the rock-matrix to be granite.
*/
template <class Context>
const SolidEnergyLawParams&
solidEnergyLawParams(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return solidEnergyLawParams_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::thermalConductionParams
*/
template <class Context>
const ThermalConductionLawParams &
thermalConductionParams(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineThermalCondParams_;
return coarseThermalCondParams_;
}
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const auto& pos = context.pos(spaceIdx, timeIdx);
if (onInlet_(pos))
values.setFreeFlow(context, spaceIdx, timeIdx, inletFluidState_);
else if (onOutlet_(pos))
values.setFreeFlow(context, spaceIdx, timeIdx, outletFluidState_);
else
values.setNoFlow();
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const auto& matParams = materialLawParams(context, spaceIdx, timeIdx);
values.assignMassConservative(outletFluidState_, matParams);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = 0.0; }
//! \}
private:
/*!
* \brief Returns whether a given global position is in the
* fine-permeability region or not.
*/
bool isFineMaterial_(const GlobalPosition& pos) const
{ return 10 <= pos[0] && pos[0] <= 20 && 0 <= pos[1] && pos[1] <= 35; }
bool onInlet_(const GlobalPosition& globalPos) const
{
Scalar x = globalPos[0];
Scalar y = globalPos[1];
return x >= 60 - eps_ && y <= 10;
}
bool onOutlet_(const GlobalPosition& globalPos) const
{
Scalar x = globalPos[0];
Scalar y = globalPos[1];
return x < eps_ && y <= 10;
}
void initFluidStates_()
{
initFluidState_(inletFluidState_, coarseMaterialParams_,
/*isInlet=*/true);
initFluidState_(outletFluidState_, coarseMaterialParams_,
/*isInlet=*/false);
}
template <class FluidState>
void initFluidState_(FluidState& fs, const MaterialLawParams& matParams, bool isInlet)
{
unsigned refPhaseIdx;
unsigned otherPhaseIdx;
// set the fluid temperatures
fs.setTemperature(temperature_);
if (isInlet) {
// only liquid on inlet
refPhaseIdx = liquidPhaseIdx;
otherPhaseIdx = gasPhaseIdx;
// set liquid saturation
fs.setSaturation(liquidPhaseIdx, 1.0);
// set pressure of the liquid phase
fs.setPressure(liquidPhaseIdx, 2e5);
// set the liquid composition to pure water
fs.setMoleFraction(liquidPhaseIdx, N2Idx, 0.0);
fs.setMoleFraction(liquidPhaseIdx, H2OIdx, 1.0);
}
else {
// elsewhere, only gas
refPhaseIdx = gasPhaseIdx;
otherPhaseIdx = liquidPhaseIdx;
// set gas saturation
fs.setSaturation(gasPhaseIdx, 1.0);
// set pressure of the gas phase
fs.setPressure(gasPhaseIdx, 1e5);
// set the gas composition to 99% nitrogen and 1% steam
fs.setMoleFraction(gasPhaseIdx, N2Idx, 0.99);
fs.setMoleFraction(gasPhaseIdx, H2OIdx, 0.01);
}
// set the other saturation
fs.setSaturation(otherPhaseIdx, 1.0 - fs.saturation(refPhaseIdx));
// calulate the capillary pressure
PhaseVector pC;
MaterialLaw::capillaryPressures(pC, matParams, fs);
fs.setPressure(otherPhaseIdx, fs.pressure(refPhaseIdx)
+ (pC[otherPhaseIdx] - pC[refPhaseIdx]));
// make the fluid state consistent with local thermodynamic
// equilibrium
using ComputeFromReferencePhase = Opm::ComputeFromReferencePhase<Scalar, FluidSystem>;
typename FluidSystem::template ParameterCache<Scalar> paramCache;
ComputeFromReferencePhase::solve(fs, paramCache, refPhaseIdx,
/*setViscosity=*/true,
/*setEnthalpy=*/false);
}
void computeThermalCondParams_(ThermalConductionLawParams& params, Scalar poro)
{
Scalar lambdaWater = 0.6;
Scalar lambdaGranite = 2.8;
Scalar lambdaWet = std::pow(lambdaGranite, (1 - poro))
* std::pow(lambdaWater, poro);
Scalar lambdaDry = std::pow(lambdaGranite, (1 - poro));
params.setFullySaturatedLambda(gasPhaseIdx, lambdaDry);
params.setFullySaturatedLambda(liquidPhaseIdx, lambdaWet);
params.setVacuumLambda(lambdaDry);
}
DimMatrix coarseK_;
DimMatrix fineK_;
Scalar coarsePorosity_;
Scalar finePorosity_;
MaterialLawParams fineMaterialParams_;
MaterialLawParams coarseMaterialParams_;
ThermalConductionLawParams fineThermalCondParams_;
ThermalConductionLawParams coarseThermalCondParams_;
SolidEnergyLawParams solidEnergyLawParams_;
Opm::CompositionalFluidState<Scalar, FluidSystem> inletFluidState_;
Opm::CompositionalFluidState<Scalar, FluidSystem> outletFluidState_;
Scalar temperature_;
Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,379 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
* \copydoc Opm::OutflowProblem
*/
#ifndef EWOMS_OUTFLOW_PROBLEM_HH
#define EWOMS_OUTFLOW_PROBLEM_HH
#include <opm/models/pvs/pvsproperties.hh>
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
#include <opm/material/fluidsystems/H2ON2LiquidPhaseFluidSystem.hpp>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
namespace Opm {
template <class TypeTag>
class OutflowProblem;
}
namespace Opm::Properties {
namespace TTag {
struct OutflowBaseProblem {};
} // namespace TTag
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::OutflowBaseProblem> { using type = Dune::YaspGrid<2>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::OutflowBaseProblem> { using type = Opm::OutflowProblem<TypeTag>; };
// Set fluid system
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::OutflowBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
// Two-component single phase fluid system
using type = Opm::H2ON2LiquidPhaseFluidSystem<Scalar>;
};
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief Problem where dissolved nitrogen is transported with the water
* phase from the left side to the right.
*
* The model domain is 1m times 1m and exhibits homogeneous soil
* properties (\f$ \mathrm{K=10e-10, \Phi=0.4}\f$). Initially the
* domain is fully saturated by water without any nitrogen dissolved.
*
* At the left side, a free-flow condition defines a nitrogen mole
* fraction of 0.02%. The water phase flows from the left side to the
* right due to the imposed pressure gradient of \f$1e5\,Pa/m\f$. The
* nitrogen is transported with the water flow and leaves the domain
* at the right boundary where an outflow boundary condition is
* used.
*/
template <class TypeTag>
class OutflowProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
// copy some indices for convenience
enum {
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld,
numPhases = FluidSystem::numPhases,
// component indices
H2OIdx = FluidSystem::H2OIdx,
N2Idx = FluidSystem::N2Idx
};
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
OutflowProblem(Simulator& simulator)
: ParentType(simulator)
, eps_(1e-6)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
temperature_ = 273.15 + 20;
FluidSystem::init(/*minT=*/temperature_ - 1, /*maxT=*/temperature_ + 2,
/*numT=*/3,
/*minp=*/0.8e5, /*maxp=*/2.5e5, /*nump=*/500);
// set parameters of porous medium
perm_ = this->toDimMatrix_(1e-10);
porosity_ = 0.4;
tortuosity_ = 0.28;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::GridFile>("./data/outflow.dgf");
Parameters::SetDefault<Parameters::EndTime<Scalar>>(100.0);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(1.0);
Parameters::SetDefault<Parameters::VtkWriteMassFractions>(true);
}
/*!
* \name Problem parameters
*/
//! \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{ return "outflow"; }
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*
* This problem assumes a temperature.
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return temperature_; } // in [K]
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*
* This problem uses a constant intrinsic permeability.
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return perm_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*
* This problem uses a constant porosity.
*/
template <class Context>
Scalar porosity(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return porosity_; }
#if 0
/*!
* \brief Define the tortuosity \f$[?]\f$.
*
*/
template <class Context>
Scalar tortuosity(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{ return tortuosity_; }
/*!
* \brief Define the dispersivity \f$[?]\f$.
*
*/
template <class Context>
Scalar dispersivity(const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{ return 0; }
#endif
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& globalPos = context.pos(spaceIdx, timeIdx);
if (onLeftBoundary_(globalPos)) {
Opm::CompositionalFluidState<Scalar, FluidSystem,
/*storeEnthalpy=*/false> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
fs.setPressure(/*phaseIdx=*/0, fs.pressure(/*phaseIdx=*/0) + 1e5);
Scalar xlN2 = 2e-4;
fs.setMoleFraction(/*phaseIdx=*/0, N2Idx, xlN2);
fs.setMoleFraction(/*phaseIdx=*/0, H2OIdx, 1 - xlN2);
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
fs.setDensity(phaseIdx, FluidSystem::density(fs, paramCache, phaseIdx));
fs.setViscosity(phaseIdx, FluidSystem::viscosity(fs, paramCache, phaseIdx));
}
// impose an freeflow boundary condition
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
}
else if (onRightBoundary_(globalPos)) {
Opm::CompositionalFluidState<Scalar, FluidSystem,
/*storeEnthalpy=*/false> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
// impose an outflow boundary condition
values.setOutFlow(context, spaceIdx, timeIdx, fs);
}
else
// no flow on top and bottom
values.setNoFlow();
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
Opm::CompositionalFluidState<Scalar, FluidSystem, /*storeEnthalpy=*/false> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
values.assignNaive(fs);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
template <class FluidState, class Context>
void initialFluidState_(FluidState& fs, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
Scalar T = temperature(context, spaceIdx, timeIdx);
// Scalar rho = FluidSystem::H2O::liquidDensity(T, /*pressure=*/1.5e5);
// Scalar z = context.pos(spaceIdx, timeIdx)[dim - 1] -
// this->boundingBoxMax()[dim - 1];
// Scalar z = context.pos(spaceIdx, timeIdx)[dim - 1] -
// this->boundingBoxMax()[dim - 1];
fs.setSaturation(/*phaseIdx=*/0, 1.0);
fs.setPressure(/*phaseIdx=*/0, 1e5 /* + rho*z */);
fs.setMoleFraction(/*phaseIdx=*/0, H2OIdx, 1.0);
fs.setMoleFraction(/*phaseIdx=*/0, N2Idx, 0);
fs.setTemperature(T);
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
fs.setDensity(phaseIdx, FluidSystem::density(fs, paramCache, phaseIdx));
fs.setViscosity(phaseIdx, FluidSystem::viscosity(fs, paramCache, phaseIdx));
}
}
const Scalar eps_;
MaterialLawParams materialParams_;
DimMatrix perm_;
Scalar temperature_;
Scalar porosity_;
Scalar tortuosity_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,441 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::PowerInjectionProblem
*/
#ifndef EWOMS_POWER_INJECTION_PROBLEM_HH
#define EWOMS_POWER_INJECTION_PROBLEM_HH
#include <opm/models/immiscible/immisciblemodel.hh>
#include <opm/models/io/cubegridvanguard.hh>
#include <opm/material/fluidmatrixinteractions/RegularizedVanGenuchten.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/fluidsystems/TwoPhaseImmiscibleFluidSystem.hpp>
#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
#include <opm/material/components/SimpleH2O.hpp>
#include <opm/material/components/Air.hpp>
#include <dune/grid/yaspgrid.hh>
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <sstream>
#include <string>
#include <type_traits>
#include <iostream>
namespace Opm {
template <class TypeTag>
class PowerInjectionProblem;
}
namespace Opm::Properties {
namespace TTag {
struct PowerInjectionBaseProblem {};
}
// Set the grid implementation to be used
template<class TypeTag>
struct Grid<TypeTag, TTag::PowerInjectionBaseProblem> { using type = Dune::YaspGrid</*dim=*/1>; };
// set the Vanguard property
template<class TypeTag>
struct Vanguard<TypeTag, TTag::PowerInjectionBaseProblem> { using type = Opm::CubeGridVanguard<TypeTag>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::PowerInjectionBaseProblem> { using type = Opm::PowerInjectionProblem<TypeTag>; };
// Set the wetting phase
template<class TypeTag>
struct WettingPhase<TypeTag, TTag::PowerInjectionBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::LiquidPhase<Scalar, Opm::SimpleH2O<Scalar> >;
};
// Set the non-wetting phase
template<class TypeTag>
struct NonwettingPhase<TypeTag, TTag::PowerInjectionBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::GasPhase<Scalar, Opm::Air<Scalar> >;
};
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::PowerInjectionBaseProblem>
{
private:
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx };
enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx };
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::wettingPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::nonWettingPhaseIdx>;
// define the material law which is parameterized by effective
// saturations
using EffectiveLaw = Opm::RegularizedVanGenuchten<Traits>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::EffToAbsLaw<EffectiveLaw>;
};
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
* \brief 1D Problem with very fast injection of gas on the left.
*
* The velocity model is chosen in the .cc file in this problem. The
* spatial parameters are inspired by the ones given by
*
* V. Jambhekar: "Forchheimer Porous-media Flow models -- Numerical
* Investigation and Comparison with Experimental Data", Master's
* Thesis at Institute for Modelling Hydraulic and Environmental
* Systems, University of Stuttgart, 2011
*/
template <class TypeTag>
class PowerInjectionProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using Indices = GetPropType<TypeTag, Properties::Indices>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using WettingPhase = GetPropType<TypeTag, Properties::WettingPhase>;
using NonwettingPhase = GetPropType<TypeTag, Properties::NonwettingPhase>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
enum {
// number of phases
numPhases = FluidSystem::numPhases,
// phase indices
wettingPhaseIdx = FluidSystem::wettingPhaseIdx,
nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx,
// equation indices
contiNEqIdx = Indices::conti0EqIdx + nonWettingPhaseIdx,
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
PowerInjectionProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
eps_ = 3e-6;
FluidSystem::init();
temperature_ = 273.15 + 26.6;
// parameters for the Van Genuchten law
// alpha and n
materialParams_.setVgAlpha(0.00045);
materialParams_.setVgN(7.3);
materialParams_.finalize();
K_ = this->toDimMatrix_(5.73e-08); // [m^2]
setupInitialFluidState_();
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::CellsX>(250);
Parameters::SetDefault<Parameters::DomainSizeX<Scalar>>(100.0);
if constexpr (dim > 1) {
Parameters::SetDefault<Parameters::CellsY>(1);
Parameters::SetDefault<Parameters::DomainSizeY<Scalar>>(1.0);
}
if constexpr (dim == 3) {
Parameters::SetDefault<Parameters::CellsZ>(1);
Parameters::SetDefault<Parameters::DomainSizeZ<Scalar>>(1.0);
}
Parameters::SetDefault<Parameters::EndTime<Scalar>>(100.0);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(1e-3);
Parameters::SetDefault<Parameters::VtkWriteFilterVelocities>(true);
}
/*!
* \name Auxiliary methods
*/
//! \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << "powerinjection_";
if (std::is_same<GetPropType<TypeTag, Properties::FluxModule>,
Opm::DarcyFluxModule<TypeTag> >::value)
oss << "darcy";
else
oss << "forchheimer";
if (std::is_same<GetPropType<TypeTag, Properties::LocalLinearizerSplice>,
Properties::TTag::AutoDiffLocalLinearizer>::value)
oss << "_" << "ad";
else
oss << "_" << "fd";
return oss.str();
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
//! \}
/*!
* \name Soil parameters
*/
//! \{
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return K_; }
/*!
* \copydoc ForchheimerBaseProblem::ergunCoefficient
*/
template <class Context>
Scalar ergunCoefficient(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return 0.3866; }
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return 0.558; }
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams&
materialLawParams(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return materialParams_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return temperature_; }
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*
* This problem sets a very high injection rate of nitrogen on the
* left and a free-flow boundary on the right.
*/
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (onLeftBoundary_(pos)) {
RateVector massRate(0.0);
massRate = 0.0;
massRate[contiNEqIdx] = -1.00; // kg / (m^2 * s)
// impose a forced flow boundary
values.setMassRate(massRate);
}
else if (onRightBoundary_(pos))
// free flow boundary with initial condition on the right
values.setFreeFlow(context, spaceIdx, timeIdx, initialFluidState_);
else
values.setNoFlow();
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{
// assign the primary variables
values.assignNaive(initialFluidState_);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < this->boundingBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
void setupInitialFluidState_()
{
initialFluidState_.setTemperature(temperature_);
Scalar Sw = 1.0;
initialFluidState_.setSaturation(wettingPhaseIdx, Sw);
initialFluidState_.setSaturation(nonWettingPhaseIdx, 1 - Sw);
Scalar p = 1e5;
initialFluidState_.setPressure(wettingPhaseIdx, p);
initialFluidState_.setPressure(nonWettingPhaseIdx, p);
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(initialFluidState_);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
initialFluidState_.setDensity(phaseIdx,
FluidSystem::density(initialFluidState_, paramCache, phaseIdx));
initialFluidState_.setViscosity(phaseIdx,
FluidSystem::viscosity(initialFluidState_, paramCache, phaseIdx));
}
}
DimMatrix K_;
MaterialLawParams materialParams_;
Opm::ImmiscibleFluidState<Scalar, FluidSystem> initialFluidState_;
Scalar temperature_;
Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,763 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::ReservoirProblem
*/
#ifndef EWOMS_RESERVOIR_PROBLEM_HH
#define EWOMS_RESERVOIR_PROBLEM_HH
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
#include <opm/material/constraintsolvers/ComputeFromReferencePhase.hpp>
#include <opm/material/fluidsystems/blackoilpvt/DryGasPvt.hpp>
#include <opm/material/fluidsystems/blackoilpvt/LiveOilPvt.hpp>
#include <opm/material/fluidsystems/blackoilpvt/ConstantCompressibilityWaterPvt.hpp>
#include <opm/models/blackoil/blackoilproperties.hh>
#include <opm/models/common/multiphasebaseparameters.hh>
#include <opm/models/discretization/common/fvbaseparameters.hh>
#include <opm/models/discretization/common/fvbaseproperties.hh>
#include <opm/models/nonlinear/newtonmethodparameters.hh>
#include <opm/models/utils/basicproperties.hh>
#include <string>
#include <vector>
namespace Opm {
template <class TypeTag>
class ReservoirProblem;
} // namespace Opm
namespace Opm::Properties {
namespace TTag {
struct ReservoirBaseProblem {};
} // namespace TTag
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::ReservoirBaseProblem> { using type = Dune::YaspGrid<2>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::ReservoirBaseProblem> { using type = Opm::ReservoirProblem<TypeTag>; };
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::ReservoirBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Traits = Opm::
ThreePhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::waterPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::oilPhaseIdx,
/*gasPhaseIdx=*/FluidSystem::gasPhaseIdx>;
public:
using type = Opm::LinearMaterial<Traits>;
};
// Enable constraint DOFs?
template<class TypeTag>
struct EnableConstraints<TypeTag, TTag::ReservoirBaseProblem> { static constexpr bool value = true; };
/*!
* \brief Explicitly set the fluid system to the black-oil fluid system
*
* If the black oil model is used, this is superfluous because that model already sets
* the FluidSystem property. Setting it explictly for the problem is a good idea anyway,
* though because other models are more generic and thus do not assume a particular fluid
* system.
*/
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::ReservoirBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::BlackOilFluidSystem<Scalar>;
};
} // namespace Opm::Properties
namespace Opm::Parameters {
// Maximum depth of the reservoir
template<class Scalar>
struct MaxDepth { static constexpr Scalar value = 2500.0; };
// The temperature inside the reservoir
template<class Scalar>
struct Temperature { static constexpr Scalar value = 293.15; };
// The width of producer/injector wells as a fraction of the width of the spatial domain
template<class Scalar>
struct WellWidth { static constexpr Scalar value = 0.01; };
} // namespace Opm::Parameters
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief Some simple test problem for the black-oil VCVF discretization
* inspired by an oil reservoir.
*
* The domain is two-dimensional and exhibits a size of 6000m times 60m. Initially, the
* reservoir is assumed by oil with a bubble point pressure of 20 MPa, which also the
* initial pressure in the domain. No-flow boundaries are used for all boundaries. The
* permeability of the lower 10 m is reduced compared to the upper 10 m of the domain
* witch capillary pressure always being neglected. Three wells are approximated using
* constraints: Two water-injector wells, one at the lower-left boundary one at the
* lower-right boundary and one producer well in the upper part of the center of the
* domain. The pressure for the producer is assumed to be 2/3 of the reservoir pressure,
* the injector wells use a pressure which is 50% above the reservoir pressure.
*/
template <class TypeTag>
class ReservoirProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Evaluation = GetPropType<TypeTag, Properties::Evaluation>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
// Grid and world dimension
enum { dim = GridView::dimension };
enum { dimWorld = GridView::dimensionworld };
// copy some indices for convenience
enum { numPhases = FluidSystem::numPhases };
enum { numComponents = FluidSystem::numComponents };
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
enum { gasCompIdx = FluidSystem::gasCompIdx };
enum { oilCompIdx = FluidSystem::oilCompIdx };
enum { waterCompIdx = FluidSystem::waterCompIdx };
using Model = GetPropType<TypeTag, Properties::Model>;
using ElementContext = GetPropType<TypeTag, Properties::ElementContext>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using Constraints = GetPropType<TypeTag, Properties::Constraints>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
using PhaseVector = Dune::FieldVector<Scalar, numPhases>;
using InitialFluidState = Opm::CompositionalFluidState<Scalar,
FluidSystem,
/*enableEnthalpy=*/true>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
ReservoirProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
temperature_ = Parameters::Get<Parameters::Temperature<Scalar>>();
maxDepth_ = Parameters::Get<Parameters::MaxDepth<Scalar>>();
wellWidth_ = Parameters::Get<Parameters::WellWidth<Scalar>>();
std::vector<std::pair<Scalar, Scalar> > Bo = {
{ 101353, 1.062 },
{ 1.82504e+06, 1.15 },
{ 3.54873e+06, 1.207 },
{ 6.99611e+06, 1.295 },
{ 1.38909e+07, 1.435 },
{ 1.73382e+07, 1.5 },
{ 2.07856e+07, 1.565 },
{ 2.76804e+07, 1.695 },
{ 3.45751e+07, 1.827 }
};
std::vector<std::pair<Scalar, Scalar> > muo = {
{ 101353, 0.00104 },
{ 1.82504e+06, 0.000975 },
{ 3.54873e+06, 0.00091 },
{ 6.99611e+06, 0.00083 },
{ 1.38909e+07, 0.000695 },
{ 1.73382e+07, 0.000641 },
{ 2.07856e+07, 0.000594 },
{ 2.76804e+07, 0.00051 },
{ 3.45751e+07, 0.000449 }
};
std::vector<std::pair<Scalar, Scalar> > Rs = {
{ 101353, 0.178108 },
{ 1.82504e+06, 16.1187 },
{ 3.54873e+06, 32.0594 },
{ 6.99611e+06, 66.0779 },
{ 1.38909e+07, 113.276 },
{ 1.73382e+07, 138.033 },
{ 2.07856e+07, 165.64 },
{ 2.76804e+07, 226.197 },
{ 3.45751e+07, 288.178 }
};
std::vector<std::pair<Scalar, Scalar> > Bg = {
{ 101353, 0.93576 },
{ 1.82504e+06, 0.0678972 },
{ 3.54873e+06, 0.0352259 },
{ 6.99611e+06, 0.0179498 },
{ 1.38909e+07, 0.00906194 },
{ 1.73382e+07, 0.00726527 },
{ 2.07856e+07, 0.00606375 },
{ 2.76804e+07, 0.00455343 },
{ 3.45751e+07, 0.00364386 },
{ 6.21542e+07, 0.00216723 }
};
std::vector<std::pair<Scalar, Scalar> > mug = {
{ 101353, 8e-06 },
{ 1.82504e+06, 9.6e-06 },
{ 3.54873e+06, 1.12e-05 },
{ 6.99611e+06, 1.4e-05 },
{ 1.38909e+07, 1.89e-05 },
{ 1.73382e+07, 2.08e-05 },
{ 2.07856e+07, 2.28e-05 },
{ 2.76804e+07, 2.68e-05 },
{ 3.45751e+07, 3.09e-05 },
{ 6.21542e+07, 4.7e-05 }
};
Scalar rhoRefO = 786.0; // [kg]
Scalar rhoRefG = 0.97; // [kg]
Scalar rhoRefW = 1037.0; // [kg]
FluidSystem::initBegin(/*numPvtRegions=*/1);
FluidSystem::setEnableDissolvedGas(true);
FluidSystem::setEnableVaporizedOil(false);
FluidSystem::setReferenceDensities(rhoRefO, rhoRefW, rhoRefG, /*regionIdx=*/0);
Opm::GasPvtMultiplexer<Scalar> *gasPvt = new Opm::GasPvtMultiplexer<Scalar>;
gasPvt->setApproach(GasPvtApproach::DryGas);
auto& dryGasPvt = gasPvt->template getRealPvt<GasPvtApproach::DryGas>();
dryGasPvt.setNumRegions(/*numPvtRegion=*/1);
dryGasPvt.setReferenceDensities(/*regionIdx=*/0, rhoRefO, rhoRefG, rhoRefW);
dryGasPvt.setGasFormationVolumeFactor(/*regionIdx=*/0, Bg);
dryGasPvt.setGasViscosity(/*regionIdx=*/0, mug);
Opm::OilPvtMultiplexer<Scalar> *oilPvt = new Opm::OilPvtMultiplexer<Scalar>;
oilPvt->setApproach(OilPvtApproach::LiveOil);
auto& liveOilPvt = oilPvt->template getRealPvt<OilPvtApproach::LiveOil>();
liveOilPvt.setNumRegions(/*numPvtRegion=*/1);
liveOilPvt.setReferenceDensities(/*regionIdx=*/0, rhoRefO, rhoRefG, rhoRefW);
liveOilPvt.setSaturatedOilGasDissolutionFactor(/*regionIdx=*/0, Rs);
liveOilPvt.setSaturatedOilFormationVolumeFactor(/*regionIdx=*/0, Bo);
liveOilPvt.setSaturatedOilViscosity(/*regionIdx=*/0, muo);
Opm::WaterPvtMultiplexer<Scalar> *waterPvt = new Opm::WaterPvtMultiplexer<Scalar>;
waterPvt->setApproach(WaterPvtApproach::ConstantCompressibilityWater);
auto& ccWaterPvt = waterPvt->template getRealPvt<WaterPvtApproach::ConstantCompressibilityWater>();
ccWaterPvt.setNumRegions(/*numPvtRegions=*/1);
ccWaterPvt.setReferenceDensities(/*regionIdx=*/0, rhoRefO, rhoRefG, rhoRefW);
ccWaterPvt.setViscosity(/*regionIdx=*/0, 9.6e-4);
ccWaterPvt.setCompressibility(/*regionIdx=*/0, 1.450377e-10);
gasPvt->initEnd();
oilPvt->initEnd();
waterPvt->initEnd();
using GasPvtSharedPtr = std::shared_ptr<Opm::GasPvtMultiplexer<Scalar> >;
FluidSystem::setGasPvt(GasPvtSharedPtr(gasPvt));
using OilPvtSharedPtr = std::shared_ptr<Opm::OilPvtMultiplexer<Scalar> >;
FluidSystem::setOilPvt(OilPvtSharedPtr(oilPvt));
using WaterPvtSharedPtr = std::shared_ptr<Opm::WaterPvtMultiplexer<Scalar> >;
FluidSystem::setWaterPvt(WaterPvtSharedPtr(waterPvt));
FluidSystem::initEnd();
pReservoir_ = 330e5;
layerBottom_ = 22.0;
// intrinsic permeabilities
fineK_ = this->toDimMatrix_(1e-12);
coarseK_ = this->toDimMatrix_(1e-11);
// porosities
finePorosity_ = 0.2;
coarsePorosity_ = 0.3;
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
fineMaterialParams_.setPcMinSat(phaseIdx, 0.0);
fineMaterialParams_.setPcMaxSat(phaseIdx, 0.0);
coarseMaterialParams_.setPcMinSat(phaseIdx, 0.0);
coarseMaterialParams_.setPcMaxSat(phaseIdx, 0.0);
}
// wrap up the initialization of the material law's parameters
fineMaterialParams_.finalize();
coarseMaterialParams_.finalize();
materialParams_.resize(this->model().numGridDof());
ElementContext elemCtx(this->simulator());
auto eIt = this->simulator().gridView().template begin<0>();
const auto& eEndIt = this->simulator().gridView().template end<0>();
for (; eIt != eEndIt; ++eIt) {
elemCtx.updateStencil(*eIt);
size_t nDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
for (unsigned dofIdx = 0; dofIdx < nDof; ++ dofIdx) {
unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
const GlobalPosition& pos = elemCtx.pos(dofIdx, /*timeIdx=*/0);
if (isFineMaterial_(pos))
materialParams_[globalDofIdx] = &fineMaterialParams_;
else
materialParams_[globalDofIdx] = &coarseMaterialParams_;
}
}
initFluidState_();
// start the first ("settle down") episode for 100 days
this->simulator().startNextEpisode(100.0*24*60*60);
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::Register<Parameters::Temperature<Scalar>>
("The temperature [K] in the reservoir");
Parameters::Register<Parameters::MaxDepth<Scalar>>
("The maximum depth [m] of the reservoir");
Parameters::Register<Parameters::WellWidth<Scalar>>
("The width of producer/injector wells as a fraction of the width"
" of the spatial domain");
Parameters::SetDefault<Parameters::GridFile>("data/reservoir.dgf");
//! By default this problem spans 1000 days (100 "settle down" days and 900 days of
//! production)
Parameters::SetDefault<Parameters::EndTime<Scalar>>(1000.0*24*60*60);
Parameters::SetDefault<Parameters::EnableStorageCache>(true);
Parameters::SetDefault<Parameters::GridFile>("data/reservoir.dgf");
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(100e3);
// increase the tolerance for this problem to get larger time steps
Parameters::SetDefault<Parameters::NewtonTolerance<Scalar>>(1e-6);
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{ return std::string("reservoir_") + Model::name() + "_" + Model::discretizationName(); }
/*!
* \copydoc FvBaseProblem::endEpisode
*/
void endEpisode()
{
// in the second episode, the actual work is done (the first is "settle down"
// episode). we need to use a pretty short initial time step here as the change
// in conditions is quite abrupt.
this->simulator().startNextEpisode(1e100);
this->simulator().setTimeStepSize(5.0);
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
// checkConservativeness() does not include the effect of constraints, so we
// disable it for this problem...
//this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*
* For this problem, a layer with high permability is located
* above one with low permeability.
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& context, unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineK_;
return coarseK_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return finePorosity_;
return coarsePorosity_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams(const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
unsigned globalIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
return *materialParams_[globalIdx];
}
const MaterialLawParams& materialLawParams(unsigned globalIdx) const
{ return *materialParams_[globalIdx]; }
/*!
* \name Problem parameters
*/
//! \{
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*
* The black-oil model assumes constant temperature to define its
* parameters. Although temperature is thus not really used by the
* model, it gets written to the VTK output. Who nows, maybe we
* will need it one day?
*/
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return temperature_; }
// \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*
* The reservoir problem uses constraints to approximate
* extraction and production wells, so all boundaries are no-flow.
*/
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{
// no flow on top and bottom
values.setNoFlow();
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*
* The reservoir problem uses a constant boundary condition for
* the whole domain.
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{
values.assignNaive(initialFluidState_);
#ifndef NDEBUG
for (unsigned pvIdx = 0; pvIdx < values.size(); ++ pvIdx)
assert(std::isfinite(values[pvIdx]));
#endif
}
/*!
* \copydoc FvBaseProblem::constraints
*
* The reservoir problem places two water-injection wells on the lower-left and
* lower-right of the domain and a production well in the middle. The injection wells
* are fully water saturated with a higher pressure, the producer is fully oil
* saturated with a lower pressure than the remaining reservoir.
*/
template <class Context>
void constraints(Constraints& constraintValues,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
if (this->simulator().episodeIndex() == 1)
return; // no constraints during the "settle down" episode
const auto& pos = context.pos(spaceIdx, timeIdx);
if (isInjector_(pos)) {
constraintValues.setActive(true);
constraintValues.assignNaive(injectorFluidState_);
}
else if (isProducer_(pos)) {
constraintValues.setActive(true);
constraintValues.assignNaive(producerFluidState_);
}
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0 everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
void initFluidState_()
{
auto& fs = initialFluidState_;
//////
// set temperatures
//////
fs.setTemperature(temperature_);
//////
// set saturations
//////
fs.setSaturation(FluidSystem::oilPhaseIdx, 1.0);
fs.setSaturation(FluidSystem::waterPhaseIdx, 0.0);
fs.setSaturation(FluidSystem::gasPhaseIdx, 0.0);
//////
// set pressures
//////
Scalar pw = pReservoir_;
PhaseVector pC;
const auto& matParams = fineMaterialParams_;
MaterialLaw::capillaryPressures(pC, matParams, fs);
fs.setPressure(oilPhaseIdx, pw + (pC[oilPhaseIdx] - pC[waterPhaseIdx]));
fs.setPressure(waterPhaseIdx, pw + (pC[waterPhaseIdx] - pC[waterPhaseIdx]));
fs.setPressure(gasPhaseIdx, pw + (pC[gasPhaseIdx] - pC[waterPhaseIdx]));
// reset all mole fractions to 0
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
fs.setMoleFraction(phaseIdx, compIdx, 0.0);
//////
// set composition of the gas and water phases
//////
fs.setMoleFraction(waterPhaseIdx, waterCompIdx, 1.0);
fs.setMoleFraction(gasPhaseIdx, gasCompIdx, 1.0);
//////
// set composition of the oil phase
//////
Scalar RsSat =
FluidSystem::saturatedDissolutionFactor(fs, oilPhaseIdx, /*pvtRegionIdx=*/0);
Scalar XoGSat = FluidSystem::convertRsToXoG(RsSat, /*pvtRegionIdx=*/0);
Scalar xoGSat = FluidSystem::convertXoGToxoG(XoGSat, /*pvtRegionIdx=*/0);
Scalar xoG = 0.95*xoGSat;
Scalar xoO = 1.0 - xoG;
// finally set the oil-phase composition
fs.setMoleFraction(oilPhaseIdx, gasCompIdx, xoG);
fs.setMoleFraction(oilPhaseIdx, oilCompIdx, xoO);
using CFRP = Opm::ComputeFromReferencePhase<Scalar, FluidSystem>;
typename FluidSystem::template ParameterCache<Scalar> paramCache;
CFRP::solve(fs,
paramCache,
/*refPhaseIdx=*/oilPhaseIdx,
/*setViscosities=*/false,
/*setEnthalpies=*/false);
// set up the fluid state used for the injectors
auto& injFs = injectorFluidState_;
injFs = initialFluidState_;
Scalar pInj = pReservoir_ * 1.5;
injFs.setPressure(waterPhaseIdx, pInj);
injFs.setPressure(oilPhaseIdx, pInj);
injFs.setPressure(gasPhaseIdx, pInj);
injFs.setSaturation(waterPhaseIdx, 1.0);
injFs.setSaturation(oilPhaseIdx, 0.0);
injFs.setSaturation(gasPhaseIdx, 0.0);
// set the composition of the phases to immiscible
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx)
injFs.setMoleFraction(phaseIdx, compIdx, 0.0);
injFs.setMoleFraction(gasPhaseIdx, gasCompIdx, 1.0);
injFs.setMoleFraction(oilPhaseIdx, oilCompIdx, 1.0);
injFs.setMoleFraction(waterPhaseIdx, waterCompIdx, 1.0);
CFRP::solve(injFs,
paramCache,
/*refPhaseIdx=*/waterPhaseIdx,
/*setViscosities=*/true,
/*setEnthalpies=*/false);
// set up the fluid state used for the producer
auto& prodFs = producerFluidState_;
prodFs = initialFluidState_;
Scalar pProd = pReservoir_ / 1.5;
prodFs.setPressure(waterPhaseIdx, pProd);
prodFs.setPressure(oilPhaseIdx, pProd);
prodFs.setPressure(gasPhaseIdx, pProd);
prodFs.setSaturation(waterPhaseIdx, 0.0);
prodFs.setSaturation(oilPhaseIdx, 1.0);
prodFs.setSaturation(gasPhaseIdx, 0.0);
CFRP::solve(prodFs,
paramCache,
/*refPhaseIdx=*/oilPhaseIdx,
/*setViscosities=*/true,
/*setEnthalpies=*/false);
}
bool isProducer_(const GlobalPosition& pos) const
{
Scalar x = pos[0] - this->boundingBoxMin()[0];
Scalar y = pos[dim - 1] - this->boundingBoxMin()[dim - 1];
Scalar width = this->boundingBoxMax()[0] - this->boundingBoxMin()[0];
Scalar height = this->boundingBoxMax()[dim - 1] - this->boundingBoxMin()[dim - 1];
// only the upper half of the center section of the spatial domain is assumed to
// be the producer
if (y <= height/2.0)
return false;
return width/2.0 - width*1e-5 < x && x < width/2.0 + width*(wellWidth_ + 1e-5);
}
bool isInjector_(const GlobalPosition& pos) const
{
Scalar x = pos[0] - this->boundingBoxMin()[0];
Scalar y = pos[dim - 1] - this->boundingBoxMin()[dim - 1];
Scalar width = this->boundingBoxMax()[0] - this->boundingBoxMin()[0];
Scalar height = this->boundingBoxMax()[dim - 1] - this->boundingBoxMin()[dim - 1];
// only the lower half of the leftmost and rightmost part of the spatial domain
// are assumed to be the water injectors
if (y > height/2.0)
return false;
return x < width*wellWidth_ - width*1e-5 || x > width*(1.0 - wellWidth_) + width*1e-5;
}
bool isFineMaterial_(const GlobalPosition& pos) const
{ return pos[dim - 1] > layerBottom_; }
DimMatrix fineK_;
DimMatrix coarseK_;
Scalar layerBottom_;
Scalar pReservoir_;
Scalar finePorosity_;
Scalar coarsePorosity_;
MaterialLawParams fineMaterialParams_;
MaterialLawParams coarseMaterialParams_;
std::vector<const MaterialLawParams*> materialParams_;
InitialFluidState initialFluidState_;
InitialFluidState injectorFluidState_;
InitialFluidState producerFluidState_;
Scalar temperature_;
Scalar maxDepth_;
Scalar wellWidth_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,488 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::RichardsLensProblem
*/
#ifndef EWOMS_RICHARDS_LENS_PROBLEM_HH
#define EWOMS_RICHARDS_LENS_PROBLEM_HH
#include <opm/models/richards/richardsmodel.hh>
#include <opm/material/components/SimpleH2O.hpp>
#include <opm/material/fluidsystems/LiquidPhase.hpp>
#include <opm/material/fluidmatrixinteractions/RegularizedVanGenuchten.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <dune/common/version.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>
namespace Opm {
template <class TypeTag>
class RichardsLensProblem;
} // namespace Opm
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct RichardsLensProblem { using InheritsFrom = std::tuple<Richards>; };
} // end namespace TTag
// Use 2d YaspGrid
template<class TypeTag>
struct Grid<TypeTag, TTag::RichardsLensProblem> { using type = Dune::YaspGrid<2>; };
// Set the physical problem to be solved
template<class TypeTag>
struct Problem<TypeTag, TTag::RichardsLensProblem> { using type = Opm::RichardsLensProblem<TypeTag>; };
// Set the wetting phase
template<class TypeTag>
struct WettingFluid<TypeTag, TTag::RichardsLensProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
public:
using type = Opm::LiquidPhase<Scalar, Opm::SimpleH2O<Scalar> >;
};
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::RichardsLensProblem>
{
private:
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx };
enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx };
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::wettingPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::nonWettingPhaseIdx>;
// define the material law which is parameterized by effective
// saturations
using EffectiveLaw = Opm::RegularizedVanGenuchten<Traits>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::EffToAbsLaw<EffectiveLaw>;
};
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
*
* \brief A water infiltration problem with a low-permeability lens
* embedded into a high-permeability domain.
*
* The domain is rectangular. The left and right boundaries are
* free-flow boundaries with fixed water pressure which corresponds to
* a fixed saturation of \f$S_w = 0\f$ in the Richards model, the
* bottom boundary is closed. The top boundary is also closed except
* for an infiltration section, where water is infiltrating into an
* initially unsaturated porous medium. This problem is very similar
* the \c LensProblem, with the main difference being that the domain
* is initally fully saturated by gas instead of water and water
* instead of a \c DNAPL infiltrates from the top.
*/
template <class TypeTag>
class RichardsLensProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using Stencil = GetPropType<TypeTag, Properties::Stencil>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Model = GetPropType<TypeTag, Properties::Model>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using Indices = GetPropType<TypeTag, Properties::Indices>;
enum {
// copy some indices for convenience
pressureWIdx = Indices::pressureWIdx,
contiEqIdx = Indices::contiEqIdx,
wettingPhaseIdx = FluidSystem::wettingPhaseIdx,
nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx,
numPhases = FluidSystem::numPhases,
// Grid and world dimension
dimWorld = GridView::dimensionworld
};
// get the material law from the property system
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
//! The parameters of the material law to be used
using MaterialLawParams = typename MaterialLaw::Params;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using PhaseVector = Dune::FieldVector<Scalar, numPhases>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
RichardsLensProblem(Simulator& simulator)
: ParentType(simulator)
, pnRef_(1e5)
{
dofIsInLens_.resize(simulator.model().numGridDof());
}
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
eps_ = 3e-6;
pnRef_ = 1e5;
lensLowerLeft_[0] = 1.0;
lensLowerLeft_[1] = 2.0;
lensUpperRight_[0] = 4.0;
lensUpperRight_[1] = 3.0;
// parameters for the Van Genuchten law
// alpha and n
lensMaterialParams_.setVgAlpha(0.00045);
lensMaterialParams_.setVgN(7.3);
lensMaterialParams_.finalize();
outerMaterialParams_.setVgAlpha(0.0037);
outerMaterialParams_.setVgN(4.7);
outerMaterialParams_.finalize();
// parameters for the linear law
// minimum and maximum pressures
// lensMaterialParams_.setEntryPC(0);
// outerMaterialParams_.setEntryPC(0);
// lensMaterialParams_.setMaxPC(0);
// outerMaterialParams_.setMaxPC(0);
lensK_ = this->toDimMatrix_(1e-12);
outerK_ = this->toDimMatrix_(5e-12);
// determine which degrees of freedom are in the lens
Stencil stencil(this->gridView(), this->simulator().model().dofMapper() );
for (const auto& elem : elements(this->gridView())) {
stencil.update(elem);
for (unsigned dofIdx = 0; dofIdx < stencil.numPrimaryDof(); ++ dofIdx) {
unsigned globalDofIdx = stencil.globalSpaceIndex(dofIdx);
const auto& dofPos = stencil.subControlVolume(dofIdx).center();
dofIsInLens_[globalDofIdx] = isInLens_(dofPos);
}
}
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::GridFile>("./data/richardslens_24x16.dgf");
// Use central differences to approximate the Jacobian matrix
using LLS = GetPropType<TypeTag, Properties::LocalLinearizerSplice>;
constexpr bool useFD = std::is_same_v<LLS, Properties::TTag::FiniteDifferenceLocalLinearizer>;
if constexpr (useFD) {
Parameters::SetDefault<Parameters::NumericDifferenceMethod>(0);
}
Parameters::SetDefault<Parameters::EndTime<Scalar>>(3000.0);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(100.0);
Parameters::SetDefault<Parameters::NewtonMaxIterations>(28);
Parameters::SetDefault<Parameters::NewtonTargetIterations>(18);
Parameters::SetDefault<Parameters::EnableGravity>(true);
}
/*!
* \name Problem parameters
*/
//! \{
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << "lens_richards_"
<< Model::discretizationName();
return oss.str();
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
/*!
* \copydoc FvBaseMultiPhaseProblem::temperature
*/
template <class Context>
Scalar temperature(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{ return temperature(context.globalSpaceIndex(spaceIdx, timeIdx), timeIdx); }
Scalar temperature(unsigned /*globalSpaceIdx*/, unsigned /*timeIdx*/) const
{ return 273.15 + 10; } // -> 10°C
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isInLens_(pos))
return lensK_;
return outerK_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return 0.4; }
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
unsigned globalSpaceIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
return materialLawParams(globalSpaceIdx, timeIdx);
}
const MaterialLawParams& materialLawParams(unsigned globalSpaceIdx,
unsigned /*timeIdx*/) const
{
if (dofIsInLens_[globalSpaceIdx])
return lensMaterialParams_;
return outerMaterialParams_;
}
/*!
* \brief Return the reference pressure [Pa] of the wetting phase.
*
* \copydetails Doxygen::contextParams
*/
template <class Context>
Scalar referencePressure(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{ return referencePressure(context.globalSpaceIndex(spaceIdx, timeIdx), timeIdx); }
// the Richards model does not have an element context available at all places
// where the reference pressure is required...
Scalar referencePressure(unsigned /*globalSpaceIdx*/,
unsigned /*timeIdx*/) const
{ return pnRef_; }
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*/
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const auto& pos = context.pos(spaceIdx, timeIdx);
if (onLeftBoundary_(pos) || onRightBoundary_(pos)) {
const auto& materialParams = this->materialLawParams(context, spaceIdx, timeIdx);
Scalar Sw = 0.0;
Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
fs.setSaturation(wettingPhaseIdx, Sw);
fs.setSaturation(nonWettingPhaseIdx, 1.0 - Sw);
PhaseVector pC;
MaterialLaw::capillaryPressures(pC, materialParams, fs);
fs.setPressure(wettingPhaseIdx, pnRef_ + pC[wettingPhaseIdx] - pC[nonWettingPhaseIdx]);
fs.setPressure(nonWettingPhaseIdx, pnRef_);
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
fs.setDensity(wettingPhaseIdx, FluidSystem::density(fs, paramCache, wettingPhaseIdx));
//fs.setDensity(nonWettingPhaseIdx, FluidSystem::density(fs, paramCache, nonWettingPhaseIdx));
fs.setViscosity(wettingPhaseIdx, FluidSystem::viscosity(fs, paramCache, wettingPhaseIdx));
//fs.setViscosity(nonWettingPhaseIdx, FluidSystem::viscosity(fs, paramCache, nonWettingPhaseIdx));
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
}
else if (onInlet_(pos)) {
RateVector massRate(0.0);
// inflow of water
massRate[contiEqIdx] = -0.04; // kg / (m * s)
values.setMassRate(massRate);
}
else
values.setNoFlow();
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const auto& materialParams = this->materialLawParams(context, spaceIdx, timeIdx);
Scalar Sw = 0.0;
Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
fs.setSaturation(wettingPhaseIdx, Sw);
fs.setSaturation(nonWettingPhaseIdx, 1.0 - Sw);
PhaseVector pC;
MaterialLaw::capillaryPressures(pC, materialParams, fs);
values[pressureWIdx] = pnRef_ + (pC[wettingPhaseIdx] - pC[nonWettingPhaseIdx]);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = Scalar(0.0); }
//! \}
private:
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < this->boundingBoxMin()[0] + eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition& pos) const
{ return pos[1] < this->boundingBoxMin()[1] + eps_; }
bool onUpperBoundary_(const GlobalPosition& pos) const
{ return pos[1] > this->boundingBoxMax()[1] - eps_; }
bool onInlet_(const GlobalPosition& pos) const
{
Scalar width = this->boundingBoxMax()[0] - this->boundingBoxMin()[0];
Scalar lambda = (this->boundingBoxMax()[0] - pos[0]) / width;
return onUpperBoundary_(pos) && 0.5 < lambda && lambda < 2.0 / 3.0;
}
bool isInLens_(const GlobalPosition& pos) const
{
for (unsigned i = 0; i < dimWorld; ++i) {
if (pos[i] < lensLowerLeft_[i] || pos[i] > lensUpperRight_[i])
return false;
}
return true;
}
GlobalPosition lensLowerLeft_;
GlobalPosition lensUpperRight_;
DimMatrix lensK_;
DimMatrix outerK_;
MaterialLawParams lensMaterialParams_;
MaterialLawParams outerMaterialParams_;
std::vector<bool> dofIsInLens_;
Scalar eps_;
Scalar pnRef_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,604 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::WaterAirProblem
*/
#ifndef EWOMS_WATER_AIR_PROBLEM_HH
#define EWOMS_WATER_AIR_PROBLEM_HH
#include <dune/common/fmatrix.hh>
#include <dune/common/fvector.hh>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/dgfparser/dgfyasp.hh>
#include <opm/material/constraintsolvers/ComputeFromReferencePhase.hpp>
#include <opm/material/fluidmatrixinteractions/LinearMaterial.hpp>
#include <opm/material/fluidmatrixinteractions/RegularizedBrooksCorey.hpp>
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
#include <opm/material/fluidstates/ImmiscibleFluidState.hpp>
#include <opm/material/fluidstates/CompositionalFluidState.hpp>
#include <opm/material/fluidsystems/H2OAirFluidSystem.hpp>
#include <opm/material/thermal/ConstantSolidHeatCapLaw.hpp>
#include <opm/material/thermal/SomertonThermalConductionLaw.hpp>
#include <opm/models/common/multiphasebaseparameters.hh>
#include <opm/models/discretization/common/fvbasefdlocallinearizer.hh>
#include <opm/models/pvs/pvsproperties.hh>
#include <opm/simulators/linalg/parallelistlbackend.hh>
#include <sstream>
#include <string>
namespace Opm {
template <class TypeTag>
class WaterAirProblem;
}
namespace Opm::Properties {
namespace TTag {
struct WaterAirBaseProblem {};
}
// Set the grid type
template<class TypeTag>
struct Grid<TypeTag, TTag::WaterAirBaseProblem> { using type = Dune::YaspGrid<2>; };
// Set the problem property
template<class TypeTag>
struct Problem<TypeTag, TTag::WaterAirBaseProblem> { using type = Opm::WaterAirProblem<TypeTag>; };
// Set the material Law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::WaterAirBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Traits = Opm::TwoPhaseMaterialTraits<Scalar,
/*wettingPhaseIdx=*/FluidSystem::liquidPhaseIdx,
/*nonWettingPhaseIdx=*/FluidSystem::gasPhaseIdx>;
// define the material law which is parameterized by effective
// saturations
using EffMaterialLaw = Opm::RegularizedBrooksCorey<Traits>;
public:
// define the material law parameterized by absolute saturations
// which uses the two-phase API
using type = Opm::EffToAbsLaw<EffMaterialLaw>;
};
// Set the thermal conduction law
template<class TypeTag>
struct ThermalConductionLaw<TypeTag, TTag::WaterAirBaseProblem>
{
private:
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
public:
// define the material law parameterized by absolute saturations
using type = Opm::SomertonThermalConductionLaw<FluidSystem, Scalar>;
};
// set the energy storage law for the solid phase
template<class TypeTag>
struct SolidEnergyLaw<TypeTag, TTag::WaterAirBaseProblem>
{ using type = Opm::ConstantSolidHeatCapLaw<GetPropType<TypeTag, Properties::Scalar>>; };
// Set the fluid system. in this case, we use the one which describes
// air and water
template<class TypeTag>
struct FluidSystem<TypeTag, TTag::WaterAirBaseProblem>
{ using type = Opm::H2OAirFluidSystem<GetPropType<TypeTag, Properties::Scalar>>; };
// Use the restarted GMRES linear solver with the ILU-2 preconditioner from dune-istl
template<class TypeTag>
struct LinearSolverSplice<TypeTag, TTag::WaterAirBaseProblem>
{ using type = TTag::ParallelIstlLinearSolver; };
template<class TypeTag>
struct LinearSolverWrapper<TypeTag, TTag::WaterAirBaseProblem>
{ using type = Opm::Linear::SolverWrapperRestartedGMRes<TypeTag>; };
template<class TypeTag>
struct PreconditionerWrapper<TypeTag, TTag::WaterAirBaseProblem>
{ using type = Opm::Linear::PreconditionerWrapperILU<TypeTag>; };
} // namespace Opm::Properties
namespace Opm {
/*!
* \ingroup TestProblems
* \brief Non-isothermal gas injection problem where a air
* is injected into a fully water saturated medium.
*
* During buoyancy driven upward migration, the gas passes a
* rectangular high temperature area. This decreases the temperature
* of the high-temperature area and accelerates gas infiltration due
* to the lower viscosity of the gas. (Be aware that the pressure of
* the gas is approximately constant within the lens, so the density
* of the gas is reduced. This more than off-sets the viscosity
* increase of the gas at constant density.)
*
* The domain is sized 40 m times 40 m. The rectangular area with
* increased temperature (380 K) starts at (20 m, 5 m) and ends at (30
* m, 35 m).
*
* For the mass conservation equation, no-flow boundary conditions are
* used on the top and on the bottom of the domain, while free-flow
* conditions apply on the left and the right boundary. Gas is
* injected at bottom from 15 m to 25 m at a rate of 0.001 kg/(s m^2)
* by means if a forced inflow boundary condition.
*
* At the free-flow boundaries, the initial condition for the bulk
* part of the domain is assumed, i. e. hydrostatic pressure, a gas
* saturation of zero and a geothermal temperature gradient of 0.03
* K/m.
*/
template <class TypeTag >
class WaterAirProblem : public GetPropType<TypeTag, Properties::BaseProblem>
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
// copy some indices for convenience
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Indices = GetPropType<TypeTag, Properties::Indices>;
enum {
numPhases = FluidSystem::numPhases,
// energy related indices
temperatureIdx = Indices::temperatureIdx,
energyEqIdx = Indices::energyEqIdx,
// component indices
H2OIdx = FluidSystem::H2OIdx,
AirIdx = FluidSystem::AirIdx,
// phase indices
liquidPhaseIdx = FluidSystem::liquidPhaseIdx,
gasPhaseIdx = FluidSystem::gasPhaseIdx,
// equation indices
conti0EqIdx = Indices::conti0EqIdx,
// Grid and world dimension
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
static const bool enableEnergy = getPropValue<TypeTag, Properties::EnableEnergy>();
using EqVector = GetPropType<TypeTag, Properties::EqVector>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using Constraints = GetPropType<TypeTag, Properties::Constraints>;
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using Model = GetPropType<TypeTag, Properties::Model>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
using ThermalConductionLawParams = GetPropType<TypeTag, Properties::ThermalConductionLawParams>;
using SolidEnergyLawParams = GetPropType<TypeTag, Properties::SolidEnergyLawParams>;
using CoordScalar = typename GridView::ctype;
using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
public:
/*!
* \copydoc Doxygen::defaultProblemConstructor
*/
WaterAirProblem(Simulator& simulator)
: ParentType(simulator)
{ }
/*!
* \copydoc FvBaseProblem::finishInit
*/
void finishInit()
{
ParentType::finishInit();
maxDepth_ = 1000.0; // [m]
eps_ = 1e-6;
FluidSystem::init(/*Tmin=*/275, /*Tmax=*/600, /*nT=*/100,
/*pmin=*/9.5e6, /*pmax=*/10.5e6, /*np=*/200);
layerBottom_ = 22.0;
// intrinsic permeabilities
fineK_ = this->toDimMatrix_(1e-13);
coarseK_ = this->toDimMatrix_(1e-12);
// porosities
finePorosity_ = 0.3;
coarsePorosity_ = 0.3;
// residual saturations
fineMaterialParams_.setResidualSaturation(liquidPhaseIdx, 0.2);
fineMaterialParams_.setResidualSaturation(gasPhaseIdx, 0.0);
coarseMaterialParams_.setResidualSaturation(liquidPhaseIdx, 0.2);
coarseMaterialParams_.setResidualSaturation(gasPhaseIdx, 0.0);
// parameters for the Brooks-Corey law
fineMaterialParams_.setEntryPressure(1e4);
coarseMaterialParams_.setEntryPressure(1e4);
fineMaterialParams_.setLambda(2.0);
coarseMaterialParams_.setLambda(2.0);
fineMaterialParams_.finalize();
coarseMaterialParams_.finalize();
// parameters for the somerton law of thermal conduction
computeThermalCondParams_(fineThermalCondParams_, finePorosity_);
computeThermalCondParams_(coarseThermalCondParams_, coarsePorosity_);
// assume constant volumetric heat capacity and granite
solidEnergyLawParams_.setSolidHeatCapacity(790.0 // specific heat capacity of granite [J / (kg K)]
* 2700.0); // density of granite [kg/m^3]
solidEnergyLawParams_.finalize();
}
/*!
* \name Problem parameters
*/
//! \{
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::GridFile>("./data/waterair.dgf");
// Use forward differences
Parameters::SetDefault<Parameters::NumericDifferenceMethod>(+1);
Parameters::SetDefault<Parameters::EndTime<Scalar>>(1.0 * 365 * 24 * 60 * 60);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(250.0);
Parameters::SetDefault<Parameters::EnableGravity>(true);
Parameters::SetDefault<Parameters::PreconditionerOrder>(2);
}
/*!
* \copydoc FvBaseProblem::name
*/
std::string name() const
{
std::ostringstream oss;
oss << "waterair_" << Model::name();
if (getPropValue<TypeTag, Properties::EnableEnergy>())
oss << "_ni";
return oss.str();
}
/*!
* \copydoc FvBaseProblem::endTimeStep
*/
void endTimeStep()
{
#ifndef NDEBUG
// checkConservativeness() does not include the effect of constraints, so we
// disable it for this problem...
//this->model().checkConservativeness();
// Calculate storage terms
EqVector storage;
this->model().globalStorage(storage);
// Write mass balance information for rank 0
if (this->gridView().comm().rank() == 0) {
std::cout << "Storage: " << storage << std::endl << std::flush;
}
#endif // NDEBUG
}
/*!
* \copydoc FvBaseMultiPhaseProblem::intrinsicPermeability
*
* In this problem, the upper part of the domain is sightly less
* permeable than the lower one.
*/
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineK_;
return coarseK_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::porosity
*/
template <class Context>
Scalar porosity(const Context& context, unsigned spaceIdx, unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return finePorosity_;
else
return coarsePorosity_;
}
/*!
* \copydoc FvBaseMultiPhaseProblem::materialLawParams
*/
template <class Context>
const MaterialLawParams& materialLawParams(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineMaterialParams_;
else
return coarseMaterialParams_;
}
/*!
* \brief Return the parameters for the energy storage law of the rock
*
* In this case, we assume the rock-matrix to be granite.
*/
template <class Context>
const SolidEnergyLawParams&
solidEnergyLawParams(const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ return solidEnergyLawParams_; }
/*!
* \copydoc FvBaseMultiPhaseProblem::thermalConductionParams
*/
template <class Context>
const ThermalConductionLawParams&
thermalConductionLawParams(const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
if (isFineMaterial_(pos))
return fineThermalCondParams_;
return coarseThermalCondParams_;
}
//! \}
/*!
* \name Boundary conditions
*/
//! \{
/*!
* \copydoc FvBaseProblem::boundary
*
* For this problem, we inject air at the inlet on the center of
* the lower domain boundary and use a no-flow condition on the
* top boundary and a and a free-flow condition on the left and
* right boundaries of the domain.
*/
template <class Context>
void boundary(BoundaryRateVector& values,
const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const auto& pos = context.cvCenter(spaceIdx, timeIdx);
assert(onLeftBoundary_(pos) ||
onLowerBoundary_(pos) ||
onRightBoundary_(pos) ||
onUpperBoundary_(pos));
if (onInlet_(pos)) {
RateVector massRate(0.0);
massRate[conti0EqIdx + AirIdx] = -1e-3; // [kg/(m^2 s)]
// impose an forced inflow boundary condition on the inlet
values.setMassRate(massRate);
if (enableEnergy) {
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
Scalar hl = fs.enthalpy(liquidPhaseIdx);
Scalar hg = fs.enthalpy(gasPhaseIdx);
values.setEnthalpyRate(values[conti0EqIdx + AirIdx] * hg +
values[conti0EqIdx + H2OIdx] * hl);
}
}
else if (onLeftBoundary_(pos) || onRightBoundary_(pos)) {
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
// impose an freeflow boundary condition
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
}
else
// no flow on top and bottom
values.setNoFlow();
}
//! \}
/*!
* \name Volumetric terms
*/
//! \{
/*!
* \copydoc FvBaseProblem::initial
*
* For this problem, we set the medium to be fully saturated by
* liquid water and assume hydrostatic pressure.
*/
template <class Context>
void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
Opm::CompositionalFluidState<Scalar, FluidSystem> fs;
initialFluidState_(fs, context, spaceIdx, timeIdx);
const auto& matParams = materialLawParams(context, spaceIdx, timeIdx);
values.assignMassConservative(fs, matParams, /*inEquilibrium=*/true);
}
/*!
* \copydoc FvBaseProblem::source
*
* For this problem, the source term of all components is 0
* everywhere.
*/
template <class Context>
void source(RateVector& rate,
const Context& /*context*/,
unsigned /*spaceIdx*/,
unsigned /*timeIdx*/) const
{ rate = 0; }
//! \}
private:
bool onLeftBoundary_(const GlobalPosition& pos) const
{ return pos[0] < eps_; }
bool onRightBoundary_(const GlobalPosition& pos) const
{ return pos[0] > this->boundingBoxMax()[0] - eps_; }
bool onLowerBoundary_(const GlobalPosition& pos) const
{ return pos[1] < eps_; }
bool onUpperBoundary_(const GlobalPosition& pos) const
{ return pos[1] > this->boundingBoxMax()[1] - eps_; }
bool onInlet_(const GlobalPosition& pos) const
{ return onLowerBoundary_(pos) && (15.0 < pos[0]) && (pos[0] < 25.0); }
bool inHighTemperatureRegion_(const GlobalPosition& pos) const
{ return (20 < pos[0]) && (pos[0] < 30) && (pos[1] < 30); }
template <class Context, class FluidState>
void initialFluidState_(FluidState& fs,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx) const
{
const GlobalPosition& pos = context.pos(spaceIdx, timeIdx);
Scalar densityW = 1000.0;
fs.setPressure(liquidPhaseIdx, 1e5 + (maxDepth_ - pos[1])*densityW*9.81);
fs.setSaturation(liquidPhaseIdx, 1.0);
fs.setMoleFraction(liquidPhaseIdx, H2OIdx, 1.0);
fs.setMoleFraction(liquidPhaseIdx, AirIdx, 0.0);
if (inHighTemperatureRegion_(pos))
fs.setTemperature(380);
else
fs.setTemperature(283.0 + (maxDepth_ - pos[1])*0.03);
// set the gas saturation and pressure
fs.setSaturation(gasPhaseIdx, 0);
Scalar pc[numPhases];
const auto& matParams = materialLawParams(context, spaceIdx, timeIdx);
MaterialLaw::capillaryPressures(pc, matParams, fs);
fs.setPressure(gasPhaseIdx, fs.pressure(liquidPhaseIdx) + (pc[gasPhaseIdx] - pc[liquidPhaseIdx]));
typename FluidSystem::template ParameterCache<Scalar> paramCache;
using CFRP = Opm::ComputeFromReferencePhase<Scalar, FluidSystem>;
CFRP::solve(fs, paramCache, liquidPhaseIdx, /*setViscosity=*/true, /*setEnthalpy=*/true);
}
void computeThermalCondParams_(ThermalConductionLawParams& params, Scalar poro)
{
Scalar lambdaGranite = 2.8; // [W / (K m)]
// create a Fluid state which has all phases present
Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
fs.setTemperature(293.15);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
fs.setPressure(phaseIdx, 1.0135e5);
}
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
Scalar rho = FluidSystem::density(fs, paramCache, phaseIdx);
fs.setDensity(phaseIdx, rho);
}
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
Scalar lambdaSaturated;
if (FluidSystem::isLiquid(phaseIdx)) {
Scalar lambdaFluid =
FluidSystem::thermalConductivity(fs, paramCache, phaseIdx);
lambdaSaturated = std::pow(lambdaGranite, (1-poro)) + std::pow(lambdaFluid, poro);
}
else
lambdaSaturated = std::pow(lambdaGranite, (1-poro));
params.setFullySaturatedLambda(phaseIdx, lambdaSaturated);
if (!FluidSystem::isLiquid(phaseIdx))
params.setVacuumLambda(lambdaSaturated);
}
}
bool isFineMaterial_(const GlobalPosition& pos) const
{ return pos[dim-1] > layerBottom_; }
DimMatrix fineK_;
DimMatrix coarseK_;
Scalar layerBottom_;
Scalar finePorosity_;
Scalar coarsePorosity_;
MaterialLawParams fineMaterialParams_;
MaterialLawParams coarseMaterialParams_;
ThermalConductionLawParams fineThermalCondParams_;
ThermalConductionLawParams coarseThermalCondParams_;
SolidEnergyLawParams solidEnergyLawParams_;
Scalar maxDepth_;
Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,65 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the reservoir problem using the black-oil model, the ECFV discretization
* and automatic differentiation.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/blackoil/blackoilmodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/reservoirproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct ReservoirBlackOilEcfvProblem
{ using InheritsFrom = std::tuple<ReservoirBaseProblem, BlackOilModel>; };
} // end namespace TTag
// Select the element centered finite volume method as spatial discretization
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::ReservoirBlackOilEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
// Use automatic differentiation to linearize the system of PDEs
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::ReservoirBlackOilEcfvProblem>
{ using type = TTag::AutoDiffLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::ReservoirBlackOilEcfvProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,59 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the black-oil model using the VCFV discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/blackoil/blackoilmodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/reservoirproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct ReservoirBlackOilVcfvProblem
{ using InheritsFrom = std::tuple<ReservoirBaseProblem, BlackOilModel>; };
} // end namespace TTag
// Select the vertex centered finite volume method as spatial discretization
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::ReservoirBlackOilVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::ReservoirBlackOilVcfvProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,64 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the black-oil VCVF discretization.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/ncp/ncpmodel.hh>
#include <opm/models/discretization/ecfv/ecfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/reservoirproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct ReservoirNcpEcfvProblem
{ using InheritsFrom = std::tuple<ReservoirBaseProblem, NcpModel>; };
} // end namespace TTag
// Select the element centered finite volume method as spatial discretization
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::ReservoirNcpEcfvProblem>
{ using type = TTag::EcfvDiscretization; };
//! use automatic differentiation to linearize the system of PDEs
template<class TypeTag>
struct LocalLinearizerSplice<TypeTag, TTag::ReservoirNcpEcfvProblem>
{ using type = TTag::AutoDiffLocalLinearizer; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::ReservoirNcpEcfvProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

View File

@@ -0,0 +1,69 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Test for the reservoir problem using the NCP model, the VCFV discretization and
* finite differences.
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/ncp/ncpmodel.hh>
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh>
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "problems/reservoirproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct ReservoirNcpVcfvProblem
{ using InheritsFrom = std::tuple<ReservoirBaseProblem, NcpModel>; };
} // end namespace TTag
// Select the vertex centered finite volume method as spatial discretization
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::ReservoirNcpVcfvProblem>
{ using type = TTag::VcfvDiscretization; };
// reduce the base epsilon for the finite difference method to 10^-11. for some reason
// the simulator converges better with this. (TODO: use automatic differentiation?)
template<class TypeTag>
struct BaseEpsilon<TypeTag, TTag::ReservoirNcpVcfvProblem>
{
using type = GetPropType<TypeTag, Scalar>;
static constexpr type value = 1e-11;
};
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::ReservoirNcpVcfvProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}

39
examples/tutorial1.cpp Normal file
View File

@@ -0,0 +1,39 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief Main file of the tutorial problem using the model which assumes
* immisciblility.
*/
#include "config.h" /*@\label{tutorial1:include-begin}@*/
#include <opm/models/utils/start.hh> /*@\label{tutorial1:include-end}@*/
#include <opm/simulators/linalg/parallelbicgstabbackend.hh>
#include "tutorial1problem.hh" /*@\label{tutorial1:include-problem-header}@*/
int main(int argc, char **argv)
{
using TypeTag = Opm::Properties::TTag::Tutorial1Problem; /*@\label{tutorial1:set-type-tag}@*/
return Opm::start<TypeTag>(argc, argv); /*@\label{tutorial1:call-start}@*/
}

View File

@@ -0,0 +1,333 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::Tutorial1Problem
*/
#ifndef EWOMS_TUTORIAL1_PROBLEM_HH /*@\label{tutorial1:guardian1}@*/
#define EWOMS_TUTORIAL1_PROBLEM_HH /*@\label{tutorial1:guardian2}@*/
// The numerical model
#include <opm/models/immiscible/immisciblemodel.hh>
// The spatial discretization (VCFV == Vertex-Centered Finite Volumes)
#include <opm/models/discretization/vcfv/vcfvdiscretization.hh> /*@\label{tutorial1:include-discretization}@*/
// The chemical species that are used
#include <opm/material/components/SimpleH2O.hpp>
#include <opm/material/components/Lnapl.hpp>
// Headers required for the capillary pressure law
#include <opm/material/fluidmatrixinteractions/RegularizedBrooksCorey.hpp> /*@\label{tutorial1:rawLawInclude}@*/
#include <opm/material/fluidmatrixinteractions/EffToAbsLaw.hpp>
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
// For the DUNE grid
#include <dune/grid/yaspgrid.hh> /*@\label{tutorial1:include-grid-manager}@*/
#include <opm/models/io/cubegridvanguard.hh> /*@\label{tutorial1:include-grid-manager}@*/
// For Dune::FieldMatrix
#include <dune/common/fmatrix.hh>
#include <dune/common/version.hh>
namespace Opm {
// forward declaration of the problem class
template <class TypeTag>
class Tutorial1Problem;
}
namespace Opm::Properties {
// Create a new type tag for the problem
// Create new type tags
namespace TTag {
struct Tutorial1Problem { using InheritsFrom = std::tuple<ImmiscibleTwoPhaseModel>; };
} // end namespace TTag
// Select the vertex centered finite volume method as spatial discretization
template<class TypeTag>
struct SpatialDiscretizationSplice<TypeTag, TTag::Tutorial1Problem>
{ using type = TTag::VcfvDiscretization; }; /*@\label{tutorial1:set-spatial-discretization}@*/
// Set the "Problem" property
template<class TypeTag>
struct Problem<TypeTag, TTag::Tutorial1Problem>
{ using type = Opm::Tutorial1Problem<TypeTag>; }; /*@\label{tutorial1:set-problem}@*/
// Set grid and the grid manager to be used
template<class TypeTag>
struct Grid<TypeTag, TTag::Tutorial1Problem> { using type = Dune::YaspGrid</*dim=*/2>; }; /*@\label{tutorial1:set-grid}@*/
template<class TypeTag>
struct Vanguard<TypeTag, TTag::Tutorial1Problem> { using type = Opm::CubeGridVanguard<TypeTag>; }; /*@\label{tutorial1:set-grid-manager}@*/
// Set the wetting phase /*@\label{tutorial1:2p-system-start}@*/
template<class TypeTag>
struct WettingPhase<TypeTag, TTag::Tutorial1Problem> /*@\label{tutorial1:wettingPhase}@*/
{
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using type = Opm::LiquidPhase<Scalar, Opm::SimpleH2O<Scalar> >;
};
// Set the non-wetting phase
template<class TypeTag>
struct NonwettingPhase<TypeTag, TTag::Tutorial1Problem> /*@\label{tutorial1:nonwettingPhase}@*/
{
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using type = Opm::LiquidPhase<Scalar, Opm::LNAPL<Scalar> >;
}; /*@\label{tutorial1:2p-system-end}@*/
// Set the material law
template<class TypeTag>
struct MaterialLaw<TypeTag, TTag::Tutorial1Problem>
{
private:
// create a class holding the necessary information for a
// two-phase capillary pressure law
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx };
enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx };
using Traits = Opm::TwoPhaseMaterialTraits<Scalar, wettingPhaseIdx, nonWettingPhaseIdx>;
// define the material law which is parameterized by effective
// saturations
using RawMaterialLaw = Opm::RegularizedBrooksCorey<Traits>; /*@\label{tutorial1:rawlaw}@*/
public:
// Convert absolute saturations into effective ones before passing
// it to the base capillary pressure law
using type = Opm::EffToAbsLaw<RawMaterialLaw>; /*@\label{tutorial1:eff2abs}@*/
};
} // namespace Opm::Properties
namespace Opm {
//! Tutorial problem using the "immiscible" model.
template <class TypeTag>
class Tutorial1Problem
: public GetPropType<TypeTag, Properties::BaseProblem> /*@\label{tutorial1:def-problem}@*/
{
using ParentType = GetPropType<TypeTag, Properties::BaseProblem>;
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
using GridView = GetPropType<TypeTag, Properties::GridView>;
// Grid dimension
enum {
dim = GridView::dimension,
dimWorld = GridView::dimensionworld
};
// The type of the intrinsic permeability tensor
using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
// eWoms specific types are specified via the property system
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
using BoundaryRateVector = GetPropType<TypeTag, Properties::BoundaryRateVector>;
using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
using Indices = GetPropType<TypeTag, Properties::Indices>;
using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>; /*@\label{tutorial1:matLawObjectType}@*/
// phase indices
enum { numPhases = FluidSystem::numPhases };
enum { wettingPhaseIdx = FluidSystem::wettingPhaseIdx };
enum { nonWettingPhaseIdx = FluidSystem::nonWettingPhaseIdx };
// Indices of the conservation equations
enum { contiWettingEqIdx = Indices::conti0EqIdx + wettingPhaseIdx };
enum { contiNonWettingEqIdx = Indices::conti0EqIdx + nonWettingPhaseIdx };
public:
//! The constructor of the problem. This only _allocates_ the memory required by the
//! problem. The constructor is supposed to _never ever_ throw an exception.
Tutorial1Problem(Simulator& simulator)
: ParentType(simulator)
, eps_(3e-6)
{ }
//! This method initializes the data structures allocated by the problem
//! constructor. In contrast to the constructor, exceptions thrown from within this
//! method won't lead to segmentation faults.
void finishInit()
{
ParentType::finishInit();
// Use an isotropic and homogeneous intrinsic permeability
K_ = this->toDimMatrix_(1e-7);
// Parameters of the Brooks-Corey law
materialParams_.setEntryPressure(500.0 /*Pa*/); /*@\label{tutorial1:setLawParams}@*/
materialParams_.setLambda(2); // shape parameter
// Set the residual saturations
materialParams_.setResidualSaturation(wettingPhaseIdx, 0.0);
materialParams_.setResidualSaturation(nonWettingPhaseIdx, 0.0);
// wrap up the initialization of the material law's parameters
materialParams_.finalize();
}
/*!
* \copydoc FvBaseMultiPhaseProblem::registerParameters
*/
static void registerParameters()
{
ParentType::registerParameters();
Parameters::SetDefault<Parameters::CellsX>(100);
Parameters::SetDefault<Parameters::CellsY>(1);
Parameters::SetDefault<Parameters::DomainSizeX<Scalar>>(300.0);
Parameters::SetDefault<Parameters::DomainSizeY<Scalar>>(60.0);
if constexpr (dim == 3) {
Parameters::SetDefault<Parameters::CellsZ>(1);
Parameters::SetDefault<Parameters::DomainSizeZ<Scalar>>(0.0);
}
Parameters::SetDefault<Parameters::EndTime<Scalar>>(100e3);
Parameters::SetDefault<Parameters::InitialTimeStepSize<Scalar>>(125.0);
}
//! Specifies the problem name. This is used for files generated by the simulation.
std::string name() const
{ return "tutorial1"; }
//! Returns the temperature at a given position.
template <class Context>
Scalar temperature(const Context& /*context*/,
unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{ return 283.15; }
//! Returns the intrinsic permeability tensor [m^2] at a position.
template <class Context>
const DimMatrix& intrinsicPermeability(const Context& /*context*/, /*@\label{tutorial1:permeability}@*/
unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{ return K_; }
//! Defines the porosity [-] of the medium at a given position
template <class Context>
Scalar porosity(const Context& /*context*/,
unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const /*@\label{tutorial1:porosity}@*/
{ return 0.2; }
//! Returns the parameter object for the material law at a given position
template <class Context>
const MaterialLawParams& materialLawParams(const Context& /*context*/, /*@\label{tutorial1:matLawParams}@*/
unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{ return materialParams_; }
//! Evaluates the boundary conditions.
template <class Context>
void boundary(BoundaryRateVector& values, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
const auto& pos = context.pos(spaceIdx, timeIdx);
if (pos[0] < eps_) {
// Free-flow conditions on left boundary
const auto& materialParams = this->materialLawParams(context, spaceIdx, timeIdx);
Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
Scalar Sw = 1.0;
fs.setSaturation(wettingPhaseIdx, Sw);
fs.setSaturation(nonWettingPhaseIdx, 1.0 - Sw);
fs.setTemperature(temperature(context, spaceIdx, timeIdx));
Scalar pC[numPhases];
MaterialLaw::capillaryPressures(pC, materialParams, fs);
fs.setPressure(wettingPhaseIdx, 200e3);
fs.setPressure(nonWettingPhaseIdx, 200e3 + pC[nonWettingPhaseIdx] - pC[nonWettingPhaseIdx]);
typename FluidSystem::template ParameterCache<Scalar> paramCache;
paramCache.updateAll(fs);
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
fs.setDensity(phaseIdx, FluidSystem::density(fs, paramCache, phaseIdx));
fs.setViscosity(phaseIdx, FluidSystem::viscosity(fs, paramCache, phaseIdx));
}
values.setFreeFlow(context, spaceIdx, timeIdx, fs);
}
else if (pos[0] > this->boundingBoxMax()[0] - eps_) {
// forced outflow at the right boundary
RateVector massRate(0.0);
massRate[contiWettingEqIdx] = 0.0; // [kg / (s m^2)]
massRate[contiNonWettingEqIdx] = 3e-2; // [kg / (s m^2)]
values.setMassRate(massRate);
}
else // no flow at the remaining boundaries
values.setNoFlow();
}
//! Evaluates the source term for all conserved quantities at a given
//! position of the domain [kg/(m^3 * s)]. Positive values mean that
//! mass is created.
template <class Context>
void source(RateVector& sourceRate, const Context& /*context*/,
unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const
{
sourceRate[contiWettingEqIdx] = 0.0;
sourceRate[contiNonWettingEqIdx] = 0.0;
}
//! Evaluates the initial value at a given position in the domain.
template <class Context>
void initial(PrimaryVariables& values, const Context& context,
unsigned spaceIdx, unsigned timeIdx) const
{
Opm::ImmiscibleFluidState<Scalar, FluidSystem> fs;
// the domain is initially fully saturated by LNAPL
Scalar Sw = 0.0;
fs.setSaturation(wettingPhaseIdx, Sw);
fs.setSaturation(nonWettingPhaseIdx, 1.0 - Sw);
// the temperature is given by the temperature() method
fs.setTemperature(temperature(context, spaceIdx, timeIdx));
// set pressure of the wetting phase to 200 kPa = 2 bar
Scalar pC[numPhases];
MaterialLaw::capillaryPressures(pC, materialLawParams(context, spaceIdx, timeIdx),
fs);
fs.setPressure(wettingPhaseIdx, 200e3);
fs.setPressure(nonWettingPhaseIdx, 200e3 + pC[nonWettingPhaseIdx] - pC[nonWettingPhaseIdx]);
values.assignNaive(fs);
}
private:
DimMatrix K_;
// Object that holds the parameters of required by the capillary pressure law.
MaterialLawParams materialParams_; /*@\label{tutorial1:matParamsObject}@*/
// small epsilon value
Scalar eps_;
};
} // namespace Opm
#endif

View File

@@ -0,0 +1,53 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \brief test for the 2p2cni VCVF discretization
*/
#include "config.h"
#include <opm/models/io/dgfvanguard.hh>
#include <opm/models/utils/start.hh>
#include <opm/models/pvs/pvsmodel.hh>
#include "problems/waterairproblem.hh"
namespace Opm::Properties {
// Create new type tags
namespace TTag {
struct WaterAirProblem
{ using InheritsFrom = std::tuple<WaterAirBaseProblem, PvsModel>; };
} // end namespace TTag
template<class TypeTag>
struct EnableEnergy<TypeTag, TTag::WaterAirProblem>
{ static constexpr bool value = true; };
} // namespace Opm::Properties
int main(int argc, char **argv)
{
using ProblemTypeTag = Opm::Properties::TTag::WaterAirProblem;
return Opm::start<ProblemTypeTag>(argc, argv);
}