diff --git a/opm/simulators/linalg/PropertyTree.cpp b/opm/simulators/linalg/PropertyTree.cpp index a64c4b30c..5f747efc9 100644 --- a/opm/simulators/linalg/PropertyTree.cpp +++ b/opm/simulators/linalg/PropertyTree.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace Opm { @@ -95,6 +96,25 @@ PropertyTree::get_child_optional(const std::string& key) const return PropertyTree(pt.get()); } +template +std::optional> +PropertyTree::get_child_items_as_vector(const std::string& child) const +{ + auto items = std::optional>{}; + + auto subTree = this->tree_->get_child_optional(child); + if (! subTree) { + return items; + } + + items.emplace(); + for (const auto& childItem : *subTree) { + items->push_back(childItem.second.template get_value()); + } + + return items; +} + PropertyTree& PropertyTree::operator=(const PropertyTree& tree) { tree_ = std::make_unique(*tree.tree_); @@ -121,4 +141,9 @@ template int PropertyTree::get(const std::string& key, const int& defValue) cons template std::size_t PropertyTree::get(const std::string& key, const std::size_t& defValue) const; template bool PropertyTree::get(const std::string& key, const bool& defValue) const; +template std::optional> +PropertyTree::get_child_items_as_vector(const std::string& child) const; +template std::optional> +PropertyTree::get_child_items_as_vector(const std::string& child) const; + } // namespace Opm diff --git a/opm/simulators/linalg/PropertyTree.hpp b/opm/simulators/linalg/PropertyTree.hpp index 2799eac16..3d6254248 100644 --- a/opm/simulators/linalg/PropertyTree.hpp +++ b/opm/simulators/linalg/PropertyTree.hpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace boost::property_tree { template class basic_ptree; @@ -128,6 +129,23 @@ public: std::optional get_child_optional(const std::string& key) const; + /// Retrieve node items as linearised vector. + /// + /// Assumes that the node's child is an array type of homongeneous + /// elements. + /// + /// \tparam T Array element type. + /// + /// \param[in] child Property key. Expected to be in hierarchical + /// notation for subtrees--i.e., using periods ('.') to separate + /// hierarchy levels. + /// + /// \return Array of property values. Nullopt if no node named by \p + /// child exists. + template + std::optional> + get_child_items_as_vector(const std::string& child) const; + /// Emit a textual representation of the property tree in JSON form /// /// \param[in,out] os Output stream. Typically a stream opened on a diff --git a/tests/test_propertytree.cpp b/tests/test_propertytree.cpp index f75fa8341..6b6891b79 100644 --- a/tests/test_propertytree.cpp +++ b/tests/test_propertytree.cpp @@ -259,4 +259,37 @@ BOOST_AUTO_TEST_CASE(Hierarchy) } } +BOOST_AUTO_TEST_CASE(Vector) +{ + auto f = TempFile{}; + f.append(R"({ + "a" : [ 1, 2, 3, 4 ], + "b" : [ 11.22, 33.44 ] +})"); + + const auto t = Opm::PropertyTree { f.name() }; + + { + const auto a = t.get_child_items_as_vector("a"); + BOOST_REQUIRE_MESSAGE(a.has_value(), R"(Node "a" must exist)"); + + const auto expect = std::vector { 1, 2, 3, 4, }; + BOOST_CHECK_EQUAL_COLLECTIONS(a ->begin(), a ->end(), + expect.begin(), expect.end()); + } + + { + const auto b = t.get_child_items_as_vector("b"); + BOOST_REQUIRE_MESSAGE(b.has_value(), R"(Node "b" must exist)"); + + const auto expect = std::vector { 11.22, 33.44, }; + BOOST_REQUIRE_EQUAL(b->size(), expect.size()); + + for (auto i = 0*b->size(); i < b->size(); ++i) { + BOOST_TEST_MESSAGE("Element " << i); + BOOST_CHECK_CLOSE((*b)[i], expect[i], 1.0e-8); + } + } +} + BOOST_AUTO_TEST_SUITE_END() // Load_From_File