|
| 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