Test Dynamic Segment Dimensions Against WSEGDIMS Limits

In particular, check that

  1. Number of MS wells <= WSEGDIMS(1)
  2. Number of segments per well <= WSEGDIMS(2)
  3. Number of branches per well <= WSEGDIMS(3)

for all report steps in the simulation run.

Example diagnostic message of a case that violates limits 2 and 3:

Error: Problem with keyword WSEGDIMS
  In CASE.DATA line 60
  The case has a multi-segmented well with 246 well segments, but at most 200 are allowed in WSEGDIMS.
  Please increase item 2 of WSEGDIMS to at least 246

Error: Problem with keyword WSEGDIMS
  In CASE.DATA line 60
  The case has a multi-segmented well with 105 lateral branches, but at most 5 are allowed in WSEGDIMS.
  Please increase item 3 of WSEGDIMS to at least 105
This commit is contained in:
Bård Skaflestad
2023-05-02 18:38:05 +02:00
parent 0bc74799ca
commit 5a79e0f8fb
6 changed files with 474 additions and 49 deletions

View File

@@ -95,7 +95,8 @@ public:
return this->nDynWlistMax;
}
const std::optional<KeywordLocation>& location() const {
const std::optional<KeywordLocation>& location() const
{
return this->m_location;
}
@@ -113,7 +114,6 @@ public:
rst_cmp(*this, data);
}
template<class Serializer>
void serializeOp(Serializer& serializer)
{
@@ -143,7 +143,6 @@ public:
static WellSegmentDims serializationTestObject();
int maxSegmentedWells() const
{
return this->nSegWellMax;
@@ -159,6 +158,11 @@ public:
return this->nLatBranchMax;
}
const std::optional<KeywordLocation>& location() const
{
return this->location_;
}
bool operator==(const WellSegmentDims& data) const;
template<class Serializer>
@@ -167,12 +171,14 @@ public:
serializer(nSegWellMax);
serializer(nSegmentMax);
serializer(nLatBranchMax);
serializer(location_);
}
private:
int nSegWellMax;
int nSegmentMax;
int nLatBranchMax;
std::optional<KeywordLocation> location_;
};
class NetworkDims {

View File

@@ -218,6 +218,18 @@ class KeywordLocation;
/// RUNSPEC keyword WELLDIMS (item 4).
const static std::string RUNSPEC_GROUPSIZE_TOO_LARGE;
/// Dynamic number of multi-segmented wells exceeds maximum declared
/// in RUNSPEC keyword WSEGDIMS (item 1).
const static std::string RUNSPEC_NUMMSW_TOO_LARGE;
/// Dynamic number of segments per MS well exceeds maximum declared
/// in RUNSPEC keyword WSEGDIMS (item 2).
const static std::string RUNSPEC_NUMSEG_PER_WELL_TOO_LARGE;
/// Dynamic number of branches exceeds maximum number declared in
/// RUNSPEC keyword WSEGDIMS (item 3).
const static std::string RUNSPEC_NUMBRANCH_TOO_LARGE;
/*
Should we allow keywords of length more than eight characters? If the
keyword is too long it will be internalized using only the eight first

View File

@@ -212,38 +212,61 @@ Welldims Welldims::serializationTestObject()
return result;
}
WellSegmentDims::WellSegmentDims() :
nSegWellMax( ParserKeywords::WSEGDIMS::NSWLMX::defaultValue ),
nSegmentMax( ParserKeywords::WSEGDIMS::NSEGMX::defaultValue ),
nLatBranchMax( ParserKeywords::WSEGDIMS::NLBRMX::defaultValue )
WellSegmentDims::WellSegmentDims()
: nSegWellMax { ParserKeywords::WSEGDIMS::NSWLMX::defaultValue }
, nSegmentMax { ParserKeywords::WSEGDIMS::NSEGMX::defaultValue }
, nLatBranchMax { ParserKeywords::WSEGDIMS::NLBRMX::defaultValue }
{}
WellSegmentDims::WellSegmentDims(const Deck& deck) : WellSegmentDims()
WellSegmentDims::WellSegmentDims(const Deck& deck)
: WellSegmentDims {}
{
if (deck.hasKeyword("WSEGDIMS")) {
const auto& wsd = deck["WSEGDIMS"][0].getRecord(0);
using WSD = ParserKeywords::WSEGDIMS;
this->nSegWellMax = wsd.getItem("NSWLMX").get<int>(0);
this->nSegmentMax = wsd.getItem("NSEGMX").get<int>(0);
this->nLatBranchMax = wsd.getItem("NLBRMX").get<int>(0);
if (deck.hasKeyword<WSD>()) {
const auto& keyword = deck.get<WSD>().front();
const auto& wsd = keyword.getRecord(0);
if (const auto& maxMSW = wsd.getItem<WSD::NSWLMX>();
! maxMSW.defaultApplied(0))
{
this->nSegWellMax = maxMSW.get<int>(0);
}
if (const auto& maxSeg = wsd.getItem<WSD::NSEGMX>();
! maxSeg.defaultApplied(0))
{
this->nSegmentMax = maxSeg.get<int>(0);
}
if (const auto& maxBranch = wsd.getItem<WSD::NLBRMX>();
! maxBranch.defaultApplied(0))
{
this->nLatBranchMax = maxBranch.get<int>(0);
}
this->location_ = keyword.location();
}
}
WellSegmentDims WellSegmentDims::serializationTestObject()
{
WellSegmentDims result;
result.nSegWellMax = 1;
result.nSegmentMax = 2;
result.nLatBranchMax = 3;
result.location_ = KeywordLocation::serializationTestObject();
return result;
}
bool WellSegmentDims::operator==(const WellSegmentDims& data) const
{
return this->maxSegmentedWells() == data.maxSegmentedWells() &&
this->maxSegmentsPerWell() == data.maxSegmentsPerWell() &&
this->maxLateralBranchesPerWell() == data.maxLateralBranchesPerWell();
return (this->maxSegmentedWells() == data.maxSegmentedWells())
&& (this->maxSegmentsPerWell() == data.maxSegmentsPerWell())
&& (this->maxLateralBranchesPerWell() == data.maxLateralBranchesPerWell())
&& (this->location() == data.location());
}
NetworkDims::NetworkDims() :

View File

@@ -86,11 +86,17 @@ namespace Opm {
addKey(UNIT_SYSTEM_MISMATCH, InputErrorAction::THROW_EXCEPTION);
// WELLDIMS actions
this->addKey(RUNSPEC_NUMWELLS_TOO_LARGE, InputErrorAction::THROW_EXCEPTION);
this->addKey(RUNSPEC_CONNS_PER_WELL_TOO_LARGE, InputErrorAction::THROW_EXCEPTION);
this->addKey(RUNSPEC_NUMGROUPS_TOO_LARGE, InputErrorAction::THROW_EXCEPTION);
this->addKey(RUNSPEC_GROUPSIZE_TOO_LARGE, InputErrorAction::THROW_EXCEPTION);
// WSEGDIMS actions (default is to emit a warning and continue)
this->addKey(RUNSPEC_NUMMSW_TOO_LARGE, InputErrorAction::WARN);
this->addKey(RUNSPEC_NUMSEG_PER_WELL_TOO_LARGE, InputErrorAction::WARN);
this->addKey(RUNSPEC_NUMBRANCH_TOO_LARGE, InputErrorAction::WARN);
addKey(UNSUPPORTED_INITIAL_THPRES, InputErrorAction::THROW_EXCEPTION);
addKey(UNSUPPORTED_TERMINATE_IF_BHP, InputErrorAction::THROW_EXCEPTION);
@@ -338,6 +344,10 @@ namespace Opm {
const std::string ParseContext::RUNSPEC_NUMGROUPS_TOO_LARGE = "RUNSPEC_NUMGROUPS_TOO_LARGE";
const std::string ParseContext::RUNSPEC_GROUPSIZE_TOO_LARGE = "RUNSPEC_GROUPSIZE_TOO_LARGE";
const std::string ParseContext::RUNSPEC_NUMMSW_TOO_LARGE = "RUNSPEC_NUMMSW_TOO_LARGE";
const std::string ParseContext::RUNSPEC_NUMSEG_PER_WELL_TOO_LARGE = "RUNSPEC_NUMSEG_PER_WELL_TOO_LARGE";
const std::string ParseContext::RUNSPEC_NUMBRANCH_TOO_LARGE = "RUNSPEC_NUMBRANCH_TOO_LARGE";
const std::string ParseContext::UNSUPPORTED_INITIAL_THPRES = "UNSUPPORTED_INITIAL_THPRES";
const std::string ParseContext::UNSUPPORTED_TERMINATE_IF_BHP = "UNSUPPORTED_TERMINATE_IF_BHP";

View File

@@ -27,6 +27,7 @@
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/Runspec.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
@@ -81,7 +82,7 @@ namespace {
const auto message_fmt = fmt::format(R"(Problem with keyword {{keyword}}
In {{file}} line {{line}}
The case has {schedVal} {entity}, but at most {maxVal} {pl} allowed in {{keyword}}.
Please increase item {item} in {{keyword}} to at least {schedVal})",
Please increase item {item} of {{keyword}} to at least {schedVal})",
"schedVal"_a = schedVal,
"maxVal"_a = maxVal,
"entity"_a = entity,
@@ -237,6 +238,144 @@ namespace {
}
} // WellDims
namespace WellSegDims {
std::size_t numMultisegWells(const Opm::Schedule& sched,
const std::size_t reportStep)
{
const auto& wnames = sched.wellNames(reportStep);
return std::count_if(std::begin(wnames), std::end(wnames),
[&sched, reportStep](const std::string& wname) -> bool
{
return sched.getWell(wname, reportStep).isMultiSegment();
});
}
int maxSegmentID(const Opm::Schedule& sched,
const std::size_t reportStep)
{
const auto& wnames = sched.wellNames(reportStep);
return std::accumulate(std::begin(wnames), std::end(wnames), 0,
[&sched, reportStep](const int m, const std::string& wname) -> int
{
// maxSegmentID() returns 0 for standard (non-MS) wells.
return std::max(m, sched.getWell(wname, reportStep).maxSegmentID());
});
}
int maxBranchID(const Opm::Schedule& sched,
const std::size_t reportStep)
{
const auto& wnames = sched.wellNames(reportStep);
return std::accumulate(std::begin(wnames), std::end(wnames), 0,
[&sched, reportStep](const int m, const std::string& wname) -> int
{
// maxBranchID() returns 0 for standard (non-MS) wells.
return std::max(m, sched.getWell(wname, reportStep).maxBranchID());
});
}
void checkNumMultisegWells(const Opm::WellSegmentDims& wsdims,
const Opm::Schedule& sched,
const Opm::ParseContext& ctxt,
Opm::ErrorGuard& guard)
{
const auto numSteps = sched.size() - 1;
auto numMSW = std::size_t{0};
for (auto step = 0*numSteps; step < numSteps; ++step) {
numMSW = std::max(numMSW, numMultisegWells(sched, step));
}
if (static_cast<int>(numMSW) <= wsdims.maxSegmentedWells()) {
return;
}
const auto item = 1; // NSWLMX = WSEGDIMS(1)
const auto* entity = (numMSW == 1)
? "multi-segmented well"
: "multi-segmented wells";
if (const auto& location = wsdims.location(); location.has_value()) {
reportError(*location, wsdims.maxSegmentedWells(), numMSW, item, entity,
Opm::ParseContext::RUNSPEC_NUMMSW_TOO_LARGE, ctxt, guard);
}
else {
reportError("WSEGDIMS", numMSW, item, entity,
Opm::ParseContext::RUNSPEC_NUMMSW_TOO_LARGE, ctxt, guard);
}
}
void checkNumSegments(const Opm::WellSegmentDims& wsdims,
const Opm::Schedule& sched,
const Opm::ParseContext& ctxt,
Opm::ErrorGuard& guard)
{
const auto numSteps = sched.size() - 1;
auto numSeg = 0;
for (auto step = 0*numSteps; step < numSteps; ++step) {
numSeg = std::max(numSeg, maxSegmentID(sched, step));
}
if (numSeg <= wsdims.maxSegmentsPerWell()) {
return;
}
const auto item = 2; // NSEGMX = WSEGDIMS(2)
const auto* entity = (numSeg == 1)
? "well segment"
: "well segments";
const auto* hostEntity = "multi-segmented well";
if (const auto& location = wsdims.location(); location.has_value()) {
reportError(*location, wsdims.maxSegmentsPerWell(), numSeg, item, hostEntity, entity,
Opm::ParseContext::RUNSPEC_NUMSEG_PER_WELL_TOO_LARGE, ctxt, guard);
}
else {
reportError("WSEGDIMS", numSeg, item, entity,
Opm::ParseContext::RUNSPEC_NUMSEG_PER_WELL_TOO_LARGE, ctxt, guard);
}
}
void checkNumBranches(const Opm::WellSegmentDims& wsdims,
const Opm::Schedule& sched,
const Opm::ParseContext& ctxt,
Opm::ErrorGuard& guard)
{
const auto numSteps = sched.size() - 1;
auto numBranch = 0;
for (auto step = 0*numSteps; step < numSteps; ++step) {
numBranch = std::max(numBranch, maxBranchID(sched, step));
}
if (numBranch <= wsdims.maxLateralBranchesPerWell()) {
return;
}
const auto item = 3; // NLBRMX = WSEGDIMS(3)
const auto* entity = (numBranch == 1)
? "lateral branch"
: "lateral branches";
const auto* hostEntity = "multi-segmented well";
if (const auto& location = wsdims.location(); location.has_value()) {
reportError(*location, wsdims.maxLateralBranchesPerWell(),
numBranch, item, hostEntity, entity,
Opm::ParseContext::RUNSPEC_NUMBRANCH_TOO_LARGE, ctxt, guard);
}
else {
reportError("WSEGDIMS", numBranch, item, entity,
Opm::ParseContext::RUNSPEC_NUMBRANCH_TOO_LARGE, ctxt, guard);
}
}
} // WellSegmentDims
void consistentWellDims(const Opm::Welldims& wdims,
const Opm::Schedule& sched,
const Opm::ParseContext& ctxt,
@@ -247,6 +386,16 @@ namespace {
WellDims::checkNumGroups (wdims, sched, ctxt, guard);
WellDims::checkGroupSize (wdims, sched, ctxt, guard);
}
void consistentSegmentDimentions(const Opm::WellSegmentDims& wsdims,
const Opm::Schedule& sched,
const Opm::ParseContext& ctxt,
Opm::ErrorGuard& guard)
{
WellSegDims::checkNumMultisegWells(wsdims, sched, ctxt, guard);
WellSegDims::checkNumSegments (wsdims, sched, ctxt, guard);
WellSegDims::checkNumBranches (wsdims, sched, ctxt, guard);
}
} // Anonymous
void
@@ -255,7 +404,10 @@ Opm::checkConsistentArrayDimensions(const EclipseState& es,
const ParseContext& ctxt,
ErrorGuard& guard)
{
consistentWellDims(es.runspec().wellDimensions(), sched, ctxt, guard);
const auto& rspec = es.runspec();
consistentWellDims(rspec.wellDimensions(), sched, ctxt, guard);
consistentSegmentDimentions(rspec.wellSegmentDimensions(), sched, ctxt, guard);
}

View File

@@ -20,21 +20,27 @@
#define BOOST_TEST_MODULE Array_Dimension_Checker
#include <boost/test/unit_test.hpp>
#include <boost/version.hpp>
#include <opm/input/eclipse/Schedule/ArrayDimChecker.hpp>
#include <opm/common/utility/OpmInputError.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/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
#include <opm/input/eclipse/Parser/InputErrorAction.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>
#include <iostream>
#include <memory>
#include <sstream>
#include <streambuf>
#include <string>
namespace {
@@ -187,6 +193,158 @@ WCONINJE
TSTEP
100*30 /
END
)" };
return Opm::Parser{}.parseString(input);
}
Opm::Deck simCaseWellSegmentDims()
{
const auto input = std::string{ R"(RUNSPEC
TITLE
Check Well Segment Dimensions /
DIMENS
20 20 15 /
OIL
WATER
METRIC
EQLDIMS
-- Defaulted
/
TABDIMS
-- Defaulted
/
WELLDIMS
2 10 5 5
/
WSEGDIMS
-- Defaulted => Max # MS wells = 0 (NSWLMX)
-- Max # segments = 1 (NSEGMX)
-- Max # branches = 1 (NLBRMX)
/
-- ====================================================================
GRID
SPECGRID
20 20 15 1 F /
DXV
20*100.0 /
DYV
20*100.0 /
DZV
15*0.1 /
DEPTHZ
441*2000 /
PORO
6000*0.3 /
PERMX
6000*100.0 /
COPY
'PERMX' 'PERMY' /
'PERMX' 'PERMZ' /
/
MULTIPLY
'PERMZ' 0.1 /
/
-- ====================================================================
PROPS
SWOF
0 0 1 0
1 1 0 0 /
PVDO
1 1.0 0.5
800 0.99 0.51 /
PVTW
300 0.99 1.0e-6 0.25 0 /
DENSITY
850.0 1014.0 1.05 /
-- ====================================================================
SOLUTION
EQUIL
2000 300 2010 0.0 2000 10 /
-- ====================================================================
SUMMARY
ALL
-- ====================================================================
SCHEDULE
RPTRST
BASIC=5 FREQ=6 /
GRUPTREE
'G' 'FIELD' /
/
WELSPECS
'I-N-1' 'G' 1 1 2000.15 'WATER' /
'P-N-0' 'G' 1 10 2000.15 'OIL' /
/
COMPDAT
'I-N-1' 0 0 2 10 'OPEN' 1* 1* 1.0 /
'P-N-0' 0 0 2 10 'OPEN' 1* 1* 1.0 /
/
WELSEGS
-- Number of MS wells = 1 (> 0 from WSEGDIMS(1))
-- Max segment ID = 234 (> 1 from WSEGDIMS(2))
-- Max branch ID = 123 (> 1 from WSEGDIMS(3))
'P-N-0' 2345.6 2456.7 1* ABS 'HF-' /
234 234 123 1 3456.7 2345.6 0.02468 0.0010000 /
/
COMPSEGS
'P-N-0' /
1 10 2 123 3456.7 3456.85 Z /
1 10 3 123 3456.85 3457.0 Z /
1 10 4 123 3457.0 3457.15 Z /
1 10 5 123 3457.15 3457.3 Z /
1 10 6 123 3457.3 3457.45 Z /
1 10 7 123 3457.45 3457.6 Z /
1 10 8 123 3457.6 3457.75 Z /
1 10 9 123 3456.75 3457.90 Z /
1 10 10 123 3456.90 3458.05 Z /
/
WCONPROD
-- Well O/S Mode ORAT WRAT GRAT LRAT RESV BHP
'P-N-*' 'OPEN' 'LRAT' 1* 1* 1* 5E3 1* 100 /
/
WCONINJE
-- Well Type O/S Mode RATE RESV BHP
'I-N-*' 'WATER' 'OPEN' 'RATE' 25E3 1* 500 /
/
TSTEP
100*30 /
END
)" };
@@ -348,17 +506,14 @@ struct CaseObjects
Opm::ErrorGuard guard;
Opm::EclipseState es;
std::shared_ptr<Opm::Python> python;
Opm::Schedule sched;
};
CaseObjects::CaseObjects(const Opm::Deck& deck, const Opm::ParseContext& ctxt)
: guard{}
, es (deck)
, python( std::make_shared<Opm::Python>())
, sched(deck, es, ctxt, guard, python)
{
}
: guard {}
, es { deck }
, sched { deck, es, ctxt, guard, std::make_shared<Opm::Python>() }
{}
CaseObjects::~CaseObjects()
{
@@ -377,8 +532,7 @@ private:
RedirectCERR::RedirectCERR(std::streambuf* buf)
: orig_{ std::cerr.rdbuf(buf) }
{
}
{}
RedirectCERR::~RedirectCERR()
{
@@ -391,7 +545,7 @@ BOOST_AUTO_TEST_SUITE(WellDimensions)
namespace {
void setWellDimsContext(const Opm::InputErrorAction action,
Opm::ParseContext& ctxt)
Opm::ParseContext& ctxt)
{
ctxt.update(Opm::ParseContext::RUNSPEC_NUMWELLS_TOO_LARGE, action);
ctxt.update(Opm::ParseContext::RUNSPEC_CONNS_PER_WELL_TOO_LARGE, action);
@@ -403,7 +557,7 @@ namespace {
BOOST_AUTO_TEST_CASE(MaxGroupSize)
{
Opm::ParseContext parseContext;
auto cse = CaseObjects{ simCaseWellDims(), parseContext };
auto cse = CaseObjects { simCaseWellDims(), parseContext };
// Verify at most ten wells in a single group.
BOOST_CHECK_EQUAL(Opm::maxGroupSize(cse.sched, 1), 10);
@@ -425,21 +579,21 @@ BOOST_AUTO_TEST_CASE(WellDims)
Opm::ParseContext parseContext;
setWellDimsContext(Opm::InputErrorAction::THROW_EXCEPTION, parseContext);
auto cse = CaseObjects{ simCaseWellDims(), parseContext};
auto cse = CaseObjects { simCaseWellDims(), parseContext };
// There should be no failures in basic input layer
BOOST_CHECK(!cse.guard);
BOOST_CHECK_THROW( Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
parseContext, cse.guard),
Opm::OpmInputError);
BOOST_CHECK_THROW(Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
parseContext, cse.guard),
Opm::OpmInputError);
setWellDimsContext(Opm::InputErrorAction::DELAYED_EXIT1, parseContext);
Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
parseContext, cse.guard);
// There *should* be errors from dimension checking
BOOST_CHECK(cse.guard);
BOOST_CHECK_MESSAGE(cse.guard, "Exceeding WELLDIMS limits must produce errors");
{
std::stringstream estream;
@@ -448,11 +602,15 @@ BOOST_AUTO_TEST_CASE(WellDims)
cse.guard.dump();
const auto error_msg = estream.str();
for (const auto& s : {"RUNSPEC_NUMWELLS_TOO_LARGE", "item 1",
"RUNSPEC_CONNS_PER_WELL_TOO_LARGE", "item 2",
"RUNSPEC_NUMGROUPS_TOO_LARGE", "item 3",
"RUNSPEC_GROUPSIZE_TOO_LARGE", "item 4"})
BOOST_CHECK( error_msg.find(s) != std::string::npos );
for (const auto& s : {"RUNSPEC_NUMWELLS_TOO_LARGE" , "item 1",
"RUNSPEC_CONNS_PER_WELL_TOO_LARGE", "item 2",
"RUNSPEC_NUMGROUPS_TOO_LARGE" , "item 3",
"RUNSPEC_GROUPSIZE_TOO_LARGE" , "item 4"})
{
BOOST_CHECK(error_msg.find(s) != std::string::npos);
}
BOOST_TEST_MESSAGE("WELLDIMS Diagnostic Message: '" << error_msg << '\'');
}
}
@@ -461,22 +619,22 @@ BOOST_AUTO_TEST_CASE(WellDims_ManyChildGroups)
Opm::ParseContext parseContext;
setWellDimsContext(Opm::InputErrorAction::THROW_EXCEPTION, parseContext);
auto cse = CaseObjects{ simCaseNodeGroupSizeFailure(), parseContext};
auto cse = CaseObjects { simCaseNodeGroupSizeFailure(), parseContext };
// There should be no failures in basic input layer
BOOST_CHECK(!cse.guard);
// There *should* be errors from dimension checking
BOOST_CHECK_THROW( Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
parseContext, cse.guard),
Opm::OpmInputError);
BOOST_CHECK_THROW(Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
parseContext, cse.guard),
Opm::OpmInputError);
setWellDimsContext(Opm::InputErrorAction::DELAYED_EXIT1, parseContext);
Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
parseContext, cse.guard);
// There *should* be errors from dimension checking
BOOST_CHECK(cse.guard);
BOOST_CHECK_MESSAGE(cse.guard, "Exceeding WELLDIMS limits must produce errors");
// Verify that we get expected output from ErrorGuard::dump()
{
@@ -486,9 +644,73 @@ BOOST_AUTO_TEST_CASE(WellDims_ManyChildGroups)
cse.guard.dump();
const auto error_msg = estream.str();
for (const auto& s : {"RUNSPEC_GROUPSIZE_TOO_LARGE", "item 4"})
BOOST_CHECK( error_msg.find(s) != std::string::npos );
for (const auto& s : {"RUNSPEC_GROUPSIZE_TOO_LARGE", "item 4"}) {
BOOST_CHECK(error_msg.find(s) != std::string::npos);
}
BOOST_TEST_MESSAGE("WELLDIMS Diagnostic Message: '" << error_msg << '\'');
}
}
BOOST_AUTO_TEST_SUITE_END()
// ====================================================================
BOOST_AUTO_TEST_SUITE(WellSegmentDimensions)
namespace {
void setWellSegmentDimsContext(const Opm::InputErrorAction action,
Opm::ParseContext& ctxt)
{
ctxt.update(Opm::ParseContext::RUNSPEC_NUMMSW_TOO_LARGE, action);
ctxt.update(Opm::ParseContext::RUNSPEC_NUMSEG_PER_WELL_TOO_LARGE, action);
ctxt.update(Opm::ParseContext::RUNSPEC_NUMBRANCH_TOO_LARGE, action);
}
}
BOOST_AUTO_TEST_CASE(WellSegDims)
{
auto parseContext = Opm::ParseContext{};
setWellSegmentDimsContext(Opm::InputErrorAction::THROW_EXCEPTION, parseContext);
auto cse = CaseObjects { simCaseWellSegmentDims(), parseContext };
// There should be no failures in basic input layer
BOOST_CHECK_MESSAGE(! cse.guard, "Reading input file must not produce errors");
// Default action (THROW_EXCEPTION) must throw exception from array
// dimension checking.
BOOST_CHECK_THROW(Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
parseContext, cse.guard),
Opm::OpmInputError);
setWellSegmentDimsContext(Opm::InputErrorAction::DELAYED_EXIT1, parseContext);
Opm::checkConsistentArrayDimensions(cse.es , cse.sched,
parseContext, cse.guard);
// There *should* be errors from dimension checking when action is DELAYED_EXIT1.
BOOST_CHECK_MESSAGE(cse.guard, "Exceeding WSEGDIMS limits must produce errors");
{
std::stringstream estream;
RedirectCERR stream(estream.rdbuf());
using namespace std::string_literals;
cse.guard.dump();
const auto error_msg = estream.str();
for (const auto* s : {"RUNSPEC_NUMMSW_TOO_LARGE" , "item 1",
"RUNSPEC_NUMSEG_PER_WELL_TOO_LARGE", "item 2",
"RUNSPEC_NUMBRANCH_TOO_LARGE" , "item 3"})
{
BOOST_CHECK_MESSAGE(error_msg.find(s) != std::string::npos,
"Diagnostic message element '"s + s +
"' must be in WSEGDIMS error message"s);
}
BOOST_TEST_MESSAGE("WSEGDIMS Diagnostic Message: '" << error_msg << '\'');
}
}
BOOST_AUTO_TEST_SUITE_END() // WellSegmentDimensions