mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#1269 Updated opm-flowdiagnostics to a14dc4ba1302bcc1e0aeb35c5de6b4bd39bce98a to fix issue with fraction sums > 1.0
This commit is contained in:
@@ -116,7 +116,7 @@ Toolbox::Impl::assignInflowFlux(const CellSetValues& inflow_flux)
|
||||
for (const auto& data : inflow_flux) {
|
||||
if (data.second > 0.0) {
|
||||
only_inflow_flux_[data.first] = data.second;
|
||||
} else {
|
||||
} else if (data.second < 0.0) {
|
||||
only_outflow_flux_[data.first] = -data.second;
|
||||
}
|
||||
}
|
||||
@@ -130,6 +130,15 @@ Toolbox::Impl::injDiag(const std::vector<CellSet>& start_sets)
|
||||
throw std::logic_error("Must set pore volumes and fluxes before calling diagnostics.");
|
||||
}
|
||||
|
||||
// Check that start sets are valid.
|
||||
for (const auto& start : start_sets) {
|
||||
for (const int cell : start) {
|
||||
if (only_inflow_flux_.count(cell) != 1 || only_outflow_flux_.count(cell) != 0) {
|
||||
throw std::runtime_error("Start set inconsistent with assignInflowFlux()-given values");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn_built_) {
|
||||
buildAssembledConnections();
|
||||
}
|
||||
@@ -158,6 +167,15 @@ Toolbox::Impl::prodDiag(const std::vector<CellSet>& start_sets)
|
||||
throw std::logic_error("Must set pore volumes and fluxes before calling diagnostics.");
|
||||
}
|
||||
|
||||
// Check that start sets are valid.
|
||||
for (const auto& start : start_sets) {
|
||||
for (const int cell : start) {
|
||||
if (only_inflow_flux_.count(cell) != 0 || only_outflow_flux_.count(cell) != 1) {
|
||||
throw std::runtime_error("Start set inconsistent with assignInflowFlux()-given values");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn_built_) {
|
||||
buildAssembledConnections();
|
||||
}
|
||||
|
||||
@@ -320,9 +320,20 @@ namespace FlowDiagnostics
|
||||
upwind_tof_contrib += tof_[upwind_cell] * tracer_[upwind_cell] * flux;
|
||||
upwind_tracer_contrib += tracer_[upwind_cell] * flux;
|
||||
}
|
||||
if (is_start_[cell]) {
|
||||
// For cells tagged as start cells, the tracer value
|
||||
// should get a contribution from the local source term
|
||||
// (which is then considered to be containing the
|
||||
// currently considered tracer).
|
||||
//
|
||||
// Start cells should therefore never have a zero source
|
||||
// term. This may need to change in the future to support
|
||||
// local tracing from arbitrary locations.
|
||||
upwind_tracer_contrib += source;
|
||||
}
|
||||
|
||||
// Compute time-of-flight and tracer.
|
||||
tracer_[cell] = is_start_[cell] ? 1.0 : upwind_tracer_contrib / total_influx;
|
||||
tracer_[cell] = upwind_tracer_contrib / total_influx;
|
||||
|
||||
if (tracer_[cell] > 0.0) {
|
||||
tof_[cell] = (pv_[cell]*tracer_[cell] + upwind_tof_contrib)
|
||||
|
||||
@@ -162,6 +162,8 @@ BOOST_AUTO_TEST_SUITE(FlowDiagnostics_Toolbox)
|
||||
|
||||
BOOST_AUTO_TEST_CASE (Constructor)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("============== Test: Constructor ==============");
|
||||
|
||||
const auto cas = Setup(2, 2);
|
||||
|
||||
Toolbox diagTool(cas.connectivity());
|
||||
@@ -170,71 +172,6 @@ BOOST_AUTO_TEST_CASE (Constructor)
|
||||
diagTool.assignConnectionFlux(cas.flux());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE (InjectionDiagnostics)
|
||||
{
|
||||
const auto cas = Setup(2, 2);
|
||||
|
||||
Toolbox diagTool(cas.connectivity());
|
||||
|
||||
diagTool.assignPoreVolume(cas.poreVolume());
|
||||
diagTool.assignConnectionFlux(cas.flux());
|
||||
|
||||
auto start = std::vector<CellSet>{ CellSet(CellSetID("I-1"), {0}),
|
||||
CellSet(CellSetID("I-2"), {int(cas.connectivity().numCells()) - 1}) };
|
||||
|
||||
const auto fwd = diagTool
|
||||
.computeInjectionDiagnostics(start);
|
||||
|
||||
// Global ToF field (accumulated from all injectors)
|
||||
{
|
||||
const auto tof = fwd.fd.timeOfFlight();
|
||||
|
||||
BOOST_CHECK_EQUAL(tof.size(), cas.connectivity().numCells());
|
||||
}
|
||||
|
||||
// Verify set of start points.
|
||||
{
|
||||
const auto startpts = fwd.fd.startPoints();
|
||||
|
||||
BOOST_CHECK_EQUAL(startpts.size(), start.size());
|
||||
|
||||
for (const auto& pt : startpts) {
|
||||
auto pos =
|
||||
std::find_if(start.begin(), start.end(),
|
||||
[&pt](const CellSet& s)
|
||||
{
|
||||
return s.id().to_string() == pt.to_string();
|
||||
});
|
||||
|
||||
// ID of 'pt' *MUST* be in set of identified start points.
|
||||
BOOST_CHECK(pos != start.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Tracer-ToF
|
||||
{
|
||||
const auto tof = fwd.fd
|
||||
.timeOfFlight(CellSetID("I-1"));
|
||||
|
||||
for (const auto& v : tof) {
|
||||
BOOST_TEST_MESSAGE("ToF[" << v.first << "] = " << v.second);
|
||||
}
|
||||
}
|
||||
|
||||
// Tracer Concentration
|
||||
{
|
||||
const auto conc = fwd.fd
|
||||
.concentration(CellSetID("I-2"));
|
||||
|
||||
BOOST_TEST_MESSAGE("conc.size() = " <<
|
||||
conc.size());
|
||||
|
||||
for (const auto& v : conc) {
|
||||
BOOST_TEST_MESSAGE("Conc[" << v.first << "] = " << v.second);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -264,6 +201,7 @@ namespace {
|
||||
|
||||
BOOST_AUTO_TEST_CASE (OneDimCase)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("============== Test: OneDimCase ==============");
|
||||
using namespace Opm::FlowDiagnostics;
|
||||
|
||||
const auto cas = Setup(5, 1);
|
||||
@@ -285,13 +223,22 @@ BOOST_AUTO_TEST_CASE (OneDimCase)
|
||||
diagTool.assignConnectionFlux(flux);
|
||||
diagTool.assignInflowFlux(wellflow);
|
||||
|
||||
// Check that inconsistent start set specifications will throw.
|
||||
{
|
||||
const int first_cell = 0;
|
||||
const int last_cell = cas.connectivity().numCells() - 1;
|
||||
auto start = std::vector<CellSet>{ CellSet(CellSetID("I-1"), {first_cell}),
|
||||
CellSet(CellSetID("I-2"), {last_cell}) };
|
||||
BOOST_CHECK_THROW(diagTool.computeInjectionDiagnostics(start), std::runtime_error);
|
||||
BOOST_CHECK_THROW(diagTool.computeProductionDiagnostics(start), std::runtime_error);
|
||||
}
|
||||
|
||||
const int first_cell = 0;
|
||||
const int last_cell = cas.connectivity().numCells() - 1;
|
||||
auto start = std::vector<CellSet>{ CellSet(CellSetID("I-1"), {first_cell}),
|
||||
CellSet(CellSetID("I-2"), {last_cell}) };
|
||||
|
||||
const auto fwd = diagTool.computeInjectionDiagnostics(start);
|
||||
const auto rev = diagTool.computeProductionDiagnostics(start);
|
||||
auto start_fwd = std::vector<CellSet>{ CellSet(CellSetID("I-1"), {first_cell}) };
|
||||
auto start_rev = std::vector<CellSet>{ CellSet(CellSetID("I-2"), {last_cell}) };
|
||||
const auto fwd = diagTool.computeInjectionDiagnostics(start_fwd);
|
||||
const auto rev = diagTool.computeProductionDiagnostics(start_rev);
|
||||
|
||||
// Global ToF field (accumulated from all injectors)
|
||||
{
|
||||
@@ -315,28 +262,27 @@ BOOST_AUTO_TEST_CASE (OneDimCase)
|
||||
{
|
||||
const auto startpts = fwd.fd.startPoints();
|
||||
|
||||
BOOST_CHECK_EQUAL(startpts.size(), start.size());
|
||||
BOOST_CHECK_EQUAL(startpts.size(), start_fwd.size());
|
||||
|
||||
for (const auto& pt : startpts) {
|
||||
auto pos =
|
||||
std::find_if(start.begin(), start.end(),
|
||||
std::find_if(start_fwd.begin(), start_fwd.end(),
|
||||
[&pt](const CellSet& s)
|
||||
{
|
||||
return s.id().to_string() == pt.to_string();
|
||||
});
|
||||
|
||||
// ID of 'pt' *MUST* be in set of identified start points.
|
||||
BOOST_CHECK(pos != start.end());
|
||||
BOOST_CHECK(pos != start_fwd.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Tracer-ToF
|
||||
{
|
||||
const auto tof = fwd.fd
|
||||
.timeOfFlight(CellSetID("I-2"));
|
||||
.timeOfFlight(CellSetID("BogusID"));
|
||||
|
||||
|
||||
std::vector<std::pair<int, double>> expected = { {last_cell, 0.0} };
|
||||
std::vector<std::pair<int, double>> expected = {};
|
||||
BOOST_REQUIRE_EQUAL(tof.size(), expected.size());
|
||||
|
||||
int i = 0;
|
||||
@@ -351,9 +297,9 @@ BOOST_AUTO_TEST_CASE (OneDimCase)
|
||||
// Tracer Concentration
|
||||
{
|
||||
const auto conc = fwd.fd
|
||||
.concentration(CellSetID("I-2"));
|
||||
.concentration(CellSetID("BogusID"));
|
||||
|
||||
std::vector<std::pair<int, double>> expected = { {last_cell, 1.0} };
|
||||
std::vector<std::pair<int, double>> expected = {};
|
||||
BOOST_REQUIRE_EQUAL(conc.size(), expected.size());
|
||||
|
||||
int i = 0;
|
||||
@@ -398,45 +344,8 @@ BOOST_AUTO_TEST_CASE (OneDimCase)
|
||||
|
||||
// Add a start point in the middle.
|
||||
const int middle_cell = 2;
|
||||
start.emplace_back(CellSet(CellSetID("Middle"), {middle_cell}));
|
||||
|
||||
const auto fwd2 = diagTool.computeInjectionDiagnostics(start);
|
||||
const auto rev2 = diagTool.computeProductionDiagnostics(start);
|
||||
|
||||
// Tracer-ToF
|
||||
{
|
||||
const auto tof = fwd2.fd
|
||||
.timeOfFlight(CellSetID("Middle"));
|
||||
|
||||
std::vector<std::pair<double, double>> expected = { {2, 0.0}, {3, 1.0}, {4, 2.0} };
|
||||
BOOST_REQUIRE_EQUAL(tof.size(), expected.size());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& v : tof) {
|
||||
BOOST_TEST_MESSAGE("ToF[" << v.first << "] = " << v.second);
|
||||
BOOST_CHECK_EQUAL(v.first, expected[i].first);
|
||||
BOOST_CHECK_CLOSE(v.second, expected[i].second, 1.0e-10);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Tracer Concentration
|
||||
{
|
||||
const auto conc = fwd2.fd
|
||||
.concentration(CellSetID("Middle"));
|
||||
|
||||
std::vector<std::pair<double, double>> expected = { {2, 1.0}, {3, 1.0}, {4, 1.0} };
|
||||
BOOST_REQUIRE_EQUAL(conc.size(), expected.size());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& v : conc) {
|
||||
BOOST_TEST_MESSAGE("Conc[" << v.first << "] = " << v.second);
|
||||
BOOST_CHECK_EQUAL(v.first, expected[i].first);
|
||||
BOOST_CHECK_CLOSE(v.second, expected[i].second, 1.0e-10);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
start_fwd.emplace_back(CellSet(CellSetID("Middle"), {middle_cell}));
|
||||
BOOST_CHECK_THROW(diagTool.computeInjectionDiagnostics(start_fwd), std::runtime_error);
|
||||
}
|
||||
|
||||
// Arrows indicate a flux of 0.3, O is a source of 0.3
|
||||
@@ -490,6 +399,7 @@ BOOST_AUTO_TEST_CASE (OneDimCase)
|
||||
// ----------------------------
|
||||
BOOST_AUTO_TEST_CASE (LocalSolutions)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("============== Test: LocalSolutions ==============");
|
||||
using namespace Opm::FlowDiagnostics;
|
||||
|
||||
const auto cas = Setup(3, 2);
|
||||
@@ -633,4 +543,205 @@ BOOST_AUTO_TEST_CASE (LocalSolutions)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Arrows indicate a flux of 0.3, O is a source of 0.3
|
||||
// and X is a sink of 0.3 (each cell has a pore volume of 0.3).
|
||||
// ----------------------------
|
||||
// | | | |
|
||||
// | O -> O -> XX |
|
||||
// | "I-1" | "I-2" -> "P-1" |
|
||||
// | | | |
|
||||
// ----------------------------
|
||||
// Cell indices:
|
||||
// ----------------------------
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | 0 | 1 | 2 |
|
||||
// | | | |
|
||||
// ----------------------------
|
||||
// Expected global injection TOF:
|
||||
// ----------------------------
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | 1.0 | 1.0 | 1.5 |
|
||||
// | | | |
|
||||
// ----------------------------
|
||||
// Expected global production TOF:
|
||||
// ----------------------------
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | 2.0 | 1.0 | 0.5 |
|
||||
// | | | |
|
||||
// ----------------------------
|
||||
// Expected local tracer I-1:
|
||||
// ----------------------------
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | 1.0 | 0.5 | 0.5 |
|
||||
// | | | |
|
||||
// ----------------------------
|
||||
// Expected local tracer I-2:
|
||||
// ----------------------------
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | 0.0 | 0.5 | 0.5 |
|
||||
// | | | |
|
||||
// ----------------------------
|
||||
// Expected local tof I-1:
|
||||
// ----------------------------
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | 1.0 | 1.5 | 2.0 |
|
||||
// | | | |
|
||||
// ----------------------------
|
||||
// Expected local tof I-2:
|
||||
// ----------------------------
|
||||
// | | | |
|
||||
// | | | |
|
||||
// | | 0.5 | 1.0 |
|
||||
// | | | |
|
||||
// ----------------------------
|
||||
BOOST_AUTO_TEST_CASE (LocalSolutionsWithMidflowSource)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("============== Test: LocalSolutionsWithMidflowSource ==============");
|
||||
using namespace Opm::FlowDiagnostics;
|
||||
|
||||
const auto cas = Setup(3, 1);
|
||||
const auto& graph = cas.connectivity();
|
||||
|
||||
// Create fluxes.
|
||||
ConnectionValues flux(ConnectionValues::NumConnections{ graph.numConnections() },
|
||||
ConnectionValues::NumPhases { 1 });
|
||||
const size_t nconn = cas.connectivity().numConnections();
|
||||
for (size_t conn = 0; conn < nconn; ++conn) {
|
||||
BOOST_TEST_MESSAGE("Connection " << conn << " connects cells "
|
||||
<< graph.connection(conn).first << " and "
|
||||
<< graph.connection(conn).second);
|
||||
}
|
||||
using C = ConnectionValues::ConnID;
|
||||
using P = ConnectionValues::PhaseID;
|
||||
flux(C{0}, P{0}) = 0.3;
|
||||
flux(C{1}, P{0}) = 0.6;
|
||||
|
||||
// Create well in/out flows.
|
||||
CellSetValues wellflow = { {0, 0.3}, {1, 0.3}, {2, -0.6} };
|
||||
|
||||
Toolbox diagTool(graph);
|
||||
diagTool.assignPoreVolume(cas.poreVolume());
|
||||
diagTool.assignConnectionFlux(flux);
|
||||
diagTool.assignInflowFlux(wellflow);
|
||||
|
||||
auto injstart = std::vector<CellSet>{ CellSet(CellSetID("I-1"), {0}),
|
||||
CellSet(CellSetID("I-2"), {1}) };
|
||||
auto prdstart = std::vector<CellSet>{ CellSet(CellSetID("P-1"), {2}) };
|
||||
|
||||
const auto fwd = diagTool.computeInjectionDiagnostics(injstart);
|
||||
const auto rev = diagTool.computeProductionDiagnostics(prdstart);
|
||||
// Global ToF field (accumulated from all injectors)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("== Global injector ToF");
|
||||
const auto tof = fwd.fd.timeOfFlight();
|
||||
BOOST_REQUIRE_EQUAL(tof.size(), cas.connectivity().numCells());
|
||||
std::vector<double> expected = { 1.0, 1.0, 1.5 };
|
||||
check_is_close(tof, expected);
|
||||
}
|
||||
|
||||
// Global ToF field (accumulated from all producers)
|
||||
{
|
||||
BOOST_TEST_MESSAGE("== Global producer ToF");
|
||||
const auto tof = rev.fd.timeOfFlight();
|
||||
BOOST_REQUIRE_EQUAL(tof.size(), cas.connectivity().numCells());
|
||||
std::vector<double> expected = { 2.0, 1.0, 0.5 };
|
||||
check_is_close(tof, expected);
|
||||
}
|
||||
|
||||
// Verify set of start points.
|
||||
{
|
||||
using VCS = std::vector<Opm::FlowDiagnostics::CellSet>;
|
||||
using VCSI = std::vector<Opm::FlowDiagnostics::CellSetID>;
|
||||
using P = std::pair<VCS, VCSI>;
|
||||
std::vector<P> pairs { P{ injstart, fwd.fd.startPoints() }, P{ prdstart, rev.fd.startPoints() } };
|
||||
for (const auto& p : pairs) {
|
||||
const auto& s1 = p.first;
|
||||
const auto& s2 = p.second;
|
||||
BOOST_CHECK_EQUAL(s1.size(), s2.size());
|
||||
for (const auto& pt : s2) {
|
||||
// ID of 'pt' *MUST* be in set of identified start points.
|
||||
auto pos = std::find_if(s1.begin(), s1.end(),
|
||||
[&pt](const CellSet& s)
|
||||
{
|
||||
return s.id().to_string() == pt.to_string();
|
||||
});
|
||||
BOOST_CHECK(pos != s1.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Local I-1 tracer concentration.
|
||||
{
|
||||
BOOST_TEST_MESSAGE("== I-1 tracer");
|
||||
const auto conc = fwd.fd.concentration(CellSetID("I-1"));
|
||||
std::vector<std::pair<int, double>> expected = { {0, 1.0}, {1, 0.5}, {2, 0.5} };
|
||||
BOOST_REQUIRE_EQUAL(conc.size(), expected.size());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& v : conc) {
|
||||
BOOST_TEST_MESSAGE("Conc[" << v.first << "] = " << v.second);
|
||||
BOOST_CHECK_EQUAL(v.first, expected[i].first);
|
||||
BOOST_CHECK_CLOSE(v.second, expected[i].second, 1.0e-10);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Local I-1 tof.
|
||||
{
|
||||
BOOST_TEST_MESSAGE("== I-1 tof");
|
||||
const auto tof = fwd.fd.timeOfFlight(CellSetID("I-1"));
|
||||
std::vector<std::pair<int, double>> expected = { {0, 1.0}, {1, 1.5}, {2, 2.0} };
|
||||
BOOST_REQUIRE_EQUAL(tof.size(), expected.size());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& v : tof) {
|
||||
BOOST_TEST_MESSAGE("ToF[" << v.first << "] = " << v.second);
|
||||
BOOST_CHECK_EQUAL(v.first, expected[i].first);
|
||||
BOOST_CHECK_CLOSE(v.second, expected[i].second, 1.0e-10);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Local I-2 tracer concentration.
|
||||
{
|
||||
BOOST_TEST_MESSAGE("== I-2 tracer");
|
||||
const auto conc = fwd.fd.concentration(CellSetID("I-2"));
|
||||
std::vector<std::pair<int, double>> expected = { {1, 0.5}, {2, 0.5} };
|
||||
BOOST_REQUIRE_EQUAL(conc.size(), expected.size());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& v : conc) {
|
||||
BOOST_TEST_MESSAGE("Conc[" << v.first << "] = " << v.second);
|
||||
BOOST_CHECK_EQUAL(v.first, expected[i].first);
|
||||
BOOST_CHECK_CLOSE(v.second, expected[i].second, 1.0e-10);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
// Local I-2 tof.
|
||||
{
|
||||
BOOST_TEST_MESSAGE("== I-2 tof");
|
||||
const auto tof = fwd.fd.timeOfFlight(CellSetID("I-2"));
|
||||
std::vector<std::pair<int, double>> expected = { {1, 0.5}, {2, 1.0} };
|
||||
BOOST_REQUIRE_EQUAL(tof.size(), expected.size());
|
||||
|
||||
int i = 0;
|
||||
for (const auto& v : tof) {
|
||||
BOOST_TEST_MESSAGE("ToF[" << v.first << "] = " << v.second);
|
||||
BOOST_CHECK_EQUAL(v.first, expected[i].first);
|
||||
BOOST_CHECK_CLOSE(v.second, expected[i].second, 1.0e-10);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
Reference in New Issue
Block a user