Merge pull request #2114 from joakim-hove/summary-oip

Add container to hold on to Original in place values
This commit is contained in:
Joakim Hove 2020-11-19 17:12:51 +01:00 committed by GitHub
commit 767f77e8c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 361 additions and 0 deletions

View File

@ -286,6 +286,7 @@ if(ENABLE_ECL_OUTPUT)
src/opm/output/eclipse/LoadRestart.cpp
src/opm/output/eclipse/LogiHEAD.cpp
src/opm/output/eclipse/RestartIO.cpp
src/opm/output/eclipse/Inplace.cpp
src/opm/output/eclipse/Summary.cpp
src/opm/output/eclipse/Tables.cpp
src/opm/output/eclipse/RegionCache.cpp
@ -411,6 +412,7 @@ if(ENABLE_ECL_OUTPUT)
tests/test_rst.cpp
tests/test_Solution.cpp
tests/test_Serializer.cpp
tests/test_Inplace.cpp
tests/test_Summary.cpp
tests/test_Summary_Group.cpp
tests/test_Tables.cpp
@ -832,6 +834,7 @@ if(ENABLE_ECL_OUTPUT)
opm/output/eclipse/RegionCache.hpp
opm/output/eclipse/RestartIO.hpp
opm/output/eclipse/RestartValue.hpp
opm/output/eclipse/Inplace.hpp
opm/output/eclipse/Summary.hpp
opm/output/eclipse/Tables.hpp
opm/output/eclipse/WindowedArray.hpp

View File

@ -0,0 +1,86 @@
/*
Copyright 2020 Equinor 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/>.
*/
#ifndef ORIGINAL_OIP
#define ORIGINAL_OIP
#include <string>
#include <unordered_map>
#include <vector>
namespace Opm {
class Inplace {
public:
enum class Phase {
WATER = 0,
OIL = 1,
GAS = 2,
OilInLiquidPhase = 3,
OilInGasPhase = 4,
GasInLiquidPhase = 5,
GasInGasPhase = 6,
PoreVolume = 7
};
/*
The purpose of this class is to transport inplace values from the
simulator code to the summary output code. The code is written very much
to fit in with the current implementation in the simulator, in particular
that the add/get functions exist in two varieties is a result of that.
The functions which don't accept region_name & region_number arguments
should be called for totals, i.e. field properties.
*/
void add(const std::string& region, const std::string& tag, std::size_t region_number, double value);
void add(const std::string& region, Phase phase, std::size_t region_number, double value);
void add(Phase phase, double value);
void add(const std::string& tag, double value);
double get(const std::string& region, const std::string& tag, std::size_t region_number) const;
double get(const std::string& region, Phase phase, std::size_t region_number) const;
double get(Phase phase) const;
double get(const std::string& tag) const;
std::size_t max_region() const;
std::size_t max_region(const std::string& region_name) const;
/*
The get_vector functions return a vector length max_region() which
contains the values added with the add() function and indexed with
(region_number - 1). This is an incarnation of id <-> index confusion and
should be replaced with a std::map instead.
*/
std::vector<double> get_vector(const std::string& region, const std::string& tag) const;
std::vector<double> get_vector(const std::string& region, Phase phase) const;
static const std::vector<Phase>& phases();
private:
std::unordered_map<std::string, std::unordered_map<Phase, std::unordered_map<std::size_t, double>>> phase_values;
std::unordered_map<std::string, std::unordered_map<std::string, std::unordered_map<std::size_t, double>>> tag_values;
};
}
#endif

View File

