Merge pull request #2114 from joakim-hove/summary-oip
Add container to hold on to Original in place values
This commit is contained in:
commit
767f77e8c8
@ -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
|
||||
|
86
opm/output/eclipse/Inplace.hpp
Normal file
86
opm/output/eclipse/Inplace.hpp
Normal 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
|
189
src/opm/output/eclipse/Inplace.cpp
Normal file
189
src/opm/output/eclipse/Inplace.cpp
Normal 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
83
tests/test_Inplace.cpp
Normal 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 );
|
||||
}
|
Loading…
Reference in New Issue
Block a user