Match Connection-to-Region in Terms of Global Cell Indices

The simulator reports data::Connection objects tied to global
Cartesian cell indices whence using the 'active_index' leads to
match failures and incorrect rate attribution at the region level.
In one field case we got region level rates and cumulatives, e.g.,
ROPR and ROPT, of zero reported to the summary file when the
expected values should be non-zero.
This commit is contained in:
Bård Skaflestad 2023-09-22 10:09:59 +02:00
parent e3fd90f965
commit ae2f052b37
2 changed files with 284 additions and 28 deletions

View File

@ -40,12 +40,12 @@ RegionCache::RegionCache(const std::set<std::string>& fip_regions, const FieldPr
continue;
for (const auto& c : connections) {
if (grid.cellActive(c.getI(), c.getJ(), c.getK())) {
size_t active_index = grid.activeIndex(c.getI(), c.getJ(), c.getK());
if (grid.cellActive(c.global_index())) {
size_t active_index = grid.activeIndex(c.global_index());
int region_id = fip_region[active_index];
auto key = std::make_pair(fip_name, region_id);
auto& well_index_list = this->connection_map[ key ];
well_index_list.push_back( { well.name() , active_index } );
well_index_list.emplace_back(well.name(), c.global_index());
}
}

View File

@ -22,57 +22,313 @@
#define BOOST_TEST_MODULE RegionCache
#include <boost/test/unit_test.hpp>
#include <stdexcept>
#include <unordered_set>
#include <opm/output/eclipse/RegionCache.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/Python/Python.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/output/eclipse/RegionCache.hpp>
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>
#include <opm/output/eclipse/RegionCache.hpp>
#include <cstddef>
#include <memory>
#include <stdexcept>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace Opm;
namespace {
const char* path = "summary_deck.DATA";
Opm::Deck summaryDeck()
{
return Opm::Parser{}.parseFile("summary_deck.DATA");
}
bool cmp_list(const std::vector<std::string>& l1, const std::vector<std::string>& l2) {
bool cmp_list(const std::vector<std::string>& l1,
const std::vector<std::string>& l2)
{
std::unordered_set<std::string> s1(l1.begin(), l1.end());
std::unordered_set<std::string> s2(l2.begin(), l2.end());
return s1 == s2;
}
} // Anonymous namespace
BOOST_AUTO_TEST_CASE(create)
{
const auto deck = summaryDeck();
const auto es = Opm::EclipseState { deck };
const auto schedule = Opm::Schedule { deck, es, std::make_shared<Opm::Python>() };
const auto& grid = es.getInputGrid();
const auto regCache = Opm::out::RegionCache {
{"FIPNUM"}, es.fieldProps(), grid, schedule
};
BOOST_AUTO_TEST_CASE(create) {
auto python = std::make_shared<Python>();
Parser parser;
Deck deck( parser.parseFile( path ));
EclipseState es(deck);
const EclipseGrid& grid = es.getInputGrid();
Schedule schedule( deck, es, python);
out::RegionCache rc({"FIPNUM"}, es.fieldProps(), grid, schedule);
{
const auto& empty = rc.connections( "FIPNUM", 4 );
const auto& empty = regCache.connections( "FIPNUM", 4 );
BOOST_CHECK_EQUAL( empty.size() , 0U );
}
{
const auto& top_layer = rc.connections( "FIPNUM", 1 );
const auto& top_layer = regCache.connections( "FIPNUM", 1 );
BOOST_CHECK_EQUAL( top_layer.size() , 4U );
{
auto pair = top_layer[0];
BOOST_CHECK_EQUAL( pair.first , "W_1");
BOOST_CHECK_EQUAL( pair.second , grid.activeIndex( 0,0,0));
BOOST_CHECK_EQUAL( pair.second , grid.getGlobalIndex(0, 0, 0));
}
}
BOOST_CHECK( rc.wells("FIPXYZ", 100).empty() );
BOOST_CHECK( rc.wells("FIPXYZ", 1).empty() );
BOOST_CHECK( rc.wells("FIPNUM", 100).empty() );
BOOST_CHECK( cmp_list(rc.wells("FIPNUM", 1), {"W_1", "W_2", "W_3", "W_4"}));
BOOST_CHECK( cmp_list(rc.wells("FIPNUM", 11), {"W_6"}));
BOOST_CHECK( regCache.wells("FIPXYZ", 100).empty() );
BOOST_CHECK( regCache.wells("FIPXYZ", 1).empty() );
BOOST_CHECK( regCache.wells("FIPNUM", 100).empty() );
BOOST_CHECK( cmp_list(regCache.wells("FIPNUM", 1), {"W_1", "W_2", "W_3", "W_4"}));
BOOST_CHECK( cmp_list(regCache.wells("FIPNUM", 11), {"W_6"}));
}
BOOST_AUTO_TEST_CASE(InactiveLayers)
{
const auto deck = Opm::Parser{}.parseString(R"(RUNSPEC
DIMENS
5 5 6 /
START
22 'SEP' 2023 /
GRID
DXV
5*100 /
DYV
5*100 /
DZV
6*10 /
DEPTHZ
36*2000 /
ACTNUM
25*1 -- K=1
25*1 -- K=2
25*0 -- K=3
25*1 -- K=4
25*1 -- K=5
10*1
1 1 0 1 1 -- ACTNUM(3, 3, 6) == 0
10*1 / -- K=6
PERMX
150*100 /
PERMY
150*100 /
PERMZ
150*10 /
PORO
150*0.3 /
REGIONS
FIPNUM
25*6 25*1 25*2 25*3 25*4 25*5 /
FIPTEST1
1 7 2 9 6
1 7 2 9 6
1 7 2 9 6
1 7 2 9 6
1 7 2 9 6 -- K=1
--
7 2 9 6 1
7 2 9 6 1
7 2 9 6 1
7 2 9 6 1
7 2 9 6 1 -- K=2
--
2 9 6 1 7
2 9 6 1 7
2 9 6 1 7
2 9 6 1 7
2 9 6 1 7 -- K=3
--
9 6 1 7 2
9 6 1 7 2
9 6 1 7 2
9 6 1 7 2
9 6 1 7 2 -- K=4
--
6 1 7 2 9
6 1 7 2 9
6 1 7 2 9
6 1 7 2 9
6 1 7 2 9 -- K=5
--
1 7 2 9 6
1 7 2 9 6
1 7 2 9 6
1 7 2 9 6
1 7 2 9 6 / -- K=6
SCHEDULE
WELSPECS
'P' 'G' 3 3 2005.0 'OIL' /
/
COMPDAT
'P' 2* 1 6 /
/
TSTEP
10 /
END
)");
const auto es = Opm::EclipseState { deck };
const auto schedule = Opm::Schedule { deck, es, std::make_shared<Opm::Python>() };
const auto& grid = es.getInputGrid();
const auto regCache = Opm::out::RegionCache {
std::set<std::string>{"FIPNUM", "FIPTEST1"},
es.fieldProps(), grid, schedule
};
const auto expect_conn = std::vector {
std::size_t { 12}, // (2, 2, 0), FIP: {NUM = 6, TEST1 = 2 }
std::size_t { 37}, // (2, 2, 1), FIP: {NUM = 1, TEST1 = 9 }
std::size_t { 87}, // (2, 2, 3), FIP: {NUM = 3, TEST1 = 1 }
std::size_t {112}, // (2, 2, 4), FIP: {NUM = 4, TEST1 = 7 }
};
{
const auto& wconn = schedule.back().wells("P").getConnections();
BOOST_CHECK_EQUAL(wconn.size(), expect_conn.size());
for (auto i = 0*wconn.size(); i < wconn.size(); ++i) {
BOOST_CHECK_EQUAL(wconn[i].global_index(), expect_conn[i]);
}
}
// FIPNUM
{
// FIPNUM = 1
{
const auto& conns = regCache.connections("FIPNUM", 1);
BOOST_CHECK_EQUAL(conns.size(), std::size_t{1});
const auto& [well, cellIx] = conns.front();
BOOST_CHECK_EQUAL(well, "P");
BOOST_CHECK_EQUAL(cellIx, expect_conn[1]);
}
// FIPNUM = 2
{
const auto& conns = regCache.connections("FIPNUM", 2);
BOOST_CHECK_MESSAGE(conns.empty(), "There must be no connections for FIPNUM=2");
}
// FIPNUM = 3
{
const auto& conns = regCache.connections("FIPNUM", 3);
BOOST_CHECK_EQUAL(conns.size(), std::size_t{1});
const auto& [well, cellIx] = conns.front();
BOOST_CHECK_EQUAL(well, "P");
BOOST_CHECK_EQUAL(cellIx, expect_conn[2]);
}
// FIPNUM = 4
{
const auto& conns = regCache.connections("FIPNUM", 4);
BOOST_CHECK_EQUAL(conns.size(), std::size_t{1});
const auto& [well, cellIx] = conns.front();
BOOST_CHECK_EQUAL(well, "P");
BOOST_CHECK_EQUAL(cellIx, expect_conn[3]);
}
// FIPNUM = 5
{
const auto& conns = regCache.connections("FIPNUM", 5);
BOOST_CHECK_MESSAGE(conns.empty(), "There must be no connections for FIPNUM=5");
}
// FIPNUM = 6
{
const auto& conns = regCache.connections("FIPNUM", 6);
BOOST_CHECK_EQUAL(conns.size(), std::size_t{1});
const auto& [well, cellIx] = conns.front();
BOOST_CHECK_EQUAL(well, "P");
BOOST_CHECK_EQUAL(cellIx, expect_conn[0]);
}
}
// FIPTEST1
{
// FIPTEST1 = 1
{
const auto& conns = regCache.connections("FIPTEST1", 1);
BOOST_CHECK_EQUAL(conns.size(), std::size_t{1});
const auto& [well, cellIx] = conns.front();
BOOST_CHECK_EQUAL(well, "P");
BOOST_CHECK_EQUAL(cellIx, expect_conn[2]);
}
// FIPTEST1 = 2
{
const auto& conns = regCache.connections("FIPTEST1", 2);
BOOST_CHECK_EQUAL(conns.size(), std::size_t{1});
const auto& [well, cellIx] = conns.front();
BOOST_CHECK_EQUAL(well, "P");
BOOST_CHECK_EQUAL(cellIx, expect_conn[0]);
}
// FIPTEST1 = 3
{
const auto& conns = regCache.connections("FIPTEST1", 3);
BOOST_CHECK_MESSAGE(conns.empty(), "There must be no connections for FIPTEST1=3");
}
// FIPTEST1 = 4
{
const auto& conns = regCache.connections("FIPTEST1", 4);
BOOST_CHECK_MESSAGE(conns.empty(), "There must be no connections for FIPTEST1=4");
}
// FIPTEST1 = 5
{
const auto& conns = regCache.connections("FIPTEST1", 5);
BOOST_CHECK_MESSAGE(conns.empty(), "There must be no connections for FIPTEST1=5");
}
// FIPTEST1 = 6
{
const auto& conns = regCache.connections("FIPTEST1", 6);
BOOST_CHECK_MESSAGE(conns.empty(), "There must be no connections for FIPTEST1=6");
}
// FIPTEST1 = 7
{
const auto& conns = regCache.connections("FIPTEST1", 7);
BOOST_CHECK_EQUAL(conns.size(), std::size_t{1});
const auto& [well, cellIx] = conns.front();
BOOST_CHECK_EQUAL(well, "P");
BOOST_CHECK_EQUAL(cellIx, expect_conn[3]);
}
// FIPTEST1 = 8
{
const auto& conns = regCache.connections("FIPTEST1", 8);
BOOST_CHECK_MESSAGE(conns.empty(), "There must be no connections for FIPTEST1=8");
}
// FIPTEST1 = 9
{
const auto& conns = regCache.connections("FIPTEST1", 9);
BOOST_CHECK_EQUAL(conns.size(), std::size_t{1});
const auto& [well, cellIx] = conns.front();
BOOST_CHECK_EQUAL(well, "P");
BOOST_CHECK_EQUAL(cellIx, expect_conn[1]);
}
}
}