@ -0,0 +1,189 @@
/*
Copyright 2020 Equinor 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 <algorithm>
#include <exception>
#include <fmt/format.h>
#include <opm/output/eclipse/Inplace.hpp>
namespace Opm {
namespace {
static const std::string FIELD_NAME = std::string{"FIELD"};
static const std::size_t FIELD_ID = 0;
}
void Inplace::add(const std::string& region, const std::string& tag, std::size_t region_id, double value) {
this->tag_values[region][tag][region_id] = value;
}
void Inplace::add(const std::string& region, Inplace::Phase phase, std::size_t region_id, double value) {
this->phase_values[region][phase][region_id] = value;
}
void Inplace::add(Inplace::Phase phase, double value) {
this->add( FIELD_NAME, phase, FIELD_ID, value );
}
void Inplace::add(const std::string& tag, double value) {
this->add( FIELD_NAME, tag, FIELD_ID, value );
}
double Inplace::get(const std::string& region, const std::string& tag, std::size_t region_id) const {
auto region_iter = this->tag_values.find(region);
if (region_iter == this->tag_values.end())
throw std::logic_error(fmt::format("No such region: {}", region));
auto tag_iter = region_iter->second.find(tag);
if (tag_iter == region_iter->second.end())
throw std::logic_error(fmt::format("No such tag: {}:{}", region, tag));
auto value_iter = tag_iter->second.find(region_id);
if (value_iter == tag_iter->second.end())
throw std::logic_error(fmt::format("No such region id: {}:{}:{}", region, tag, region_id));
return value_iter->second;
}
double Inplace::get(const std::string& region, Inplace::Phase phase, std::size_t region_id) const {
auto region_iter = this->phase_values.find(region);
if (region_iter == this->phase_values.end())
throw std::logic_error(fmt::format("No such region: {}", region));
auto phase_iter = region_iter->second.find(phase);
if (phase_iter == region_iter->second.end())
throw std::logic_error(fmt::format("No such phase: {}:{}", region, static_cast<int>(phase)));
auto value_iter = phase_iter->second.find(region_id);
if (value_iter == phase_iter->second.end())
throw std::logic_error(fmt::format("No such region id: {}:{}:{}", region, static_cast<int>(phase), region_id));
return value_iter->second;
}
double Inplace::get(Inplace::Phase phase) const {
return this->get(FIELD_NAME, phase, FIELD_ID);
}
double Inplace::get(const std::string& tag) const {
return this->get(FIELD_NAME, tag, FIELD_ID);
}
namespace {
std::size_t region_max(const std::unordered_map<std::size_t, double>& region_map) {
std::size_t max_value = 0;
for (const auto& [region_id, _] : region_map) {
(void)_;
max_value = std::max(max_value, region_id);
}
return max_value;
}
}
std::size_t Inplace::max_region() const {
std::size_t max_value = 0;
for (const auto& [_, phase_map] : this->phase_values) {
(void)_;
for (const auto& [__, region_map] : phase_map) {
(void)__;
max_value = std::max(max_value, region_max(region_map));
}
}
for (const auto& [_, string_map] : this->tag_values) {
(void)_;
for (const auto& [__, region_map] : string_map) {
(void)__;
max_value = std::max(max_value, region_max(region_map));
}
}
return max_value;
}
std::size_t Inplace::max_region(const std::string& region_name) const {
std::optional<std::size_t> max_value;
{
const auto& region_iter = this->phase_values.find(region_name);
if (region_iter != this->phase_values.end()) {
max_value = 0;
for (const auto& [_, region_map] : region_iter->second) {
(void)_;
max_value = std::max(*max_value, region_max(region_map));
}
}
}
{
const auto& region_iter = this->tag_values.find(region_name);
if (region_iter != this->tag_values.end()) {
if (!max_value.has_value())
max_value = 0;
for (const auto& [_, region_map] : region_iter->second) {
(void)_;
max_value = std::max(*max_value, region_max(region_map));
}
}
}
if (!max_value.has_value())
throw std::logic_error(fmt::format("No such region: {}", region_name));
return max_value.value();
}
// This should probably die - temporarily added for porting of ecloutputblackoilmodule
std::vector<double> Inplace::get_vector(const std::string& region, Phase phase) const {
std::vector<double> v(this->max_region(region), 0);
const auto& region_map = this->phase_values.at(region).at(phase);
for (const auto& [region_id, value] : region_map)
v[region_id - 1] = value;
return v;
}
std::vector<double> Inplace::get_vector(const std::string& region, const std::string& tag) const {
std::vector<double> v(this->max_region(region), 0);
const auto& region_map = this->tag_values.at(region).at(tag);
for (const auto& [region_id, value] : region_map)
v[region_id - 1] = value;
return v;
}
const std::vector<Inplace::Phase>& Inplace::phases() {
static const std::vector<Phase> phases_ = {
Inplace::Phase::WATER,
Inplace::Phase::OIL,
Inplace::Phase::GAS,
Inplace::Phase::OilInLiquidPhase,
Inplace::Phase::OilInGasPhase,
Inplace::Phase::GasInLiquidPhase,
Inplace::Phase::GasInGasPhase,
Inplace::Phase::PoreVolume
};
return phases_;
}
}

83
tests/test_Inplace.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
Copyright 2020 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/>.
*/
#define BOOST_TEST_MODULE Inplace
#include <boost/test/unit_test.hpp>
#include <opm/output/eclipse/Inplace.hpp>
using namespace Opm;
bool contains(const std::vector<Inplace::Phase>& phases, Inplace::Phase phase) {
auto find_iter = std::find(phases.begin(), phases.end(), phase);
return find_iter != phases.end();
}
BOOST_AUTO_TEST_CASE(TESTInplace) {
Inplace oip;
oip.add("FIPNUM", Inplace::Phase::OIL, 3, 100);
oip.add("FIPNUM", Inplace::Phase::OIL, 6, 50);
oip.add("FIPNUM", "StringID", 5, 200);
BOOST_CHECK_EQUAL( oip.get("FIPNUM", Inplace::Phase::OIL, 3) , 100);
BOOST_CHECK_EQUAL( oip.get("FIPNUM", Inplace::Phase::OIL, 6) , 50);
BOOST_CHECK_EQUAL( oip.get("FIPNUM", "StringID", 5) , 200);
BOOST_CHECK_THROW( oip.get("FIPNUM", Inplace::Phase::OIL, 4), std::exception);
BOOST_CHECK_THROW( oip.get("FIPNUM", Inplace::Phase::GAS, 3), std::exception);
BOOST_CHECK_THROW( oip.get("FIPX", Inplace::Phase::OIL, 3) , std::exception);
BOOST_CHECK_THROW( oip.get("FIPNUM", "StringID", 4), std::exception);
BOOST_CHECK_THROW( oip.get("FIPNUM", "XXX", 3), std::exception);
BOOST_CHECK_THROW( oip.get("FIPX", "StringID", 3) , std::exception);
BOOST_CHECK_EQUAL( oip.max_region(), 6);
BOOST_CHECK_EQUAL( oip.max_region("FIPNUM"), 6);
BOOST_CHECK_THROW( oip.max_region("FIPX"), std::exception);
oip.add(Inplace::Phase::GAS, 100);
BOOST_CHECK_EQUAL( oip.get(Inplace::Phase::GAS) , 100);
BOOST_CHECK_THROW( oip.get(Inplace::Phase::OIL), std::exception);
const auto& phases = Inplace::phases();
BOOST_CHECK(contains(phases, Inplace::Phase::WATER));
BOOST_CHECK(contains(phases, Inplace::Phase::OIL));
BOOST_CHECK(contains(phases, Inplace::Phase::GAS));
BOOST_CHECK(contains(phases, Inplace::Phase::OilInLiquidPhase));
BOOST_CHECK(contains(phases, Inplace::Phase::OilInGasPhase));
BOOST_CHECK(contains(phases, Inplace::Phase::GasInLiquidPhase));
BOOST_CHECK(contains(phases, Inplace::Phase::GasInGasPhase));
BOOST_CHECK(contains(phases, Inplace::Phase::PoreVolume));
auto v1 = oip.get_vector("FIPNUM", Inplace::Phase::OIL);
std::vector<double> e1 = {0,0,100,0,0,50};
BOOST_CHECK( v1 == e1 );
auto v2 = oip.get_vector("FIPNUM", "StringID");
std::vector<double> e2 = {0,0,0,0,200,0};
BOOST_CHECK( v2 == e2 );
}