mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#1206 Updated the opm-flowdiag libraries
This commit is contained in:
550
ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/tests/runAcceptanceTest.cpp
vendored
Normal file
550
ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/tests/runAcceptanceTest.cpp
vendored
Normal file
@@ -0,0 +1,550 @@
|
||||
/*
|
||||
Copyright 2017 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2017 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <examples/exampleSetup.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <ert/ecl/ecl_file.h>
|
||||
#include <ert/ecl/ecl_file_kw.h>
|
||||
#include <ert/ecl/ecl_file_view.h>
|
||||
#include <ert/ecl/ecl_kw.h>
|
||||
#include <ert/ecl/ecl_kw_magic.h>
|
||||
#include <ert/util/ert_unique_ptr.hpp>
|
||||
|
||||
namespace StringUtils {
|
||||
namespace {
|
||||
std::string trim(const std::string& s)
|
||||
{
|
||||
const auto anchor_ws =
|
||||
boost::regex(R"~~(^\s+([^\s]+)\s+$)~~");
|
||||
|
||||
auto m = boost::smatch{};
|
||||
|
||||
if (boost::regex_match(s, m, anchor_ws)) {
|
||||
return m[1];
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string& s)
|
||||
{
|
||||
if (s.empty()) {
|
||||
// Single element vector whose only element is the empty
|
||||
// string.
|
||||
return { "" };
|
||||
}
|
||||
|
||||
const auto sep = boost::regex(R"~~([\s,;.|]+)~~");
|
||||
|
||||
using TI = boost::sregex_token_iterator;
|
||||
|
||||
// vector<string>(begin, end)
|
||||
//
|
||||
// Range is every substring (i.e., token) in input string 's'
|
||||
// that does NOT match 'sep'.
|
||||
return{ TI(s.begin(), s.end(), sep, -1), TI{} };
|
||||
}
|
||||
} // namespace Anonymous
|
||||
|
||||
template <typename T>
|
||||
struct StringTo;
|
||||
|
||||
template <>
|
||||
struct StringTo<int>
|
||||
{
|
||||
static int value(const std::string& s);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StringTo<double>
|
||||
{
|
||||
static double value(const std::string& s);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StringTo<std::string>
|
||||
{
|
||||
static std::string value(const std::string& s);
|
||||
};
|
||||
|
||||
int StringTo<int>::value(const std::string& s)
|
||||
{
|
||||
return std::stoi(s);
|
||||
}
|
||||
|
||||
double StringTo<double>::value(const std::string& s)
|
||||
{
|
||||
return std::stod(s);
|
||||
}
|
||||
|
||||
std::string StringTo<std::string>::value(const std::string& s)
|
||||
{
|
||||
return trim(s);
|
||||
}
|
||||
|
||||
namespace VectorValue {
|
||||
template <typename T>
|
||||
std::vector<T> get(const std::string& s, std::true_type)
|
||||
{
|
||||
return split(s);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> get(const std::string& s, std::false_type)
|
||||
{
|
||||
const auto tokens = split(s);
|
||||
|
||||
auto ret = std::vector<T>{};
|
||||
ret.reserve(tokens.size());
|
||||
for (const auto& token : tokens) {
|
||||
ret.push_back(StringTo<T>::value(token));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> get(const std::string& s)
|
||||
{
|
||||
return get<T>(s, typename std::is_same<T, std::string>::type());
|
||||
}
|
||||
} // namespace VectorValue
|
||||
} // namespace StringUtils
|
||||
|
||||
namespace {
|
||||
struct PoreVolume
|
||||
{
|
||||
std::vector<double> data;
|
||||
};
|
||||
|
||||
class VectorDifference
|
||||
{
|
||||
public:
|
||||
using Vector = std::vector<double>;
|
||||
using size_type = Vector::size_type;
|
||||
|
||||
VectorDifference(const Vector& x, const Vector& y)
|
||||
: x_(x), y_(y)
|
||||
{
|
||||
if (x_.size() != y_.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Incompatible Array Sizes: Expected 2x"
|
||||
<< x_.size() << ", but got ("
|
||||
<< x_.size() << ", " << y_.size() << ')';
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return x_.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return this->size() == 0;
|
||||
}
|
||||
|
||||
double operator[](const size_type i) const
|
||||
{
|
||||
return x_[i] - y_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
const Vector& x_;
|
||||
const Vector& y_;
|
||||
};
|
||||
|
||||
template <class Vector1, class Vector2>
|
||||
class VectorRatio
|
||||
{
|
||||
public:
|
||||
using size_type = typename std::decay<
|
||||
decltype(std::declval<Vector1>()[0])
|
||||
>::type;
|
||||
|
||||
VectorRatio(const Vector1& x, const Vector2& y)
|
||||
: x_(x), y_(y)
|
||||
{
|
||||
if (x_.size() != y.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Incompatible Array Sizes: Expected 2x"
|
||||
<< x_.size() << ", but got ("
|
||||
<< x_.size() << ", " << y_.size() << ')';
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return x_.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return x_.empty();
|
||||
}
|
||||
|
||||
double operator[](const size_type i) const
|
||||
{
|
||||
return x_[i] / y_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
const Vector1& x_;
|
||||
const Vector2& y_;
|
||||
};
|
||||
|
||||
struct ErrorMeasurement
|
||||
{
|
||||
double volume;
|
||||
double inf;
|
||||
};
|
||||
|
||||
struct ErrorTolerance
|
||||
{
|
||||
double absolute;
|
||||
double relative;
|
||||
};
|
||||
|
||||
struct AggregateErrors
|
||||
{
|
||||
std::vector<ErrorMeasurement> absolute;
|
||||
std::vector<ErrorMeasurement> relative;
|
||||
};
|
||||
|
||||
struct ReferenceToF
|
||||
{
|
||||
std::vector<double> forward;
|
||||
std::vector<double> reverse;
|
||||
};
|
||||
|
||||
template <class FieldVariable>
|
||||
double volumeMetric(const PoreVolume& pv,
|
||||
const FieldVariable& x)
|
||||
{
|
||||
if (x.size() != pv.data.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Incompatible Array Sizes: Expected 2x"
|
||||
<< pv.data.size() << ", but got ("
|
||||
<< pv.data.size() << ", " << x.size() << ')';
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
|
||||
auto num = 0.0;
|
||||
auto den = 0.0;
|
||||
|
||||
for (decltype(pv.data.size())
|
||||
i = 0, n = pv.data.size(); i < n; ++i)
|
||||
{
|
||||
num += std::abs(x[i]) * pv.data[i];
|
||||
den += pv.data[i];
|
||||
}
|
||||
|
||||
return num / den;
|
||||
}
|
||||
|
||||
template <class FieldVariable>
|
||||
double pointMetric(const FieldVariable& x)
|
||||
{
|
||||
static_assert(std::is_same<typename std::decay<decltype(std::abs(x[0]))>::type, double>::value,
|
||||
"Field Variable Value Type Must be 'double'");
|
||||
|
||||
if (x.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto max = 0*x[0] - 1;
|
||||
|
||||
for (decltype(x.size())
|
||||
i = 0, n = x.size(); i < n; ++i)
|
||||
{
|
||||
const auto t = std::abs(x[i]);
|
||||
|
||||
if (t > max) {
|
||||
max = t;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
std::vector<int>
|
||||
availableReportSteps(const example::FilePaths& paths)
|
||||
{
|
||||
using FilePtr = ::ERT::
|
||||
ert_unique_ptr<ecl_file_type, ecl_file_close>;
|
||||
|
||||
const auto rsspec_fn = example::
|
||||
deriveFileName(paths.grid, { ".RSSPEC", ".FRSSPEC" });
|
||||
|
||||
// Read-only, keep open between requests
|
||||
const auto open_flags = 0;
|
||||
|
||||
auto rsspec = FilePtr{
|
||||
ecl_file_open(rsspec_fn.generic_string().c_str(), open_flags)
|
||||
};
|
||||
|
||||
auto* globView = ecl_file_get_global_view(rsspec.get());
|
||||
|
||||
const auto* ITIME_kw = "ITIME";
|
||||
const auto n = ecl_file_view_get_num_named_kw(globView, ITIME_kw);
|
||||
|
||||
auto steps = std::vector<int>(n);
|
||||
|
||||
for (auto i = 0*n; i < n; ++i) {
|
||||
const auto* itime =
|
||||
ecl_file_view_iget_named_kw(globView, ITIME_kw, i);
|
||||
|
||||
const auto* itime_data =
|
||||
static_cast<const int*>(ecl_kw_iget_ptr(itime, 0));
|
||||
|
||||
steps[i] = itime_data[0];
|
||||
}
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
ErrorTolerance
|
||||
testTolerances(const ::Opm::parameter::ParameterGroup& param)
|
||||
{
|
||||
const auto atol = param.getDefault("atol", 1.0e-8);
|
||||
const auto rtol = param.getDefault("rtol", 5.0e-12);
|
||||
|
||||
return ErrorTolerance{ atol, rtol };
|
||||
}
|
||||
|
||||
int numDigits(const std::vector<int>& steps)
|
||||
{
|
||||
if (steps.empty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto m =
|
||||
*std::max_element(std::begin(steps), std::end(steps));
|
||||
|
||||
if (m == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert (m > 0);
|
||||
|
||||
return std::floor(std::log10(static_cast<double>(m))) + 1;
|
||||
}
|
||||
|
||||
ReferenceToF
|
||||
loadReference(const ::Opm::parameter::ParameterGroup& param,
|
||||
const int step,
|
||||
const int nDigits)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
using VRef = std::reference_wrapper<std::vector<double>>;
|
||||
|
||||
auto fname = fs::path(param.get<std::string>("ref-dir"));
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << "tof-" << std::setw(nDigits) << std::setfill('0')
|
||||
<< step << ".txt";
|
||||
|
||||
fname /= os.str();
|
||||
}
|
||||
|
||||
fs::ifstream input(fname);
|
||||
|
||||
if (! input) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Unable to Open Reference Data File "
|
||||
<< fname.filename();
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
|
||||
auto tof = ReferenceToF{};
|
||||
|
||||
auto ref = std::array<VRef,2>{{ std::ref(tof.forward) ,
|
||||
std::ref(tof.reverse) }};
|
||||
|
||||
{
|
||||
auto i = static_cast<decltype(ref[0].get().size())>(0);
|
||||
auto t = 0.0;
|
||||
|
||||
while (input >> t) {
|
||||
ref[i].get().push_back(t);
|
||||
|
||||
i = (i + 1) % 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (tof.forward.size() != tof.reverse.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Unable to Read Consistent ToF Reference Data From "
|
||||
<< fname.filename();
|
||||
|
||||
throw std::out_of_range(os.str());
|
||||
}
|
||||
|
||||
return tof;
|
||||
}
|
||||
|
||||
void computeErrors(const PoreVolume& pv,
|
||||
const std::vector<double>& ref,
|
||||
const ::Opm::FlowDiagnostics::Solution& fd,
|
||||
AggregateErrors& E)
|
||||
{
|
||||
const auto tof = fd.timeOfFlight();
|
||||
const auto diff = VectorDifference(tof, ref); // tof - ref
|
||||
|
||||
using Vector1 = std::decay<decltype(diff)>::type;
|
||||
using Vector2 = std::decay<decltype(ref)>::type;
|
||||
using Ratio = VectorRatio<Vector1, Vector2>;
|
||||
|
||||
const auto rat = Ratio(diff, ref); // (tof - ref) / ref
|
||||
|
||||
auto abs = ErrorMeasurement{};
|
||||
{
|
||||
abs.volume = volumeMetric(pv, diff);
|
||||
abs.inf = pointMetric ( diff);
|
||||
}
|
||||
|
||||
auto rel = ErrorMeasurement{};
|
||||
{
|
||||
rel.volume = volumeMetric(pv, rat);
|
||||
rel.inf = pointMetric ( rat);
|
||||
}
|
||||
|
||||
E.absolute.push_back(std::move(abs));
|
||||
E.relative.push_back(std::move(rel));
|
||||
}
|
||||
|
||||
std::array<AggregateErrors, 2>
|
||||
sampleDifferences(example::Setup&& setup,
|
||||
const std::vector<int>& steps)
|
||||
{
|
||||
const auto start =
|
||||
std::vector<Opm::FlowDiagnostics::CellSet>{};
|
||||
|
||||
const auto nDigits = numDigits(steps);
|
||||
|
||||
const auto pv = PoreVolume{ setup.graph.poreVolume() };
|
||||
|
||||
auto E = std::array<AggregateErrors, 2>{};
|
||||
|
||||
for (const auto& step : steps) {
|
||||
if (step == 0) {
|
||||
// Ignore initial condition
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! setup.selectReportStep(step)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto ref = loadReference(setup.param, step, nDigits);
|
||||
|
||||
{
|
||||
const auto fwd = setup.toolbox
|
||||
.computeInjectionDiagnostics(start);
|
||||
|
||||
computeErrors(pv, ref.forward, fwd.fd, E[0]);
|
||||
}
|
||||
|
||||
{
|
||||
const auto rev = setup.toolbox
|
||||
.computeProductionDiagnostics(start);
|
||||
|
||||
computeErrors(pv, ref.reverse, rev.fd, E[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
bool errorAcceptable(const std::vector<ErrorMeasurement>& E,
|
||||
const double tol)
|
||||
{
|
||||
return std::accumulate(std::begin(E), std::end(E), true,
|
||||
[tol](const bool ok, const ErrorMeasurement& e)
|
||||
{
|
||||
// Fine if at least one of .volume or .inf <= tol.
|
||||
return ok && ! ((e.volume > tol) && (e.inf > tol));
|
||||
});
|
||||
}
|
||||
|
||||
bool everythingFine(const AggregateErrors& E,
|
||||
const ErrorTolerance& tol)
|
||||
{
|
||||
return errorAcceptable(E.absolute, tol.absolute)
|
||||
&& errorAcceptable(E.relative, tol.relative);
|
||||
}
|
||||
} // namespace Anonymous
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
try {
|
||||
auto setup = example::Setup(argc, argv);
|
||||
|
||||
const auto tol = testTolerances(setup.param);
|
||||
const auto steps = availableReportSteps(setup.file_paths);
|
||||
|
||||
const auto E = sampleDifferences(std::move(setup), steps);
|
||||
const auto ok =
|
||||
everythingFine(E[0], tol) && everythingFine(E[1], tol);
|
||||
|
||||
std::cout << (ok ? "OK" : "FAIL") << '\n';
|
||||
|
||||
if (! ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Caught Exception: " << e.what() << '\n';
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@@ -0,0 +1,587 @@
|
||||
/*
|
||||
Copyright 2017 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2017 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <examples/exampleSetup.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#include <ert/ecl/ecl_file.h>
|
||||
#include <ert/ecl/ecl_file_kw.h>
|
||||
#include <ert/ecl/ecl_file_view.h>
|
||||
#include <ert/ecl/ecl_kw.h>
|
||||
#include <ert/ecl/ecl_kw_magic.h>
|
||||
#include <ert/util/ert_unique_ptr.hpp>
|
||||
|
||||
namespace StringUtils {
|
||||
namespace {
|
||||
std::string trim(const std::string& s)
|
||||
{
|
||||
const auto anchor_ws =
|
||||
boost::regex(R"~~(^\s+([^\s]+)\s+$)~~");
|
||||
|
||||
auto m = boost::smatch{};
|
||||
|
||||
if (boost::regex_match(s, m, anchor_ws)) {
|
||||
return m[1];
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string& s)
|
||||
{
|
||||
if (s.empty()) {
|
||||
// Single element vector whose only element is the empty
|
||||
// string.
|
||||
return { "" };
|
||||
}
|
||||
|
||||
const auto sep = boost::regex(R"~~([\s,;.|]+)~~");
|
||||
|
||||
using TI = boost::sregex_token_iterator;
|
||||
|
||||
// vector<string>(begin, end)
|
||||
//
|
||||
// Range is every substring (i.e., token) in input string 's'
|
||||
// that does NOT match 'sep'.
|
||||
return{ TI(s.begin(), s.end(), sep, -1), TI{} };
|
||||
}
|
||||
} // namespace Anonymous
|
||||
|
||||
template <typename T>
|
||||
struct StringTo;
|
||||
|
||||
template <>
|
||||
struct StringTo<int>
|
||||
{
|
||||
static int value(const std::string& s);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StringTo<double>
|
||||
{
|
||||
static double value(const std::string& s);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct StringTo<std::string>
|
||||
{
|
||||
static std::string value(const std::string& s);
|
||||
};
|
||||
|
||||
int StringTo<int>::value(const std::string& s)
|
||||
{
|
||||
return std::stoi(s);
|
||||
}
|
||||
|
||||
double StringTo<double>::value(const std::string& s)
|
||||
{
|
||||
return std::stod(s);
|
||||
}
|
||||
|
||||
std::string StringTo<std::string>::value(const std::string& s)
|
||||
{
|
||||
return trim(s);
|
||||
}
|
||||
|
||||
namespace VectorValue {
|
||||
template <typename T>
|
||||
std::vector<T> get(const std::string& s, std::true_type)
|
||||
{
|
||||
return split(s);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> get(const std::string& s, std::false_type)
|
||||
{
|
||||
const auto tokens = split(s);
|
||||
|
||||
auto ret = std::vector<T>{};
|
||||
ret.reserve(tokens.size());
|
||||
for (const auto& token : tokens) {
|
||||
ret.push_back(StringTo<T>::value(token));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> get(const std::string& s)
|
||||
{
|
||||
return get<T>(s, typename std::is_same<T, std::string>::type());
|
||||
}
|
||||
} // namespace VectorValue
|
||||
} // namespace StringUtils
|
||||
|
||||
namespace {
|
||||
struct Reference
|
||||
{
|
||||
std::vector<double> data;
|
||||
};
|
||||
|
||||
struct Calculated
|
||||
{
|
||||
std::vector<double> data;
|
||||
};
|
||||
|
||||
class VectorUnits
|
||||
{
|
||||
private:
|
||||
using USys = ::Opm::ECLUnits::UnitSystem;
|
||||
|
||||
public:
|
||||
using UnitConvention = ::Opm::ECLGraph::UnitConvention;
|
||||
|
||||
VectorUnits()
|
||||
: units_({ { "pressure", &USys::pressure } })
|
||||
{
|
||||
}
|
||||
|
||||
UnitConvention getUnit(const std::string& vector) const
|
||||
{
|
||||
auto p = units_.find(vector);
|
||||
|
||||
if (p == units_.end()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Unsupported Vector Quantity '" << vector << '\'';
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
|
||||
return p->second;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, UnitConvention> units_;
|
||||
};
|
||||
|
||||
class VectorDifference
|
||||
{
|
||||
public:
|
||||
using Vector = std::vector<double>;
|
||||
using size_type = Vector::size_type;
|
||||
|
||||
VectorDifference(const Vector& x, const Vector& y)
|
||||
: x_(x), y_(y)
|
||||
{
|
||||
if (x_.size() != y_.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Incompatible Array Sizes: Expected 2x"
|
||||
<< x_.size() << ", but got ("
|
||||
<< x_.size() << ", " << y_.size() << ')';
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return x_.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return this->size() == 0;
|
||||
}
|
||||
|
||||
double operator[](const size_type i) const
|
||||
{
|
||||
return x_[i] - y_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
const Vector& x_;
|
||||
const Vector& y_;
|
||||
};
|
||||
|
||||
template <class Vector1, class Vector2>
|
||||
class VectorRatio
|
||||
{
|
||||
public:
|
||||
using size_type = typename std::decay<
|
||||
decltype(std::declval<Vector1>()[0])
|
||||
>::type;
|
||||
|
||||
VectorRatio(const Vector1& x, const Vector2& y)
|
||||
: x_(x), y_(y)
|
||||
{
|
||||
if (x_.size() != y.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Incompatible Array Sizes: Expected 2x"
|
||||
<< x_.size() << ", but got ("
|
||||
<< x_.size() << ", " << y_.size() << ')';
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return x_.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return x_.empty();
|
||||
}
|
||||
|
||||
double operator[](const size_type i) const
|
||||
{
|
||||
return x_[i] / y_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
const Vector1& x_;
|
||||
const Vector2& y_;
|
||||
};
|
||||
|
||||
struct ErrorMeasurement
|
||||
{
|
||||
double volume;
|
||||
double inf;
|
||||
};
|
||||
|
||||
struct ErrorTolerance
|
||||
{
|
||||
double absolute;
|
||||
double relative;
|
||||
};
|
||||
|
||||
struct AggregateErrors
|
||||
{
|
||||
std::vector<ErrorMeasurement> absolute;
|
||||
std::vector<ErrorMeasurement> relative;
|
||||
};
|
||||
|
||||
struct ReferenceSolution
|
||||
{
|
||||
std::vector<double> raw;
|
||||
std::vector<double> SI;
|
||||
};
|
||||
|
||||
template <class FieldVariable>
|
||||
double volumeMetric(const FieldVariable& x)
|
||||
{
|
||||
auto result = 0.0;
|
||||
|
||||
for (decltype(x.size())
|
||||
i = 0, n = x.size(); i < n; ++i)
|
||||
{
|
||||
const auto m = std::abs(x[i]);
|
||||
result += m * m;
|
||||
}
|
||||
|
||||
return std::sqrt(result / x.size());
|
||||
}
|
||||
|
||||
template <class FieldVariable>
|
||||
double pointMetric(const FieldVariable& x)
|
||||
{
|
||||
static_assert(std::is_same<typename std::decay<decltype(std::abs(x[0]))>::type, double>::value,
|
||||
"Field Variable Value Type Must be 'double'");
|
||||
|
||||
if (x.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto max = 0*x[0] - 1;
|
||||
|
||||
for (decltype(x.size())
|
||||
i = 0, n = x.size(); i < n; ++i)
|
||||
{
|
||||
const auto t = std::abs(x[i]);
|
||||
|
||||
if (t > max) {
|
||||
max = t;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
std::vector<int>
|
||||
availableReportSteps(const example::FilePaths& paths)
|
||||
{
|
||||
using FilePtr = ::ERT::
|
||||
ert_unique_ptr<ecl_file_type, ecl_file_close>;
|
||||
|
||||
const auto rsspec_fn = example::
|
||||
deriveFileName(paths.grid, { ".RSSPEC", ".FRSSPEC" });
|
||||
|
||||
// Read-only, keep open between requests
|
||||
const auto open_flags = 0;
|
||||
|
||||
auto rsspec = FilePtr{
|
||||
ecl_file_open(rsspec_fn.generic_string().c_str(), open_flags)
|
||||
};
|
||||
|
||||
auto* globView = ecl_file_get_global_view(rsspec.get());
|
||||
|
||||
const auto* ITIME_kw = "ITIME";
|
||||
const auto n = ecl_file_view_get_num_named_kw(globView, ITIME_kw);
|
||||
|
||||
auto steps = std::vector<int>(n);
|
||||
|
||||
for (auto i = 0*n; i < n; ++i) {
|
||||
const auto* itime =
|
||||
ecl_file_view_iget_named_kw(globView, ITIME_kw, i);
|
||||
|
||||
const auto* itime_data =
|
||||
static_cast<const int*>(ecl_kw_iget_ptr(itime, 0));
|
||||
|
||||
steps[i] = itime_data[0];
|
||||
}
|
||||
|
||||
return steps;
|
||||
}
|
||||
|
||||
ErrorTolerance
|
||||
testTolerances(const ::Opm::parameter::ParameterGroup& param)
|
||||
{
|
||||
const auto atol = param.getDefault("atol", 1.0e-8);
|
||||
const auto rtol = param.getDefault("rtol", 5.0e-12);
|
||||
|
||||
return ErrorTolerance{ atol, rtol };
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
testQuantities(const ::Opm::parameter::ParameterGroup& param)
|
||||
{
|
||||
return StringUtils::VectorValue::
|
||||
get<std::string>(param.get<std::string>("quant"));
|
||||
}
|
||||
|
||||
int numDigits(const std::vector<int>& steps)
|
||||
{
|
||||
if (steps.empty()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto m =
|
||||
*std::max_element(std::begin(steps), std::end(steps));
|
||||
|
||||
if (m == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert (m > 0);
|
||||
|
||||
return std::floor(std::log10(static_cast<double>(m))) + 1;
|
||||
}
|
||||
|
||||
ReferenceSolution
|
||||
loadReference(const ::Opm::parameter::ParameterGroup& param,
|
||||
const std::string& quant,
|
||||
const int step,
|
||||
const int nDigits)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
using VRef = std::reference_wrapper<std::vector<double>>;
|
||||
|
||||
auto x = ReferenceSolution{};
|
||||
auto ref = std::array<VRef,2>{{ std::ref(x.raw) ,
|
||||
std::ref(x.SI ) }};
|
||||
|
||||
auto i = 0;
|
||||
|
||||
for (const auto* q : { "raw", "SI" }) {
|
||||
auto fname = fs::path(param.get<std::string>("ref-dir"))
|
||||
/ boost::algorithm::to_lower_copy(quant);
|
||||
{
|
||||
std::ostringstream os;
|
||||
|
||||
os << q << '-'
|
||||
<< std::setw(nDigits) << std::setfill('0')
|
||||
<< step << ".txt";
|
||||
|
||||
fname /= os.str();
|
||||
}
|
||||
|
||||
fs::ifstream input(fname);
|
||||
|
||||
if (input) {
|
||||
ref[i].get().assign(std::istream_iterator<double>(input),
|
||||
std::istream_iterator<double>());
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (x.raw.size() != x.SI.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Unable to Read Consistent Reference Data From '"
|
||||
<< param.get<std::string>("ref-dir") << "' In Step "
|
||||
<< step;
|
||||
|
||||
throw std::out_of_range(os.str());
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void computeErrors(const Reference& ref,
|
||||
const Calculated& calc,
|
||||
AggregateErrors& E)
|
||||
{
|
||||
const auto diff =
|
||||
VectorDifference(calc.data, ref.data); // calc - ref
|
||||
|
||||
using Vector1 = std::decay<decltype(diff)>::type;
|
||||
using Vector2 = std::decay<decltype(ref.data)>::type;
|
||||
using Ratio = VectorRatio<Vector1, Vector2>;
|
||||
|
||||
const auto rat = Ratio(diff, ref.data); // (tof - ref) / ref
|
||||
|
||||
auto abs = ErrorMeasurement{};
|
||||
{
|
||||
abs.volume = volumeMetric(diff);
|
||||
abs.inf = pointMetric (diff);
|
||||
}
|
||||
|
||||
auto rel = ErrorMeasurement{};
|
||||
{
|
||||
rel.volume = volumeMetric(rat);
|
||||
rel.inf = pointMetric (rat);
|
||||
}
|
||||
|
||||
E.absolute.push_back(std::move(abs));
|
||||
E.relative.push_back(std::move(rel));
|
||||
}
|
||||
|
||||
std::array<AggregateErrors, 2>
|
||||
sampleDifferences(const ::Opm::ECLGraph& graph,
|
||||
const ::Opm::parameter::ParameterGroup& param,
|
||||
const std::string& quant,
|
||||
const std::vector<int>& steps)
|
||||
{
|
||||
const auto ECLquant = boost::algorithm::to_upper_copy(quant);
|
||||
|
||||
auto unit = VectorUnits()
|
||||
.getUnit(boost::algorithm::to_lower_copy(quant));
|
||||
|
||||
const auto start =
|
||||
std::vector<Opm::FlowDiagnostics::CellSet>{};
|
||||
|
||||
const auto nDigits = numDigits(steps);
|
||||
|
||||
auto E = std::array<AggregateErrors, 2>{};
|
||||
|
||||
for (const auto& step : steps) {
|
||||
if (! graph.selectReportStep(step)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto ref = loadReference(param, quant, step, nDigits);
|
||||
|
||||
{
|
||||
const auto raw = Calculated {
|
||||
graph.rawLinearisedCellData<double>(ECLquant)
|
||||
};
|
||||
|
||||
computeErrors(Reference{ ref.raw }, raw, E[0]);
|
||||
}
|
||||
|
||||
{
|
||||
const auto SI = Calculated {
|
||||
graph.linearisedCellData(ECLquant, unit)
|
||||
};
|
||||
|
||||
computeErrors(Reference{ ref.SI }, SI, E[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
bool errorAcceptable(const std::vector<ErrorMeasurement>& E,
|
||||
const double tol)
|
||||
{
|
||||
return std::accumulate(std::begin(E), std::end(E), true,
|
||||
[tol](const bool ok, const ErrorMeasurement& e)
|
||||
{
|
||||
// Fine if at least one of .volume or .inf <= tol.
|
||||
return ok && ! ((e.volume > tol) && (e.inf > tol));
|
||||
});
|
||||
}
|
||||
|
||||
bool everythingFine(const AggregateErrors& E,
|
||||
const ErrorTolerance& tol)
|
||||
{
|
||||
return errorAcceptable(E.absolute, tol.absolute)
|
||||
&& errorAcceptable(E.relative, tol.relative);
|
||||
}
|
||||
} // namespace Anonymous
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
try {
|
||||
const auto prm = example::initParam(argc, argv);
|
||||
const auto pth = example::FilePaths(prm);
|
||||
const auto tol = testTolerances(prm);
|
||||
|
||||
const auto steps = availableReportSteps(pth);
|
||||
const auto graph = example::initGraph(pth);
|
||||
|
||||
auto all_ok = true;
|
||||
for (const auto& quant : testQuantities(prm)) {
|
||||
const auto E = sampleDifferences(graph, prm, quant, steps);
|
||||
|
||||
const auto ok =
|
||||
everythingFine(E[0], tol) && everythingFine(E[1], tol);
|
||||
|
||||
std::cout << quant << ": " << (ok ? "OK" : "FAIL") << '\n';
|
||||
|
||||
all_ok = all_ok && ok;
|
||||
}
|
||||
|
||||
if (! all_ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Caught Exception: " << e.what() << '\n';
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
229
ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/tests/runTransTest.cpp
vendored
Normal file
229
ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/tests/runTransTest.cpp
vendored
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
Copyright 2017 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2017 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/utility/ECLGraph.hpp>
|
||||
|
||||
#include <examples/exampleSetup.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
namespace {
|
||||
class VectorDifference
|
||||
{
|
||||
public:
|
||||
using Vector = std::vector<double>;
|
||||
using size_type = Vector::size_type;
|
||||
|
||||
VectorDifference(const Vector& x, const Vector& y)
|
||||
: x_(x), y_(y)
|
||||
{
|
||||
if (x_.size() != y_.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Incompatible Array Sizes: Expected 2x"
|
||||
<< x_.size() << ", but got ("
|
||||
<< x_.size() << ", " << y_.size() << ')';
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return x_.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return this->size() == 0;
|
||||
}
|
||||
|
||||
double operator[](const size_type i) const
|
||||
{
|
||||
return x_[i] - y_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
const Vector& x_;
|
||||
const Vector& y_;
|
||||
};
|
||||
|
||||
template <class Vector1, class Vector2>
|
||||
class VectorRatio
|
||||
{
|
||||
public:
|
||||
using size_type = typename std::decay<
|
||||
decltype(std::declval<Vector1>()[0])
|
||||
>::type;
|
||||
|
||||
VectorRatio(const Vector1& x, const Vector2& y)
|
||||
: x_(x), y_(y)
|
||||
{
|
||||
if (x_.size() != y.size()) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Incompatible Array Sizes: Expected 2x"
|
||||
<< x_.size() << ", but got ("
|
||||
<< x_.size() << ", " << y_.size() << ')';
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return x_.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return x_.empty();
|
||||
}
|
||||
|
||||
double operator[](const size_type i) const
|
||||
{
|
||||
return x_[i] / y_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
const Vector1& x_;
|
||||
const Vector2& y_;
|
||||
};
|
||||
|
||||
struct ErrorTolerance
|
||||
{
|
||||
double absolute;
|
||||
double relative;
|
||||
};
|
||||
|
||||
template <class FieldVariable>
|
||||
double pointMetric(const FieldVariable& x)
|
||||
{
|
||||
static_assert(std::is_same<typename std::decay<decltype(std::abs(x[0]))>::type, double>::value,
|
||||
"Field Variable Value Type Must be 'double'");
|
||||
|
||||
if (x.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto max = 0*x[0] - 1;
|
||||
|
||||
for (decltype(x.size())
|
||||
i = 0, n = x.size(); i < n; ++i)
|
||||
{
|
||||
const auto t = std::abs(x[i]);
|
||||
|
||||
if (t > max) {
|
||||
max = t;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
ErrorTolerance
|
||||
testTolerances(const ::Opm::parameter::ParameterGroup& param)
|
||||
{
|
||||
const auto atol = param.getDefault("atol", 1.0e-8);
|
||||
const auto rtol = param.getDefault("rtol", 5.0e-12);
|
||||
|
||||
return ErrorTolerance{ atol, rtol };
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
loadReference(const ::Opm::parameter::ParameterGroup& param)
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
const auto fname =
|
||||
fs::path(param.get<std::string>("ref-dir")) / "trans.txt";
|
||||
|
||||
fs::ifstream input(fname);
|
||||
|
||||
if (! input) {
|
||||
std::ostringstream os;
|
||||
|
||||
os << "Unable to Open Reference Trans-Data File "
|
||||
<< fname.filename();
|
||||
|
||||
throw std::domain_error(os.str());
|
||||
}
|
||||
|
||||
return {
|
||||
std::istream_iterator<double>(input),
|
||||
std::istream_iterator<double>()
|
||||
};
|
||||
}
|
||||
|
||||
bool transfieldAcceptable(const ::Opm::parameter::ParameterGroup& param,
|
||||
const std::vector<double>& trans)
|
||||
{
|
||||
const auto Tref = loadReference(param);
|
||||
|
||||
if (Tref.size() != trans.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto diff = VectorDifference{ trans, Tref };
|
||||
|
||||
using Vector1 = std::decay<decltype(diff)>::type;
|
||||
using Vector2 = std::decay<decltype(Tref)>::type;
|
||||
using Ratio = VectorRatio<Vector1, Vector2>;
|
||||
|
||||
const auto rat = Ratio(diff, Tref);
|
||||
const auto tol = testTolerances(param);
|
||||
|
||||
return ! ((pointMetric(diff) > tol.absolute) ||
|
||||
(pointMetric(rat) > tol.relative));
|
||||
}
|
||||
} // namespace Anonymous
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
try {
|
||||
const auto prm = example::initParam(argc, argv);
|
||||
const auto pth = example::FilePaths(prm);
|
||||
const auto G = example::initGraph(pth);
|
||||
const auto T = G.transmissibility();
|
||||
const auto ok = transfieldAcceptable(prm, T);
|
||||
|
||||
std::cout << (ok ? "OK" : "FAIL") << '\n';
|
||||
|
||||
if (! ok) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Caught Exception: " << e.what() << '\n';
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
235
ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/tests/test_eclunithandling.cpp
vendored
Normal file
235
ThirdParty/custom-opm-flowdiag-app/opm-flowdiagnostics-applications/tests/test_eclunithandling.cpp
vendored
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
Copyright 2017 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2017 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media Project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#if HAVE_DYNAMIC_BOOST_TEST
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
#endif
|
||||
|
||||
#define NVERBOSE
|
||||
|
||||
#define BOOST_TEST_MODULE TEST_ASSEMBLED_CONNECTIONS
|
||||
|
||||
#include <opm/common/utility/platform_dependent/disable_warnings.h>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
|
||||
|
||||
#include <opm/utility/ECLUnitHandling.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
BOOST_AUTO_TEST_SUITE (Basic_Conversion)
|
||||
|
||||
BOOST_AUTO_TEST_CASE (Constructor)
|
||||
{
|
||||
auto M = ::Opm::ECLUnits::createUnitSystem(1); // METRIC
|
||||
auto F = ::Opm::ECLUnits::createUnitSystem(2); // FIELD
|
||||
auto L = ::Opm::ECLUnits::createUnitSystem(3); // LAB
|
||||
auto P = ::Opm::ECLUnits::createUnitSystem(4); // PVT-M
|
||||
|
||||
BOOST_CHECK_THROW(::Opm::ECLUnits::createUnitSystem( 5), std::runtime_error);
|
||||
BOOST_CHECK_THROW(::Opm::ECLUnits::createUnitSystem(-1), std::runtime_error);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE (Metric)
|
||||
{
|
||||
auto M = ::Opm::ECLUnits::createUnitSystem(1);
|
||||
|
||||
// Pressure (bars)
|
||||
{
|
||||
const auto scale = M->pressure();
|
||||
const auto expect = 100.0e3;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Reservoir Volume Rate (rm^3 / day)
|
||||
{
|
||||
const auto scale = M->reservoirRate();
|
||||
const auto expect = 1.157407407407407e-05;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Reservoir Volume (rm^3)
|
||||
{
|
||||
const auto scale = M->reservoirVolume();
|
||||
const auto expect = 1.0;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Time (day)
|
||||
{
|
||||
const auto scale = M->time();
|
||||
const auto expect = 86.400e+03;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Transmissibility ((cP * m^3) / (day * barsa))
|
||||
{
|
||||
const auto scale = M->transmissibility();
|
||||
const auto expect = 1.157407407407407e-13;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE (Field)
|
||||
{
|
||||
auto F = ::Opm::ECLUnits::createUnitSystem(2);
|
||||
|
||||
// Pressure (psi)
|
||||
{
|
||||
const auto scale = F->pressure();
|
||||
const auto expect = 6.894757293168360e+03;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Reservoir Volume Rate (rb / day)
|
||||
{
|
||||
const auto scale = F->reservoirRate();
|
||||
const auto expect = 1.840130728333334e-06;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Reservoir Volume (rb)
|
||||
{
|
||||
const auto scale = F->reservoirVolume();
|
||||
const auto expect = 1.589872949280001e-01;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Time (day)
|
||||
{
|
||||
const auto scale = F->time();
|
||||
const auto expect = 86.400e+03;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Transmissibility ((cP * rb) / (day * psia))
|
||||
{
|
||||
const auto scale = F->transmissibility();
|
||||
const auto expect = 2.668883979653090e-13;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE (Lab)
|
||||
{
|
||||
auto L = ::Opm::ECLUnits::createUnitSystem(3);
|
||||
|
||||
// Pressure (atm)
|
||||
{
|
||||
const auto scale = L->pressure();
|
||||
const auto expect = 101.325e+03;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Reservoir Volume Rate (r(cm)^3 / h)
|
||||
{
|
||||
const auto scale = L->reservoirRate();
|
||||
const auto expect = 2.777777777777778e-10;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Reservoir Volume (r(cm)^3)
|
||||
{
|
||||
const auto scale = L->reservoirVolume();
|
||||
const auto expect = 1.0e-06;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Time (hour)
|
||||
{
|
||||
const auto scale = L->time();
|
||||
const auto expect = 3600.0;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Transmissibility ((cP * (cm)^3) / (h * atm))
|
||||
{
|
||||
const auto scale = L->transmissibility();
|
||||
const auto expect = 2.741453518655592e-18;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE (PVT_M)
|
||||
{
|
||||
auto P = ::Opm::ECLUnits::createUnitSystem(4);
|
||||
|
||||
// Pressure (atm)
|
||||
{
|
||||
const auto scale = P->pressure();
|
||||
const auto expect = 101.325e+03;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Reservoir Volume Rate (rm^3 / day)
|
||||
{
|
||||
const auto scale = P->reservoirRate();
|
||||
const auto expect = 1.157407407407407e-05;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Reservoir Volume (rm^3)
|
||||
{
|
||||
const auto scale = P->reservoirVolume();
|
||||
const auto expect = 1.0;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Time (day)
|
||||
{
|
||||
const auto scale = P->time();
|
||||
const auto expect = 86.400e+03;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
|
||||
// Transmissibility ((cP * rm^3 / (day * atm))
|
||||
{
|
||||
const auto scale = P->transmissibility();
|
||||
const auto expect = 1.142272299439830e-13;
|
||||
|
||||
BOOST_CHECK_CLOSE(scale, expect, 1.0e-10);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END ()
|
||||
Reference in New Issue
Block a user