If there is an EDITNNCR entry and a NNC entry for the same cell pair then the EDITNNCR entry is not be represented inernally but we simply overwrite the transmissibility of the corresponding NNC entry. If there is an EDITNNC entry and an EDITNNCR entry for the same cell pair then the EDITNNC entry is removed while internalizing EDITNNCR. Order matters for EDITNNCR entries in the sense that later specified values will overwrite previous entries when we internalize. Note that similar to EDITNNC only the first 7 options are represented and the rest is ignored by OPM flow. Note that EDITNNCR entries for neighboring cells are ignored (like for EDITNNC).
448 lines
8.6 KiB
C++
448 lines
8.6 KiB
C++
/*
|
|
Copyright 2015 IRIS
|
|
|
|
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 3 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/>.
|
|
*/
|
|
|
|
#include <opm/input/eclipse/EclipseState/Grid/NNC.hpp>
|
|
#include <opm/input/eclipse/Parser/Parser.hpp>
|
|
#include <opm/input/eclipse/Deck/Deck.hpp>
|
|
#include <opm/input/eclipse/EclipseState/Grid/GridDims.hpp>
|
|
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
|
#include <opm/input/eclipse/Units/Units.hpp>
|
|
|
|
#define BOOST_TEST_MODULE NNCTests
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
using namespace Opm;
|
|
|
|
|
|
const std::string no_nnc_input = R"(
|
|
RUNSPEC
|
|
|
|
OIL
|
|
GAS
|
|
WATER
|
|
|
|
|
|
DIMENS
|
|
10 10 1 /
|
|
|
|
GRID
|
|
|
|
DXV
|
|
10*1000.0
|
|
/
|
|
|
|
DYV
|
|
10*1000.0
|
|
/
|
|
|
|
DZ
|
|
100*20.0
|
|
/
|
|
|
|
TOPS
|
|
100*10
|
|
/
|
|
|
|
PORO
|
|
100*0.15 /
|
|
)";
|
|
|
|
const std::string actnum = R"(
|
|
RUNSPEC
|
|
|
|
OIL
|
|
GAS
|
|
WATER
|
|
|
|
|
|
DIMENS
|
|
10 10 1 /
|
|
|
|
GRID
|
|
|
|
DXV
|
|
10*1000.0
|
|
/
|
|
|
|
DYV
|
|
10*1000.0
|
|
/
|
|
|
|
DZ
|
|
100*20.0
|
|
/
|
|
|
|
TOPS
|
|
100*10
|
|
/
|
|
|
|
ACTNUM
|
|
10*0 90*1
|
|
/
|
|
|
|
NNC
|
|
1 1 1 1 3 1 0.5 / -- Inactive cell
|
|
3 1 1 3 3 1 0.5 / -- Inactive cell
|
|
2 2 1 3 3 1 1.0 / -- Valid
|
|
100 100 100 200 200 200 1.0 / -- Very invalid
|
|
/
|
|
|
|
PORO
|
|
100*0.15 /
|
|
|
|
EDIT
|
|
|
|
EDITNNC
|
|
5 1 1 1 5 3 0.5 / -- Inactive cell
|
|
2 2 1 3 3 1 0.5 / -- Valid - coupled to NNC
|
|
4 4 1 5 5 1 2.0 / -- Valid
|
|
-1 4 4 -1 7 7 1.0 / -- Very invalid
|
|
/
|
|
|
|
)";
|
|
|
|
|
|
|
|
|
|
const std::string nnc_input = R"(
|
|
RUNSPEC
|
|
|
|
OIL
|
|
GAS
|
|
WATER
|
|
|
|
|
|
DIMENS
|
|
10 10 1 /
|
|
|
|
GRID
|
|
|
|
DXV
|
|
10*1000.0
|
|
/
|
|
|
|
DYV
|
|
10*1000.0
|
|
/
|
|
|
|
DZ
|
|
100*20.0
|
|
/
|
|
|
|
TOPS
|
|
100*10
|
|
/
|
|
|
|
PORO
|
|
100*0.15 /
|
|
|
|
NNC
|
|
1 1 1 2 1 1 0.5 /
|
|
1 1 1 1 2 1 1.0 /
|
|
/
|
|
|
|
NNC
|
|
1 1 1 2 1 1 0.5 /
|
|
1 2 1 1 2 1 1.0 /
|
|
/
|
|
)";
|
|
|
|
|
|
|
|
const std::string editnnc_input = R"(
|
|
RUNSPEC
|
|
|
|
OIL
|
|
GAS
|
|
WATER
|
|
|
|
|
|
DIMENS
|
|
10 10 1 /
|
|
|
|
GRID
|
|
|
|
NNC
|
|
7 1 1 3 1 1 0.1 /
|
|
3 1 1 5 1 1 0.1 /
|
|
/
|
|
|
|
|
|
DXV
|
|
10*1000.0
|
|
/
|
|
|
|
DYV
|
|
10*1000.0
|
|
/
|
|
|
|
DZ
|
|
100*20.0
|
|
/
|
|
|
|
TOPS
|
|
100*10
|
|
/
|
|
|
|
PORO
|
|
100*0.15 /
|
|
|
|
EDIT
|
|
|
|
|
|
EDITNNC
|
|
5 1 1 3 1 1 2.0 /
|
|
3 1 1 1 1 1 0.1 /
|
|
1 1 1 1 2 1 0.01 / -- This is ignored because the two cells are ijk neighbours
|
|
2 1 1 2 3 1 0.2 /
|
|
/
|
|
|
|
EDITNNC
|
|
1 1 1 2 1 1 0.1 / -- Ignored
|
|
2 1 1 2 3 1 0.3 /
|
|
/
|
|
)";
|
|
|
|
const std::string editnncr_input = R"(
|
|
RUNSPEC
|
|
|
|
OIL
|
|
GAS
|
|
WATER
|
|
|
|
|
|
DIMENS
|
|
10 10 1 /
|
|
|
|
GRID
|
|
|
|
NNC
|
|
7 1 1 3 1 1 0.1 / -- Transmissibility will be overwritten with 10 by EDITNNCR
|
|
3 1 1 5 1 1 0.1 /
|
|
/
|
|
|
|
|
|
DXV
|
|
10*1000.0
|
|
/
|
|
|
|
DYV
|
|
10*1000.0
|
|
/
|
|
|
|
DZ
|
|
100*20.0
|
|
/
|
|
|
|
TOPS
|
|
100*10
|
|
/
|
|
|
|
PORO
|
|
100*0.15 /
|
|
|
|
EDIT
|
|
|
|
EDITNNC
|
|
5 1 1 3 1 1 2.0 / -- Will be removed after internalization as there is an NNC
|
|
3 1 1 1 1 1 0.1 / -- stays internalized
|
|
2 1 1 2 3 1 0.3 / -- Will be removed after internalization as there is an EDTNNCR
|
|
/
|
|
|
|
EDITNNCR
|
|
8 1 1 3 1 1 2.0 /
|
|
1 1 1 1 2 1 0.01 / -- This is ignored because the two cells are ijk neighbours
|
|
2 1 1 2 3 1 0.2 / -- Overwritten with 0.3 by next entry
|
|
7 1 1 3 1 1 10 / -- Will overwrite entry in NNC
|
|
/
|
|
|
|
EDITNNCR
|
|
1 1 1 2 1 1 0.1 / -- Ignored
|
|
2 1 1 2 3 1 0.3 / -- Overwrites previous value
|
|
/
|
|
)";
|
|
|
|
|
|
std::optional<NNCdata> find_nnc(const std::vector<NNCdata>& v, std::size_t c1, std::size_t c2) {
|
|
if (c1 > c2)
|
|
return find_nnc(v, c2, c1);
|
|
|
|
auto iter = std::find_if(v.begin(), v.end(), [c1,c2](const NNCdata& nnc) { return nnc.cell1 == c1 && nnc.cell2 == c2; });
|
|
if (iter != v.end())
|
|
return *iter;
|
|
|
|
return {};
|
|
}
|
|
|
|
void check_edit_nnc(const std::vector<NNCdata>& v, std::size_t c1, std::size_t c2, double t) {
|
|
const auto& nnc = find_nnc(v, c1, c2);
|
|
BOOST_REQUIRE(nnc.has_value());
|
|
BOOST_CHECK_CLOSE(nnc->trans, t , 1e-6);
|
|
}
|
|
|
|
void check_nnc(const std::vector<NNCdata>& v, std::size_t c1, std::size_t c2, double t) {
|
|
check_edit_nnc(v, c1, c2, t*Opm::Metric::Transmissibility);
|
|
}
|
|
|
|
bool has_nnc(const std::vector<NNCdata>& v, std::size_t c1, std::size_t c2) {
|
|
const auto& nnc = find_nnc(v, c1, c2);
|
|
return nnc.has_value();
|
|
}
|
|
|
|
void check_order(const std::vector<NNCdata>& d) {
|
|
for (const auto& nnc : d)
|
|
BOOST_CHECK(nnc.cell1 <= nnc.cell2);
|
|
|
|
if (d.size() <= 1)
|
|
return;
|
|
|
|
for (std::size_t index=1; index < d.size(); index++) {
|
|
const auto& nnc1 = d[index - 1];
|
|
const auto& nnc2 = d[index];
|
|
|
|
if (nnc1 < nnc2)
|
|
continue;
|
|
|
|
BOOST_CHECK_EQUAL(nnc1.cell1, nnc2.cell1);
|
|
BOOST_CHECK_EQUAL(nnc1.cell2, nnc2.cell2);
|
|
}
|
|
}
|
|
|
|
|
|
void check_order(const NNC& nnc) {
|
|
check_order(nnc.input());
|
|
check_order(nnc.edit());
|
|
check_order(nnc.editr());
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(noNNC)
|
|
{
|
|
Parser parser;
|
|
auto deck = parser.parseString(no_nnc_input);
|
|
EclipseState eclipseState(deck);
|
|
const auto& nnc = eclipseState.getInputNNC();
|
|
check_order(nnc);
|
|
BOOST_CHECK(!eclipseState.hasInputNNC());
|
|
BOOST_CHECK(nnc.input().empty());
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(readDeck)
|
|
{
|
|
Parser parser;
|
|
auto deck = parser.parseString(nnc_input);
|
|
EclipseState eclipseState(deck);
|
|
const auto& grid = eclipseState.getInputGrid();
|
|
const auto& nnc = eclipseState.getInputNNC();
|
|
check_order(nnc);
|
|
BOOST_CHECK(!nnc.input().empty());
|
|
const std::vector<NNCdata>& nncdata = nnc.input();
|
|
|
|
// test the NNCs in nnc.DATA
|
|
BOOST_CHECK_EQUAL(nncdata.size(), 4);
|
|
check_nnc(nncdata, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(1,0,0), 0.50);
|
|
check_nnc(nncdata, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(0,1,0), 1.00);
|
|
|
|
const auto& loc = nnc.input_location( nncdata[0] );
|
|
BOOST_CHECK_EQUAL(loc.keyword, "NNC");
|
|
}
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(noNNC_EDIT)
|
|
{
|
|
Parser parser;
|
|
auto deck = parser.parseString(no_nnc_input);
|
|
EclipseState eclipseState(deck);
|
|
const auto& editnnc = eclipseState.getInputNNC();
|
|
BOOST_CHECK(editnnc.edit().empty());
|
|
BOOST_CHECK(editnnc.editr().empty());
|
|
}
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(readDeck_EDIT)
|
|
{
|
|
Parser parser;
|
|
auto deck = parser.parseString(editnnc_input);
|
|
EclipseGrid grid(10,10,10);
|
|
|
|
NNC nnc(grid, deck);
|
|
const std::vector<NNCdata>& data = nnc.edit();
|
|
|
|
BOOST_CHECK_EQUAL(data.size(), 2); //neighbouring connections in EDITNNC are ignored
|
|
BOOST_CHECK(!has_nnc(data, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(0,1,0)));
|
|
BOOST_CHECK(!has_nnc(data, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(1,0,0)));
|
|
|
|
check_order(nnc);
|
|
check_edit_nnc(data, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(0,0,0), 0.1);
|
|
check_edit_nnc(data, grid.getGlobalIndex(1,0,0), grid.getGlobalIndex(1,2,0), 0.06);
|
|
|
|
const std::vector<NNCdata>& input = nnc.input();
|
|
check_nnc(input, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(4,0,0), 0.20);
|
|
check_nnc(input, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(6,0,0), 0.10);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(readDeck_EDITR)
|
|
{
|
|
Parser parser;
|
|
auto deck = parser.parseString(editnncr_input);
|
|
EclipseGrid grid(10,10,10);
|
|
|
|
NNC nnc(grid, deck);
|
|
const std::vector<NNCdata>& input = nnc.input();
|
|
const std::vector<NNCdata>& edit = nnc.edit();
|
|
const std::vector<NNCdata>& editr = nnc.editr();
|
|
check_order(nnc);
|
|
|
|
BOOST_CHECK_EQUAL(input.size(), 2);
|
|
check_nnc(input, grid.getGlobalIndex(6,0,0), grid.getGlobalIndex(2,0,0), 10);
|
|
check_nnc(input, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(4,0,0), 0.1*2.0);
|
|
|
|
BOOST_CHECK_EQUAL(edit.size(), 1);
|
|
BOOST_CHECK(!has_nnc(edit, grid.getGlobalIndex(4,0,0), grid.getGlobalIndex(2,0,0)));
|
|
check_edit_nnc(edit, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(0,0,0), 0.1);
|
|
|
|
BOOST_CHECK_EQUAL(editr.size(), 2);
|
|
BOOST_CHECK(!has_nnc(editr, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(0,1,0)));
|
|
BOOST_CHECK(!has_nnc(editr, grid.getGlobalIndex(6,0,0), grid.getGlobalIndex(2,0,0)));
|
|
BOOST_CHECK(!has_nnc(editr, grid.getGlobalIndex(0,0,0), grid.getGlobalIndex(1,0,0)));
|
|
check_nnc(editr, grid.getGlobalIndex(1,0,0), grid.getGlobalIndex(1,2,0), 0.3);
|
|
check_nnc(editr, grid.getGlobalIndex(2,0,0), grid.getGlobalIndex(7,0,0), 2.0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(ACTNUM)
|
|
{
|
|
Parser parser;
|
|
auto deck = parser.parseString(actnum);
|
|
EclipseState eclipseState(deck);
|
|
const auto& grid = eclipseState.getInputGrid();
|
|
const auto& editnnc = eclipseState.getInputNNC();
|
|
const auto& edit = editnnc.edit();
|
|
const auto& input = editnnc.input();
|
|
BOOST_CHECK_EQUAL(edit.size(), 1);
|
|
BOOST_CHECK_EQUAL(input.size(), 1);
|
|
check_nnc(input, grid.getGlobalIndex(1,1,0), grid.getGlobalIndex(2,2,0), 0.5);
|
|
check_edit_nnc(edit, grid.getGlobalIndex(3,3,0), grid.getGlobalIndex(4,4,0), 2.0);
|
|
check_order(editnnc);
|
|
}
|
|
|
|
|