Fix ISEG[0] Output Order

The value in ISEG[0] does not necessarily correspond to the search
order of that segment.  Rather, ISEG[0] is the depth-first ordering
of the segment search tree when traversing kick-off branches before
the main stem from which those branches kick off.
This commit is contained in:
Bård Skaflestad
2023-09-29 18:13:06 +02:00
parent 1d5ae49cdc
commit d7edd7c2ee
2 changed files with 156 additions and 6 deletions

View File

@@ -565,7 +565,7 @@ namespace {
const auto& segment = welSegSet[ind];
auto segNumber = segment.segmentNumber();
auto iS = (segNumber-1)*noElmSeg;
iSeg[iS + Ix::SegNo] = welSegSet[orderedSegmentNo[ind]].segmentNumber();
iSeg[ind*noElmSeg + Ix::SegNo] = welSegSet[orderedSegmentNo[ind]].segmentNumber();
iSeg[iS + Ix::OutSeg] = segment.outletSegment();
iSeg[iS + Ix::InSegCurBranch] = (inflowSegmentCurBranch(well.name(), welSegSet, ind) == 0) ? 0 : welSegSet[inflowSegmentCurBranch(well.name(), welSegSet, ind)].segmentNumber();
iSeg[iS + Ix::BranchNo] = segment.branchNumber();
@@ -838,6 +838,7 @@ namespace {
bool haveWellRes = (well.getStatus() != Opm::Well::Status::SHUT) ? (wRatesIt != wr.end()) : false;
const auto volFromLengthUnitConv = units.from_si(M::length, units.from_si(M::length, units.from_si(M::length, 1.)));
const auto areaFromLengthUnitConv = units.from_si(M::length, units.from_si(M::length, 1.));
//
//Initialize temporary variables
double temp_o = 0.;
@@ -845,10 +846,9 @@ namespace {
double temp_g = 0.;
// find well connections and calculate segment rates based on well connection production/injection terms
auto sSFR = SegmentSetFlowRates{};
if (haveWellRes) {
sSFR = getSegmentSetFlowRates(welSegSet, wRatesIt->second.connections, welConns, units);
}
const auto sSFR = haveWellRes
? getSegmentSetFlowRates(welSegSet, wRatesIt->second.connections, welConns, units)
: SegmentSetFlowRates{};
auto get = [&smry, &wname](const std::string& vector, const std::string& segment_nr)
{
@@ -856,7 +856,6 @@ namespace {
return smry.get(key, 0.0);
};
// Treat the top segment individually
{
const int segNumber = segment0.segmentNumber();

View File

@@ -153,6 +153,96 @@ Opm::data::Wells wr()
return xw;
}
//------------------------------------------------------------------+
// Models a multi-lateral well with the following segment structure |
//------------------------------------------------------------------+
// |
// 12 13 14 15 16 |
// o----o----o-----o------o-----o (2) |
// 11 / 20 \ 21 \ |
// / o o (6) |
// / \ |
// / 22 \ 23 24 |
// 1 2 3 / 4 5 6 o----o----o (5) |
// ---o---o---o-----o---o---o (1) |
// \ |
// 7 \ 8 9 10 |
// o---o---o-----o (3) |
// \ |
// 17 \ 18 19 |
// o----o----o (4) |
//------------------------------------------------------------------+
// Branch (1): 1, 2, 3, 4, 5, 6 |
// Branch (2): 11, 12, 13, 14, 15, 16 |
// Branch (3): 7, 8, 9, 10 |
// Branch (4): 17, 18, 19 |
// Branch (5): 20, 22, 23, 24 |
// Branch (6): 12 |
//------------------------------------------------------------------+
Opm::Deck multilaterals()
{
return Opm::Parser{}.parseString(R"(RUNSPEC
START
29 'SEP' 2023 /
DIMENS
10 10 3 /
OIL
GAS
WATER
DISGAS
VAPOIL
GRID
DXV
10*100.0 /
DYV
10*100.0 /
DZV
3*5.0 /
PERMX
300*100.0 /
COPY
PERMX PERMY /
PERMX PERMZ /
/
MULTIPLY
PERMZ 0.1 /
/
PORO
300*0.3 /
DEPTHZ
121*2000.0 /
SCHEDULE
WELSPECS
'MLP' 'G' 10 10 2002.5 'OIL' /
/
COMPDAT
'MLP' 10 10 3 3 'OPEN' 1* 123.4 /
/
WELSEGS
'MLP' 2002.5 0.0 1* 'INC' 'H--' /
--
2 6 1 1 0.1 0.1 0.2 0.01 /
7 10 3 5 0.1 0.1 0.2 0.01 /
11 16 2 3 0.1 0.1 0.2 0.01 /
17 19 4 10 0.1 0.1 0.2 0.01 /
20 20 5 14 0.1 0.1 0.2 0.01 /
21 21 6 15 0.1 0.1 0.2 0.01 /
22 24 5 20 0.1 0.1 0.2 0.01 /
/
COMPSEGS
'MLP' /
--
10 10 3 5 0.0 1.0 'Z' /
/
WCONPROD
'MLP' 'OPEN' 'ORAT' 321.0 4* 10.0 /
/
TSTEP
5*30 /
END
)");
}
} // Anonymous namespace
struct SimulationCase
@@ -407,6 +497,67 @@ BOOST_AUTO_TEST_CASE (Declared_MSW_Data)
}
}
// The segments must appear in the following depth first search toe-to-heel
// order in ISEG[0]. We furthermore, go along kick-off branches before
// searching the main branch. Note that this order is *different* from
// ILBS/ILBR.
//
// 24, 23, 22, 20, -- Branch (5)
// 21, -- Branch (6)
// 16, 15, 14, 13, 12, 11, -- Branch (2)
// 19, 18, 17, -- Branch (4)
// 10, 9, 8, 7, -- Branch (3)
// 6, 5, 4, 3, 2, 1, -- Branch (1)
//
BOOST_AUTO_TEST_CASE(Multilateral_Segments_ISEG_0)
{
const auto cse = SimulationCase { multilaterals() };
const auto& es = cse.es;
const auto& grid = cse.grid;
const auto& sched = cse.sched;
const auto& units = es.getUnits();
const auto smry = Opm::SummaryState { Opm::TimeService::now() };
// Report Step 1: 2023-09-29 --> 2023-10-23
const auto rptStep = std::size_t {1};
const double secs_elapsed = 30 * 86'400.0;
const auto ih = Opm::RestartIO::Helpers::
createInteHead(es, grid, sched, secs_elapsed,
rptStep, rptStep + 1, rptStep);
const auto xw = Opm::data::Wells {};
auto amswd = Opm::RestartIO::Helpers::AggregateMSWData {ih};
amswd.captureDeclaredMSWData(sched, rptStep, units,
ih, grid, smry, xw);
auto isegOffset = [&ih](const int ix)
{
return ih[VI::intehead::NISEGZ] * ix;
};
const auto expect = std::vector {
24, 23, 22, 20, // Branch (5)
21, // Branch (6)
16, 15, 14, 13, 12, 11, // Branch (2)
19, 18, 17, // Branch (4)
10, 9, 8, 7, // Branch (3)
6, 5, 4, 3, 2, 1, // Branch (1)
};
const auto& iseg = amswd.getISeg();
for (auto i = 0*expect.size(); i < expect.size(); ++i) {
BOOST_CHECK_MESSAGE(iseg[isegOffset(i)] == expect[i],
"ISEG[0](" << i << ") == "
<< iseg[isegOffset(i)]
<< " differs from expected value "
<< expect[i]);
}
}
BOOST_AUTO_TEST_CASE(MSW_AICD)
{
const auto simCase = SimulationCase {first_sim("TEST_AGGREGATE_MSW.DATA")};