From c69beedb303c36908587d63088523c3e7df3bc84 Mon Sep 17 00:00:00 2001 From: Kristian Flikka Date: Wed, 20 Nov 2013 13:48:55 +0100 Subject: [PATCH] Added support for re-parenting a node --- .../EclipseState/Schedule/GroupTree.cpp | 52 ++++++++++++---- .../EclipseState/Schedule/GroupTree.hpp | 9 +-- .../EclipseState/Schedule/GroupTreeNode.cpp | 27 ++++---- .../EclipseState/Schedule/GroupTreeNode.hpp | 7 +-- .../Schedule/tests/GroupTreeNodeTests.cpp | 42 ++++++++----- .../Schedule/tests/GroupTreeTests.cpp | 62 ++++++++++++++++--- .../ScheduleCreateFromDeck.cpp | 34 ++++++++++ .../SCHEDULE/SCHEDULE_GROUPS_REPARENT | 20 ++++++ 8 files changed, 196 insertions(+), 57 deletions(-) create mode 100644 testdata/integration_tests/SCHEDULE/SCHEDULE_GROUPS_REPARENT diff --git a/opm/parser/eclipse/EclipseState/Schedule/GroupTree.cpp b/opm/parser/eclipse/EclipseState/Schedule/GroupTree.cpp index c209e5d9b..7eea536d4 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/GroupTree.cpp +++ b/opm/parser/eclipse/EclipseState/Schedule/GroupTree.cpp @@ -31,21 +31,28 @@ namespace Opm { } GroupTreeNodePtr GroupTree::updateTree(const std::string& childName) { - if (getNode(childName)) { - throw std::invalid_argument("Node \"" + childName + "\" is already in tree, cannot move (yet)"); - } - return m_root->addChildGroup(childName); + return updateTree(childName, m_root->name()); } GroupTreeNodePtr GroupTree::updateTree(const std::string& childName, const std::string& parentName) { - if (getNode(childName)) { - throw std::invalid_argument("Node \"" + childName + "\" is already in tree, cannot move (yet)"); + if (childName == m_root->name()) { + throw std::domain_error("Error, trying to add node with the same name as the root, offending name: " + childName); } - GroupTreeNodePtr parentNode = getNode(parentName); - if (!parentNode) { - parentNode = updateTree(parentName); + + GroupTreeNodePtr newParentNode = getNode(parentName); + if (!newParentNode) { + newParentNode = updateTree(parentName); + } + + GroupTreeNodePtr childNodeInTree = getNode(childName); + if (childNodeInTree) { + GroupTreeNodePtr currentParent = getParent(childName); + currentParent->removeChild(childNodeInTree); + newParentNode->addChildGroup(childNodeInTree); + return childNodeInTree; + } else { + return newParentNode->addChildGroup(childName); } - return parentNode->addChildGroup(childName); } GroupTreeNodePtr GroupTree::getNode(const std::string& nodeName) const { @@ -59,7 +66,28 @@ namespace Opm { } else { std::map::iterator iter = current->begin(); while (iter != current->end()) { - GroupTreeNodePtr result = getNode(nodeName, (*iter).second); + GroupTreeNodePtr result = getNode(nodeName, (*iter).second); + if (result) { + return result; + } + ++iter; + } + return GroupTreeNodePtr(); + } + } + + GroupTreeNodePtr GroupTree::getParent(const std::string& childName) const { + GroupTreeNodePtr currentChild = m_root; + return getParent(childName, currentChild, GroupTreeNodePtr()); + } + + GroupTreeNodePtr GroupTree::getParent(const std::string& childName, GroupTreeNodePtr currentChild, GroupTreeNodePtr parent) const { + if (currentChild->name() == childName) { + return parent; + } else { + std::map::iterator iter = currentChild->begin(); + while (iter != currentChild->end()) { + GroupTreeNodePtr result = getParent(childName, (*iter).second, currentChild); if (result) { return result; } @@ -100,7 +128,7 @@ namespace Opm { std::map::iterator iter = fromNode->begin(); while (iter != fromNode->end()) { GroupTreeNodePtr child = (*iter).second; - std::cout << "<-" << child->name() << "(" << child.get() << ")" << std::endl; + std::cout << "<-" << child->name() << "(" << child.get() << ")" << std::endl; printTree(child); ++iter; } diff --git a/opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp b/opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp index f3e1b1b35..b99261c90 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/GroupTree.hpp @@ -32,9 +32,11 @@ namespace Opm { public: GroupTree(); GroupTreeNodePtr updateTree(const std::string& childName); - GroupTreeNodePtr updateTree(const std::string& childName, const std::string& parentName ); + GroupTreeNodePtr updateTree(const std::string& childName, const std::string& parentName); GroupTreeNodePtr getNode(const std::string& nodeName) const; + GroupTreeNodePtr getParent(const std::string& childName) const; + boost::shared_ptr deepCopy() const; void printTree() const; @@ -42,11 +44,10 @@ namespace Opm { private: GroupTreeNodePtr m_root; GroupTreeNodePtr getNode(const std::string& nodeName, GroupTreeNodePtr current) const; + GroupTreeNodePtr getParent(const std::string& childName, GroupTreeNodePtr currentChild, GroupTreeNodePtr parent) const; + void deepCopy(GroupTreeNodePtr origin, GroupTreeNodePtr copy) const; void printTree(GroupTreeNodePtr fromNode) const; - - - }; typedef boost::shared_ptr GroupTreePtr; diff --git a/opm/parser/eclipse/EclipseState/Schedule/GroupTreeNode.cpp b/opm/parser/eclipse/EclipseState/Schedule/GroupTreeNode.cpp index 2979380ef..878a96520 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/GroupTreeNode.cpp +++ b/opm/parser/eclipse/EclipseState/Schedule/GroupTreeNode.cpp @@ -24,30 +24,35 @@ namespace Opm { GroupTreeNode::GroupTreeNode(const std::string& name) { m_name = name; - m_parent = NULL; - } - - GroupTreeNode::GroupTreeNode(const std::string& name, GroupTreeNode * parent) { - m_name = name; - m_parent = parent; } const std::string& GroupTreeNode::name() const { return m_name; } - GroupTreeNode * GroupTreeNode::parent() const { - return m_parent; - } - GroupTreeNodePtr GroupTreeNode::addChildGroup(const std::string& childName) { if (hasChildGroup(childName)) { throw std::invalid_argument("Child group with name \"" + childName + "\"already exists."); } - GroupTreeNodePtr child(new GroupTreeNode(childName, this)); + GroupTreeNodePtr child(new GroupTreeNode(childName)); m_childGroups[childName] = child; return child; } + + void GroupTreeNode::addChildGroup(boost::shared_ptr childGroup) { + if (hasChildGroup(childGroup->name())) { + throw std::invalid_argument("Child group with name \"" + childGroup->name() + "\"already exists under node " + m_name); + } + m_childGroups[childGroup->name()] = childGroup; + } + + + void GroupTreeNode::removeChild(GroupTreeNodePtr child) { + if (!hasChildGroup(child->name())) { + throw std::invalid_argument("The node " + m_name + " does not have a child named " + child->name()); + } + m_childGroups.erase(child->name()); + } bool GroupTreeNode::hasChildGroup(const std::string& childName) const { return m_childGroups.find(childName) != m_childGroups.end(); diff --git a/opm/parser/eclipse/EclipseState/Schedule/GroupTreeNode.hpp b/opm/parser/eclipse/EclipseState/Schedule/GroupTreeNode.hpp index 0bd30d837..abbc5bff8 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/GroupTreeNode.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/GroupTreeNode.hpp @@ -32,12 +32,13 @@ namespace Opm { class GroupTreeNode { public: const std::string& name() const; - GroupTreeNode * parent() const; boost::shared_ptr addChildGroup(const std::string& childName); + void addChildGroup(boost::shared_ptr childGroup); + bool hasChildGroup(const std::string& childName) const; + void removeChild(boost::shared_ptr child); boost::shared_ptr getChildGroup(const std::string& childName); - void setParent(GroupTreeNode * parent); static boost::shared_ptr createFieldNode(); std::map >::iterator begin(); std::map >::iterator end(); @@ -45,10 +46,8 @@ namespace Opm { private: GroupTreeNode(const std::string& name); - GroupTreeNode(const std::string& name, GroupTreeNode * parent); std::string m_name; std::map > m_childGroups; - GroupTreeNode * m_parent; }; typedef boost::shared_ptr GroupTreeNodePtr; diff --git a/opm/parser/eclipse/EclipseState/Schedule/tests/GroupTreeNodeTests.cpp b/opm/parser/eclipse/EclipseState/Schedule/tests/GroupTreeNodeTests.cpp index f779fd158..4b9f40f6f 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/tests/GroupTreeNodeTests.cpp +++ b/opm/parser/eclipse/EclipseState/Schedule/tests/GroupTreeNodeTests.cpp @@ -33,20 +33,6 @@ BOOST_AUTO_TEST_CASE(CreateFieldNode) { BOOST_CHECK_EQUAL("FIELD", node->name()); } - -BOOST_AUTO_TEST_CASE(CreateFieldNode_HasNoParent) { - GroupTreeNodePtr node = GroupTreeNode::createFieldNode(); - BOOST_CHECK(!node->parent()); -} - - -BOOST_AUTO_TEST_CASE(CreateChild_WithFieldParent_ParentSet) { - GroupTreeNodePtr fieldNode = GroupTreeNode::createFieldNode(); - GroupTreeNodePtr child = fieldNode->addChildGroup("Child"); - BOOST_CHECK_EQUAL(fieldNode.get(), child->parent()); -} - - BOOST_AUTO_TEST_CASE(CreateChild_WithFieldParent_ParentHasChild) { GroupTreeNodePtr fieldNode = GroupTreeNode::createFieldNode(); BOOST_CHECK(!fieldNode->hasChildGroup("Child")); @@ -55,16 +41,38 @@ BOOST_AUTO_TEST_CASE(CreateChild_WithFieldParent_ParentHasChild) { BOOST_CHECK_EQUAL(child, fieldNode->getChildGroup("Child")); } - BOOST_AUTO_TEST_CASE(CreateChildGroup_ChildExists_Throws) { GroupTreeNodePtr fieldNode = GroupTreeNode::createFieldNode(); GroupTreeNodePtr child = fieldNode->addChildGroup("Child"); BOOST_CHECK_THROW(fieldNode->addChildGroup("Child"), std::invalid_argument); } - BOOST_AUTO_TEST_CASE(GetChildGroup_ChildNotExisting_Throws) { GroupTreeNodePtr fieldNode = GroupTreeNode::createFieldNode(); GroupTreeNodePtr child = fieldNode->addChildGroup("Child2"); BOOST_CHECK_THROW(fieldNode->getChildGroup("Child"), std::invalid_argument); -} \ No newline at end of file +} + + +BOOST_AUTO_TEST_CASE(RemoveChild_ChildNonExisting_Throws) { + GroupTreeNodePtr fieldNodeDummy = GroupTreeNode::createFieldNode(); + GroupTreeNodePtr fieldNode = GroupTreeNode::createFieldNode(); + GroupTreeNodePtr child = fieldNode->addChildGroup("Child1"); + BOOST_CHECK_THROW(fieldNode->removeChild(fieldNodeDummy), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(RemoveChild_RemoveTwice_Throws) { + GroupTreeNodePtr fieldNodeDummy = GroupTreeNode::createFieldNode(); + GroupTreeNodePtr fieldNode = GroupTreeNode::createFieldNode(); + GroupTreeNodePtr child = fieldNode->addChildGroup("Child1"); + BOOST_CHECK_NO_THROW(fieldNode->removeChild(child));; + BOOST_CHECK_THROW(fieldNode->removeChild(child), std::invalid_argument); + +} + +BOOST_AUTO_TEST_CASE(RemoveChild_ChildExists_ChildRemoved) { + GroupTreeNodePtr fieldNode = GroupTreeNode::createFieldNode(); + GroupTreeNodePtr child = fieldNode->addChildGroup("Child1"); + BOOST_CHECK_NO_THROW(fieldNode->removeChild(child)); + BOOST_CHECK(!fieldNode->hasChildGroup("Child1")); +} diff --git a/opm/parser/eclipse/EclipseState/Schedule/tests/GroupTreeTests.cpp b/opm/parser/eclipse/EclipseState/Schedule/tests/GroupTreeTests.cpp index 02dcbf531..a6c55d788 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/tests/GroupTreeTests.cpp +++ b/opm/parser/eclipse/EclipseState/Schedule/tests/GroupTreeTests.cpp @@ -40,7 +40,20 @@ BOOST_AUTO_TEST_CASE(GetNode_NonExistingNode_ReturnsNull) { BOOST_CHECK_EQUAL(GroupTreeNodePtr(), tree.getNode("Non-existing")); } -BOOST_AUTO_TEST_CASE(AddNode_ParentNotSpecified_AddedUnderField) { +BOOST_AUTO_TEST_CASE(GetNodeAndParent_AllOK) { + GroupTree tree; + tree.updateTree("GRANDPARENT", "FIELD"); + tree.updateTree("PARENT", "GRANDPARENT"); + tree.updateTree("GRANDCHILD", "PARENT"); + + GroupTreeNodePtr grandchild = tree.getNode("GRANDCHILD"); + BOOST_CHECK(grandchild); + GroupTreeNodePtr parent = tree.getParent("GRANDCHILD"); + BOOST_CHECK_EQUAL("PARENT", parent->name()); + BOOST_CHECK(parent->hasChildGroup("GRANDCHILD")); +} + +BOOST_AUTO_TEST_CASE(UpdateTree_ParentNotSpecified_AddedUnderField) { GroupTree tree; tree.updateTree("CHILD_OF_FIELD"); BOOST_CHECK(tree.getNode("CHILD_OF_FIELD")); @@ -48,7 +61,7 @@ BOOST_AUTO_TEST_CASE(AddNode_ParentNotSpecified_AddedUnderField) { BOOST_CHECK(rootNode->hasChildGroup("CHILD_OF_FIELD")); } -BOOST_AUTO_TEST_CASE(AddNode_ParentIsField_AddedUnderField) { +BOOST_AUTO_TEST_CASE(UpdateTree_ParentIsField_AddedUnderField) { GroupTree tree; tree.updateTree("CHILD_OF_FIELD", "FIELD"); BOOST_CHECK(tree.getNode("CHILD_OF_FIELD")); @@ -56,7 +69,7 @@ BOOST_AUTO_TEST_CASE(AddNode_ParentIsField_AddedUnderField) { BOOST_CHECK(rootNode->hasChildGroup("CHILD_OF_FIELD")); } -BOOST_AUTO_TEST_CASE(AddNode_ParentNotAdded_ChildAndParentAdded) { +BOOST_AUTO_TEST_CASE(UpdateTree_ParentNotAdded_ChildAndParentAdded) { GroupTree tree; tree.updateTree("CHILD", "NEWPARENT"); BOOST_CHECK(tree.getNode("CHILD")); @@ -66,6 +79,37 @@ BOOST_AUTO_TEST_CASE(AddNode_ParentNotAdded_ChildAndParentAdded) { BOOST_CHECK(newParent->hasChildGroup("CHILD")); } +BOOST_AUTO_TEST_CASE(UpdateTree_AddFieldNode_Throws) { + GroupTree tree; + BOOST_CHECK_THROW(tree.updateTree("FIELD", "NEWPARENT"), std::domain_error); + BOOST_CHECK_THROW(tree.updateTree("FIELD"), std::domain_error); +} + +BOOST_AUTO_TEST_CASE(UpdateTree_ChildExists_ChildMoved) { + GroupTree tree; + tree.updateTree("OLDPARENT", "FIELD"); + tree.updateTree("NEWPARENT", "FIELD"); + tree.updateTree("THECHILD", "OLDPARENT"); + tree.updateTree("GRANDCHILD1", "THECHILD"); + tree.updateTree("GRANDCHILD2", "THECHILD"); + + GroupTreeNodePtr oldParent = tree.getNode("OLDPARENT"); + BOOST_CHECK(oldParent->hasChildGroup("THECHILD")); + GroupTreeNodePtr theChild = oldParent->getChildGroup("THECHILD"); + BOOST_CHECK(theChild->hasChildGroup("GRANDCHILD1")); + + GroupTreeNodePtr newParent = tree.getNode("NEWPARENT"); + BOOST_CHECK(!newParent->hasChildGroup("THECHILD")); + + tree.updateTree("THECHILD", "NEWPARENT"); + + BOOST_CHECK(!oldParent->hasChildGroup("THECHILD")); + + BOOST_CHECK(newParent->hasChildGroup("THECHILD")); + theChild = newParent->getChildGroup("THECHILD"); + BOOST_CHECK(theChild->hasChildGroup("GRANDCHILD1")); +} + BOOST_AUTO_TEST_CASE(DeepCopy_TreeWithChildren_ObjectsDifferContentMatch) { GroupTreePtr tree(new GroupTree()); tree->updateTree("L1CHILD1", "FIELD"); @@ -73,33 +117,33 @@ BOOST_AUTO_TEST_CASE(DeepCopy_TreeWithChildren_ObjectsDifferContentMatch) { tree->updateTree("L2CHILD1", "L1CHILD1"); tree->updateTree("L2CHILD2", "L1CHILD1"); tree->updateTree("L3CHILD1", "L2CHILD1"); - + GroupTreePtr copiedTree = tree->deepCopy(); GroupTreeNodePtr fieldNodeCopy = copiedTree->getNode("FIELD"); GroupTreeNodePtr fieldNodeOriginal = tree->getNode("FIELD"); BOOST_CHECK(!(fieldNodeCopy == fieldNodeOriginal)); BOOST_CHECK_EQUAL(fieldNodeCopy->name(), fieldNodeOriginal->name()); - + GroupTreeNodePtr L1CHILD1NodeCopy = fieldNodeCopy->getChildGroup("L1CHILD1"); GroupTreeNodePtr L1CHILD1NodeOriginal = fieldNodeOriginal->getChildGroup("L1CHILD1"); BOOST_CHECK(!(L1CHILD1NodeCopy == L1CHILD1NodeOriginal)); BOOST_CHECK_EQUAL(L1CHILD1NodeCopy->name(), L1CHILD1NodeOriginal->name()); - + GroupTreeNodePtr L1CHILD2NodeCopy = fieldNodeCopy->getChildGroup("L1CHILD2"); GroupTreeNodePtr L1CHILD2NodeOriginal = fieldNodeOriginal->getChildGroup("L1CHILD2"); BOOST_CHECK(!(L1CHILD2NodeCopy == L1CHILD2NodeOriginal)); BOOST_CHECK_EQUAL(L1CHILD2NodeCopy->name(), L1CHILD2NodeOriginal->name()); - + GroupTreeNodePtr L2CHILD1NodeCopy = L1CHILD1NodeCopy->getChildGroup("L2CHILD1"); GroupTreeNodePtr L2CHILD1NodeOriginal = L1CHILD1NodeOriginal->getChildGroup("L2CHILD1"); BOOST_CHECK(!(L2CHILD1NodeCopy == L2CHILD1NodeOriginal)); BOOST_CHECK_EQUAL(L2CHILD1NodeCopy->name(), L2CHILD1NodeOriginal->name()); - + GroupTreeNodePtr L2CHILD2NodeCopy = L1CHILD1NodeCopy->getChildGroup("L2CHILD2"); GroupTreeNodePtr L2CHILD2NodeOriginal = L1CHILD1NodeOriginal->getChildGroup("L2CHILD2"); BOOST_CHECK(!(L2CHILD2NodeCopy == L2CHILD2NodeOriginal)); BOOST_CHECK_EQUAL(L2CHILD2NodeCopy->name(), L2CHILD2NodeOriginal->name()); - + GroupTreeNodePtr L3CHILD1NodeCopy = L2CHILD1NodeCopy->getChildGroup("L3CHILD1"); GroupTreeNodePtr L3CHILD1NodeOriginal = L2CHILD1NodeOriginal->getChildGroup("L3CHILD1"); BOOST_CHECK(!(L3CHILD1NodeCopy == L3CHILD1NodeOriginal)); diff --git a/opm/parser/eclipse/IntegrationTests/ScheduleCreateFromDeck.cpp b/opm/parser/eclipse/IntegrationTests/ScheduleCreateFromDeck.cpp index 009b31244..7ac5fd965 100644 --- a/opm/parser/eclipse/IntegrationTests/ScheduleCreateFromDeck.cpp +++ b/opm/parser/eclipse/IntegrationTests/ScheduleCreateFromDeck.cpp @@ -189,6 +189,40 @@ BOOST_AUTO_TEST_CASE(GroupTreeTest_WELSPECS_AND_GRUPTREE_correct_tree) { BOOST_CHECK_EQUAL("GROUP_NILS", GROUP_NILS->name()); }; +BOOST_AUTO_TEST_CASE(GroupTreeTest_GRUPTREE_WITH_REPARENT_correct_tree) { + ParserPtr parser(new Parser()); + boost::filesystem::path scheduleFile("testdata/integration_tests/SCHEDULE/SCHEDULE_GROUPS_REPARENT"); + DeckPtr deck = parser->parse(scheduleFile.string()); + ScheduleConstPtr schedule(new Schedule(deck)); + + schedule->getGroupTree(0)->printTree(); + std::cout << std::endl << std::endl; + schedule->getGroupTree(1)->printTree(); + + // Time , from first GRUPTREE + GroupTreeNodePtr root0 = schedule->getGroupTree(0)->getNode("FIELD"); + BOOST_REQUIRE_EQUAL("FIELD", root0->name()); + BOOST_CHECK(root0->hasChildGroup("GROUP_BJARNE")); + GroupTreeNodePtr GROUP_BJARNE0 = root0->getChildGroup("GROUP_BJARNE"); + BOOST_CHECK_EQUAL("GROUP_BJARNE", GROUP_BJARNE0->name()); + + BOOST_CHECK(root0->hasChildGroup("GROUP_NEW")); + GroupTreeNodePtr GROUP_NEW0 = root0->getChildGroup("GROUP_NEW"); + BOOST_CHECK_EQUAL("GROUP_NEW", GROUP_NEW0->name()); + + + BOOST_CHECK(GROUP_BJARNE0->hasChildGroup("GROUP_BIRGER")); + GroupTreeNodePtr GROUP_BIRGER0 = GROUP_BJARNE0->getChildGroup("GROUP_BIRGER"); + BOOST_CHECK_EQUAL("GROUP_BIRGER", GROUP_BIRGER0->name()); + + BOOST_CHECK(GROUP_NEW0->hasChildGroup("GROUP_NILS")); + GroupTreeNodePtr GROUP_NILS0 = GROUP_NEW0->getChildGroup("GROUP_NILS"); + BOOST_CHECK_EQUAL("GROUP_NILS", GROUP_NILS0->name()); + + // SÅ den nye strukturen med et barneflytt +}; + + BOOST_AUTO_TEST_CASE(GroupTreeTest_PrintGrouptree) { ParserPtr parser(new Parser()); boost::filesystem::path scheduleFile("testdata/integration_tests/SCHEDULE/SCHEDULE_WELSPECS_GROUPS"); diff --git a/testdata/integration_tests/SCHEDULE/SCHEDULE_GROUPS_REPARENT b/testdata/integration_tests/SCHEDULE/SCHEDULE_GROUPS_REPARENT new file mode 100644 index 000000000..013bfaa0b --- /dev/null +++ b/testdata/integration_tests/SCHEDULE/SCHEDULE_GROUPS_REPARENT @@ -0,0 +1,20 @@ +START -- Time 0 +10 MAI 2007 / + +SCHEDULE + +GRUPTREE + 'GROUP_BIRGER' 'GROUP_BJARNE' / -- BJARNE under FIELD, BIRGER under BJARNE + 'GROUP_NILS' 'GROUP_NEW' / -- NILS under NEW, NEW should be under FIELD +/ + +TSTEP -- Time 1 + 10 / + +GRUPTREE + 'GROUP_BIRGER' 'GROUP_NEW' / -- Move BIRGER to NEW, i.e. NEW should now have NILS AND BIRGER, and BJARNE is childless +/ + + + +