diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake
index cea6e0e83..926127cc9 100644
--- a/CMakeLists_files.cmake
+++ b/CMakeLists_files.cmake
@@ -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
diff --git a/opm/output/eclipse/Inplace.hpp b/opm/output/eclipse/Inplace.hpp
new file mode 100644
index 000000000..e840e48b0
--- /dev/null
+++ b/opm/output/eclipse/Inplace.hpp
@@ -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 .
+*/
+
+#ifndef ORIGINAL_OIP
+#define ORIGINAL_OIP
+
+#include
+#include
+#include
+
+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 get_vector(const std::string& region, const std::string& tag) const;
+ std::vector get_vector(const std::string& region, Phase phase) const;
+
+ static const std::vector& phases();
+private:
+ std::unordered_map>> phase_values;
+ std::unordered_map>> tag_values;
+};
+
+
+}
+
+#endif
diff --git a/src/opm/output/eclipse/Inplace.cpp b/src/opm/output/eclipse/Inplace.cpp
new file mode 100644
index 000000000..da182005a
--- /dev/null
+++ b/src/opm/output/eclipse/Inplace.cpp
@@ -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 .
+*/
+
+#include
+#include
+
+#include
+
+#include
+
+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(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(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& 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 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 Inplace::get_vector(const std::string& region, Phase phase) const {
+ std::vector 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 Inplace::get_vector(const std::string& region, const std::string& tag) const {
+ std::vector 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::phases() {
+ static const std::vector 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_;
+}
+
+
+}
diff --git a/tests/test_Inplace.cpp b/tests/test_Inplace.cpp
new file mode 100644
index 000000000..827278854
--- /dev/null
+++ b/tests/test_Inplace.cpp
@@ -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 .
+*/
+
+#define BOOST_TEST_MODULE Inplace
+#include
+
+
+
+#include
+
+using namespace Opm;
+
+
+bool contains(const std::vector& 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 e1 = {0,0,100,0,0,50};
+ BOOST_CHECK( v1 == e1 );
+
+ auto v2 = oip.get_vector("FIPNUM", "StringID");
+ std::vector e2 = {0,0,0,0,200,0};
+ BOOST_CHECK( v2 == e2 );
+}