mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Import opm-models
This commit is contained in:
286
examples/art2dgf.cpp
Normal file
286
examples/art2dgf.cpp
Normal 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;
|
||||
}
|
||||
62
examples/co2_ptflash_ecfv.cpp
Normal file
62
examples/co2_ptflash_ecfv.cpp
Normal 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);
|
||||
}
|
||||
85
examples/co2injection_flash_ecfv.cpp
Normal file
85
examples/co2injection_flash_ecfv.cpp
Normal 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);
|
||||
}
|
||||
87
examples/co2injection_flash_ni_ecfv.cpp
Normal file
87
examples/co2injection_flash_ni_ecfv.cpp
Normal 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);
|
||||
}
|
||||
83
examples/co2injection_flash_ni_vcfv.cpp
Normal file
83
examples/co2injection_flash_ni_vcfv.cpp
Normal 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);
|
||||
}
|
||||
79
examples/co2injection_flash_vcfv.cpp
Normal file
79
examples/co2injection_flash_vcfv.cpp
Normal 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);
|
||||
}
|
||||
60
examples/co2injection_immiscible_ecfv.cpp
Normal file
60
examples/co2injection_immiscible_ecfv.cpp
Normal 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);
|
||||
}
|
||||
68
examples/co2injection_immiscible_ni_ecfv.cpp
Normal file
68
examples/co2injection_immiscible_ni_ecfv.cpp
Normal 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);
|
||||
}
|
||||
63
examples/co2injection_immiscible_ni_vcfv.cpp
Normal file
63
examples/co2injection_immiscible_ni_vcfv.cpp
Normal 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);
|
||||
}
|
||||
60
examples/co2injection_immiscible_vcfv.cpp
Normal file
60
examples/co2injection_immiscible_vcfv.cpp
Normal 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);
|
||||
}
|
||||
57
examples/co2injection_ncp_ecfv.cpp
Normal file
57
examples/co2injection_ncp_ecfv.cpp
Normal 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);
|
||||
}
|
||||
66
examples/co2injection_ncp_ni_ecfv.cpp
Normal file
66
examples/co2injection_ncp_ni_ecfv.cpp
Normal 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);
|
||||
}
|
||||
60
examples/co2injection_ncp_ni_vcfv.cpp
Normal file
60
examples/co2injection_ncp_ni_vcfv.cpp
Normal 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);
|
||||
}
|
||||
58
examples/co2injection_ncp_vcfv.cpp
Normal file
58
examples/co2injection_ncp_vcfv.cpp
Normal 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);
|
||||
}
|
||||
57
examples/co2injection_pvs_ecfv.cpp
Normal file
57
examples/co2injection_pvs_ecfv.cpp
Normal 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);
|
||||
}
|
||||
65
examples/co2injection_pvs_ni_ecfv.cpp
Normal file
65
examples/co2injection_pvs_ni_ecfv.cpp
Normal 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);
|
||||
}
|
||||
61
examples/co2injection_pvs_ni_vcfv.cpp
Normal file
61
examples/co2injection_pvs_ni_vcfv.cpp
Normal 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);
|
||||
}
|
||||
58
examples/co2injection_pvs_vcfv.cpp
Normal file
58
examples/co2injection_pvs_vcfv.cpp
Normal 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
52
examples/cuvette_pvs.cpp
Normal 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);
|
||||
}
|
||||
48
examples/diffusion_flash.cpp
Normal file
48
examples/diffusion_flash.cpp
Normal 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);
|
||||
}
|
||||
49
examples/diffusion_ncp.cpp
Normal file
49
examples/diffusion_ncp.cpp
Normal 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);
|
||||
}
|
||||
48
examples/diffusion_pvs.cpp
Normal file
48
examples/diffusion_pvs.cpp
Normal 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);
|
||||
}
|
||||
52
examples/finger_immiscible_ecfv.cpp
Normal file
52
examples/finger_immiscible_ecfv.cpp
Normal 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);
|
||||
}
|
||||
52
examples/finger_immiscible_vcfv.cpp
Normal file
52
examples/finger_immiscible_vcfv.cpp
Normal 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);
|
||||
}
|
||||
39
examples/fracture_discretefracture.cpp
Normal file
39
examples/fracture_discretefracture.cpp
Normal 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);
|
||||
}
|
||||
51
examples/groundwater_immiscible.cpp
Normal file
51
examples/groundwater_immiscible.cpp
Normal 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);
|
||||
}
|
||||
50
examples/infiltration_pvs.cpp
Normal file
50
examples/infiltration_pvs.cpp
Normal 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);
|
||||
}
|
||||
40
examples/lens_immiscible_ecfv_ad.cpp
Normal file
40
examples/lens_immiscible_ecfv_ad.cpp
Normal 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);
|
||||
}
|
||||
57
examples/lens_immiscible_ecfv_ad.hh
Normal file
57
examples/lens_immiscible_ecfv_ad.hh
Normal 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
|
||||
93
examples/lens_immiscible_ecfv_ad_23.cpp
Normal file
93
examples/lens_immiscible_ecfv_ad_23.cpp
Normal 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);
|
||||
}
|
||||
49
examples/lens_immiscible_ecfv_ad_cu1.cpp
Normal file
49
examples/lens_immiscible_ecfv_ad_cu1.cpp
Normal 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);
|
||||
}
|
||||
49
examples/lens_immiscible_ecfv_ad_cu2.cpp
Normal file
49
examples/lens_immiscible_ecfv_ad_cu2.cpp
Normal 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);
|
||||
}
|
||||
41
examples/lens_immiscible_ecfv_ad_main.cpp
Normal file
41
examples/lens_immiscible_ecfv_ad_main.cpp
Normal 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);
|
||||
}
|
||||
66
examples/lens_immiscible_ecfv_ad_trans.cpp
Normal file
66
examples/lens_immiscible_ecfv_ad_trans.cpp
Normal 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);
|
||||
}
|
||||
60
examples/lens_immiscible_vcfv_ad.cpp
Normal file
60
examples/lens_immiscible_vcfv_ad.cpp
Normal 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);
|
||||
}
|
||||
60
examples/lens_immiscible_vcfv_fd.cpp
Normal file
60
examples/lens_immiscible_vcfv_fd.cpp
Normal 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);
|
||||
}
|
||||
61
examples/lens_richards_ecfv.cpp
Normal file
61
examples/lens_richards_ecfv.cpp
Normal 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);
|
||||
}
|
||||
57
examples/lens_richards_vcfv.cpp
Normal file
57
examples/lens_richards_vcfv.cpp
Normal 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);
|
||||
}
|
||||
52
examples/obstacle_immiscible.cpp
Normal file
52
examples/obstacle_immiscible.cpp
Normal 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
53
examples/obstacle_ncp.cpp
Normal 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
55
examples/obstacle_pvs.cpp
Normal 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
53
examples/outflow_pvs.cpp
Normal 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);
|
||||
}
|
||||
55
examples/powerinjection_darcy_ad.cpp
Normal file
55
examples/powerinjection_darcy_ad.cpp
Normal 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);
|
||||
}
|
||||
55
examples/powerinjection_darcy_fd.cpp
Normal file
55
examples/powerinjection_darcy_fd.cpp
Normal 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);
|
||||
}
|
||||
55
examples/powerinjection_forchheimer_ad.cpp
Normal file
55
examples/powerinjection_forchheimer_ad.cpp
Normal 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);
|
||||
}
|
||||
55
examples/powerinjection_forchheimer_fd.cpp
Normal file
55
examples/powerinjection_forchheimer_fd.cpp
Normal 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);
|
||||
}
|
||||
66
examples/problems/co2injectionflash.hh
Normal file
66
examples/problems/co2injectionflash.hh
Normal 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
|
||||
648
examples/problems/co2injectionproblem.hh
Normal file
648
examples/problems/co2injectionproblem.hh
Normal 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
|
||||
520
examples/problems/co2ptflashproblem.hh
Normal file
520
examples/problems/co2ptflashproblem.hh
Normal 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
|
||||
642
examples/problems/cuvetteproblem.hh
Normal file
642
examples/problems/cuvetteproblem.hh
Normal 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
|
||||
385
examples/problems/diffusionproblem.hh
Normal file
385
examples/problems/diffusionproblem.hh
Normal 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
|
||||
562
examples/problems/fingerproblem.hh
Normal file
562
examples/problems/fingerproblem.hh
Normal 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
|
||||
663
examples/problems/fractureproblem.hh
Normal file
663
examples/problems/fractureproblem.hh
Normal 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
|
||||
403
examples/problems/groundwaterproblem.hh
Normal file
403
examples/problems/groundwaterproblem.hh
Normal 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
|
||||
476
examples/problems/infiltrationproblem.hh
Normal file
476
examples/problems/infiltrationproblem.hh
Normal 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
|
||||
643
examples/problems/lensproblem.hh
Normal file
643
examples/problems/lensproblem.hh
Normal 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
|
||||
583
examples/problems/obstacleproblem.hh
Normal file
583
examples/problems/obstacleproblem.hh
Normal 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
|
||||
379
examples/problems/outflowproblem.hh
Normal file
379
examples/problems/outflowproblem.hh
Normal 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
|
||||
441
examples/problems/powerinjectionproblem.hh
Normal file
441
examples/problems/powerinjectionproblem.hh
Normal 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
|
||||
763
examples/problems/reservoirproblem.hh
Normal file
763
examples/problems/reservoirproblem.hh
Normal 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
|
||||
488
examples/problems/richardslensproblem.hh
Normal file
488
examples/problems/richardslensproblem.hh
Normal 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
|
||||
604
examples/problems/waterairproblem.hh
Normal file
604
examples/problems/waterairproblem.hh
Normal 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
|
||||
65
examples/reservoir_blackoil_ecfv.cpp
Normal file
65
examples/reservoir_blackoil_ecfv.cpp
Normal 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);
|
||||
}
|
||||
59
examples/reservoir_blackoil_vcfv.cpp
Normal file
59
examples/reservoir_blackoil_vcfv.cpp
Normal 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);
|
||||
}
|
||||
64
examples/reservoir_ncp_ecfv.cpp
Normal file
64
examples/reservoir_ncp_ecfv.cpp
Normal 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);
|
||||
}
|
||||
69
examples/reservoir_ncp_vcfv.cpp
Normal file
69
examples/reservoir_ncp_vcfv.cpp
Normal 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
39
examples/tutorial1.cpp
Normal 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}@*/
|
||||
}
|
||||
333
examples/tutorial1problem.hh
Normal file
333
examples/tutorial1problem.hh
Normal 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
|
||||
|
||||
53
examples/waterair_pvs_ni.cpp
Normal file
53
examples/waterair_pvs_ni.cpp
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user