Skip to content

Commit 217a830

Browse files
committed
Add a unit test for CombinedGridWellGraph
1 parent fcf679a commit 217a830

2 files changed

Lines changed: 175 additions & 0 deletions

File tree

CMakeLists_files.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ list(APPEND TEST_SOURCE_FILES
9999
tests/test_repairzcorn.cpp
100100
tests/test_sparsetable.cpp
101101
tests/test_subgridpart.cpp
102+
tests/cpgrid/combinedgridwellgraph_test.cpp
102103
tests/cpgrid/distribution_test.cpp
103104
tests/cpgrid/entityrep_test.cpp
104105
tests/cpgrid/entity_test.cpp
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2+
// vi: set et ts=4 sw=4 sts=4:
3+
/*
4+
Copyright 2026 Equinor ASA.
5+
6+
This file is part of the Open Porous Media project (OPM).
7+
8+
OPM is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation, either version 3 of the License, or
11+
(at your option) any later version.
12+
13+
OPM is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with OPM. If not, see <http://www.gnu.org/licenses/>.
20+
21+
Consult the COPYING file in the top-level source directory of this
22+
module for the precise wording of the license and the list of
23+
copyright holders.
24+
*/
25+
26+
#include <config.h>
27+
28+
#include <dune/common/version.hh>
29+
30+
#define BOOST_TEST_MODULE CombinedGridWellGraph
31+
#define BOOST_TEST_NO_MAIN
32+
#include <boost/test/unit_test.hpp>
33+
#include <opm/grid/CpGrid.hpp>
34+
#include <opm/grid/common/GridEnums.hpp>
35+
#include <opm/grid/common/ZoltanGraphFunctions.hpp>
36+
#include <opm/grid/utility/OpmWellType.hpp>
37+
38+
#if HAVE_OPM_COMMON
39+
#include <opm/input/eclipse/Deck/Deck.hpp>
40+
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
41+
#include <opm/input/eclipse/Parser/Parser.hpp>
42+
#include <opm/input/eclipse/Schedule/Well/Connection.hpp>
43+
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
44+
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
45+
#endif
46+
47+
#include <algorithm>
48+
#include <numeric>
49+
50+
#if HAVE_OPM_COMMON
51+
namespace {
52+
// create Wells, we only use well name and cell locations
53+
auto createConnection (int i, int j, int k)
54+
{
55+
return Opm::Connection(i,j,k,0, 0,Opm::Connection::State::OPEN,
56+
Opm::Connection::Direction::Z,
57+
Opm::Connection::CTFKind::DeckValue, 0,
58+
5.,Opm::Connection::CTFProperties(),0,false);
59+
}
60+
auto createWell (const std::string& name)
61+
{
62+
using namespace Opm;
63+
return Dune::cpgrid::OpmWellType(name,name,0,0,0,0,0.,WellType(),
64+
Well::ProducerCMode(),Connection::Order(),UnitSystem(),
65+
0.,0.,false,false,0,Well::GasInflowEquation());
66+
};
67+
} // end anonymous namespace
68+
#endif
69+
70+
BOOST_AUTO_TEST_CASE(CombinedGridWellGraph)
71+
{
72+
///! beware, test functionality, not implementation
73+
74+
/// construct CombinedGridWellGraph
75+
Dune::CpGrid grid;
76+
std::array<int, 3> dims { 3, 3, 1 };
77+
std::array<double, 3> size { 1., 1., 1. };
78+
grid.createCartesian(dims, size);
79+
80+
auto wellCon = std::make_shared<Opm::WellConnections>(); // do not confuse with Dune::cpgrid::WellConnections
81+
std::vector<Dune::cpgrid::OpmWellType> wells;
82+
wellCon->add(createConnection(0,0,0));
83+
wellCon->add(createConnection(1,0,0));
84+
wellCon->add(createConnection(2,0,0));
85+
wells.push_back(createWell("first_row"));
86+
wells[0].updateConnections(wellCon,true);
87+
88+
wellCon = std::make_shared<Opm::WellConnections>(); // reset
89+
wellCon->add(createConnection(0,0,0));
90+
wellCon->add(createConnection(1,1,0));
91+
wellCon->add(createConnection(2,2,0));
92+
wells.push_back(createWell("diag"));
93+
wells[1].updateConnections(wellCon,true);
94+
95+
// std::vector<OpmWellType> wells;
96+
std::unordered_map<std::string, std::set<int>> possibleFutureConnections;
97+
std::vector<double> transmissibilities{0., 1., 2., 0., 0., 3., 4., 0., 0., 5., 6., 0., // X
98+
0., 0., 0.,11.,12.,13.,14.,15.,16., 0., 0., 0., // Y
99+
0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.}; // Z
100+
Dune::cpgrid::CombinedGridWellGraph gridWellGraph(grid, &wells, possibleFutureConnections,
101+
transmissibilities.data(), false, Dune::EdgeWeightMethod::defaultTransEdgeWgt);
102+
const auto& wellEdges = gridWellGraph.getWellsGraph();
103+
104+
/// log transmissibilities do not affect well connections
105+
{
106+
Dune::cpgrid::CombinedGridWellGraph logGridWellGraph(grid, &wells, possibleFutureConnections,
107+
transmissibilities.data(), false, Dune::EdgeWeightMethod::logTransEdgeWgt);
108+
const auto& logWellEdges = logGridWellGraph.getWellsGraph();
109+
BOOST_REQUIRE(wellEdges == logWellEdges);
110+
}
111+
112+
/// connections of every well are interconnected
113+
BOOST_REQUIRE(wellEdges.size() == 9); // all vertices
114+
std::set<int> edges{1, 2, 4, 8}; // both wells have the cell 0
115+
BOOST_REQUIRE(wellEdges[0].size() == 4);
116+
BOOST_REQUIRE(wellEdges[0] == edges);
117+
edges = std::set<int>{0,2};
118+
BOOST_REQUIRE(wellEdges[1].size() == 2);
119+
BOOST_REQUIRE(wellEdges[1] == edges);
120+
edges = std::set<int>{0,1};
121+
BOOST_REQUIRE(wellEdges[2].size() == 2);
122+
BOOST_REQUIRE(wellEdges[2] == edges);
123+
BOOST_REQUIRE(wellEdges[3].size() == 0);
124+
edges = std::set<int>{0,8};
125+
BOOST_REQUIRE(wellEdges[4].size() == 2);
126+
BOOST_REQUIRE(wellEdges[4] == edges);
127+
BOOST_REQUIRE(wellEdges[5].size() == 0);
128+
BOOST_REQUIRE(wellEdges[6].size() == 0);
129+
BOOST_REQUIRE(wellEdges[7].size() == 0);
130+
edges = std::set<int>{0,4};
131+
BOOST_REQUIRE(wellEdges[8].size() == 2);
132+
BOOST_REQUIRE(wellEdges[8] == edges);
133+
134+
/// well edge weight is by defaul equal to the sum of all grid edges
135+
auto wellEdgeWeight = calculateWellEdgeWeight<float>(grid, gridWellGraph);
136+
// the sum (102) gets multipied by 1e18 to accomodate partitioners that use integral weights (Metis)
137+
BOOST_REQUIRE(std::abs(wellEdgeWeight / 1e18 - 102.) < 1e-5);
138+
139+
// a positive multiplier changes the weight from sum_of_faces to multiplier_\times_average_face
140+
gridWellGraph.setMultiplyWellConnectivities(21.); // there are 42 grid edges in total
141+
wellEdgeWeight = calculateWellEdgeWeight<float>(grid, gridWellGraph);
142+
BOOST_REQUIRE(std::abs(wellEdgeWeight / 1e18 - 51.) < 1e-5);
143+
144+
/// edges from well connections overwrite grid edges
145+
int neighborCounter{0};
146+
std::vector<uint> gID(9), nborGID(32, 0); // 32=2x(12 inner faces + 4 new connections due to wells)
147+
ZOLTAN_ID_PTR nborGIDData = nborGID.data(), gIDData = gID.data();
148+
std::vector<float> ewgts(32, 0.);
149+
for (int i=0; i<9; ++i) {
150+
gID[i] = i;
151+
fillNBORGIDAndWeightsForSpecificCellAndIncrementNeighborCounterForGridWithWells(gridWellGraph, i, gIDData, neighborCounter, nborGIDData, ewgts.data(), wellEdgeWeight);
152+
}
153+
154+
BOOST_REQUIRE(neighborCounter == 32);
155+
// check if the well edge weights are at correct places
156+
for (const auto i : std::vector<int>{0,1,2,3, 5,6, 8,9, 14,15, 28,29}) {
157+
BOOST_REQUIRE(ewgts[i] == wellEdgeWeight);
158+
}
159+
const auto weightSum = std::accumulate(ewgts.begin(), ewgts.end(), 0.);
160+
// sum of edge weights is 102, there are 6 well connections in total and grid edges {1,2} were overwritten
161+
BOOST_REQUIRE(std::abs(weightSum/1e18 - 2*(102 + 6*wellEdgeWeight/1e18 - 1 - 2)) < 1e-3);
162+
}
163+
164+
bool init_unit_test_func()
165+
{
166+
return true;
167+
}
168+
169+
int main(int argc, char** argv)
170+
{
171+
Dune::MPIHelper::instance(argc, argv);
172+
boost::unit_test::unit_test_main(&init_unit_test_func,
173+
argc, argv);
174+
}

0 commit comments

Comments
 (0)