diff --git a/src/fesa/io/abaqus/domain_mapper.cpp b/src/fesa/io/abaqus/domain_mapper.cpp index c7b0c63..c6aa07d 100644 --- a/src/fesa/io/abaqus/domain_mapper.cpp +++ b/src/fesa/io/abaqus/domain_mapper.cpp @@ -398,20 +398,23 @@ private: }); } - bool containsSetName(const RawPart& part, const std::string& name) const { + bool containsSetName( + const std::vector& sets, + const std::string& name) const { const auto matches = [&name](const RawSet& set) { return equalName(set.name, name); }; - return std::any_of(part.nodeSets.begin(), part.nodeSets.end(), matches) || - std::any_of(part.elementSets.begin(), part.elementSets.end(), matches); + return std::any_of(sets.begin(), sets.end(), matches); } - bool containsAssemblySetName(const std::string& name) const { + bool containsAssemblySetName( + bool nodeSet, + const std::string& name) const { return std::any_of( assemblySets_.begin(), assemblySets_.end(), - [&name](const RawAssemblySet& set) { - return equalName(set.name, name); + [nodeSet, &name](const RawAssemblySet& set) { + return set.isNodeSet == nodeSet && equalName(set.name, name); }); } @@ -1025,10 +1028,12 @@ private: "GENERATE is a valueless flag."); return; } - if (containsSetName(part, *name)) { + const auto& sets = nodeSet ? part.nodeSets : part.elementSets; + if (containsSetName(sets, *name)) { inputFailure( "duplicate-entity", block.location, block.canonicalName, - *name, "Set names are unique within a part."); + *name, + "Set names are unique within their node-set or element-set namespace."); return; } RawSet set{*name, {}, block.location}; @@ -1295,10 +1300,11 @@ private: "GENERATE is a valueless flag."); return; } - if (containsAssemblySetName(*name)) { + if (containsAssemblySetName(nodeSet, *name)) { inputFailure( "duplicate-entity", block.location, block.canonicalName, - *name, "Assembly set names are unique."); + *name, + "Assembly set names are unique within their node-set or element-set namespace."); return; } RawAssemblySet set{nodeSet, *name, *instance, {}, block.location}; @@ -2275,6 +2281,14 @@ private: return; } if (rawSet.isNodeSet) { + definition_.nodeSets.erase( + std::remove_if( + definition_.nodeSets.begin(), + definition_.nodeSets.end(), + [&rawSet](const NodeSet& set) { + return equalName(set.name, rawSet.name); + }), + definition_.nodeSets.end()); NodeSet set{ rawSet.name, definitionInstance->name, {}, rawSet.location}; for (const auto member : rawSet.members) { @@ -2295,6 +2309,14 @@ private: } definition_.nodeSets.push_back(std::move(set)); } else { + definition_.elementSets.erase( + std::remove_if( + definition_.elementSets.begin(), + definition_.elementSets.end(), + [&rawSet](const ElementSet& set) { + return equalName(set.name, rawSet.name); + }), + definition_.elementSets.end()); ElementSet set{ rawSet.name, definitionInstance->name, {}, rawSet.location}; for (const auto member : rawSet.members) { diff --git a/tests/unit/io/abaqus/domain_mapper_test.cpp b/tests/unit/io/abaqus/domain_mapper_test.cpp index e1d90cd..e8e54f7 100644 --- a/tests/unit/io/abaqus/domain_mapper_test.cpp +++ b/tests/unit/io/abaqus/domain_mapper_test.cpp @@ -436,6 +436,69 @@ OnlySecond, 2, 5. ASSERT_TRUE(largeFinite.hasValue()); } +TEST(InpDomainMapping, KeepsNodeAndElementSetNamesInSeparateNamespaces) { + auto sharedName = mapText( + "separate-part-set-namespaces", + replaceOnce( + shellDeck(), + "*Elset, elset=ShellS4\n10", + "*Nset, nset=ShellS4\n1, 2, 3, 4\n*Elset, elset=ShellS4\n10")); + + ASSERT_TRUE(sharedName.hasValue()); + const auto& domain = sharedName.value(); + EXPECT_TRUE(std::any_of( + domain.nodeSets().begin(), domain.nodeSets().end(), + [](const fesa::NodeSet& set) { return set.name == "ShellS4"; })); + EXPECT_TRUE(std::any_of( + domain.elementSets().begin(), domain.elementSets().end(), + [](const fesa::ElementSet& set) { return set.name == "ShellS4"; })); + + auto duplicateNodeSet = mapText( + "duplicate-part-node-set", + replaceOnce( + shellDeck(), + "*Elset, elset=ShellS4\n10", + "*Nset, nset=Shared\n1\n*Nset, nset=Shared\n2\n" + "*Elset, elset=ShellS4\n10")); + ASSERT_FALSE(duplicateNodeSet.hasValue()); + EXPECT_NE(findDiagnostic(duplicateNodeSet.status(), "duplicate-entity"), nullptr); + + auto duplicateElementSet = mapText( + "duplicate-part-element-set", + replaceOnce( + shellDeck(), + "*Elset, elset=ShellS4\n10", + "*Elset, elset=Repeated\n10\n*Elset, elset=Repeated\n20\n" + "*Elset, elset=ShellS4\n10")); + ASSERT_FALSE(duplicateElementSet.hasValue()); + EXPECT_NE(findDiagnostic(duplicateElementSet.status(), "duplicate-entity"), nullptr); + + auto assemblySharedName = mapText( + "separate-assembly-set-namespaces", + replaceOnce( + replaceOnce( + minimalDeck(), + "*Elset, elset=BeamSet\n1", + "*Nset, nset=Root\n1, 2\n*Elset, elset=BeamSet\n1"), + "*Nset, nset=Root, instance=Beam-1\n1", + "*Nset, nset=Root, instance=Beam-1\n1\n" + "*Elset, elset=Root, instance=Beam-1\n1")); + ASSERT_TRUE(assemblySharedName.hasValue()); + const auto& assemblyDomain = assemblySharedName.value(); + const auto rootNodeSetCount = std::count_if( + assemblyDomain.nodeSets().begin(), assemblyDomain.nodeSets().end(), + [](const fesa::NodeSet& set) { return set.name == "Root"; }); + EXPECT_EQ(rootNodeSetCount, 1); + const auto rootNodeSet = std::find_if( + assemblyDomain.nodeSets().begin(), assemblyDomain.nodeSets().end(), + [](const fesa::NodeSet& set) { return set.name == "Root"; }); + ASSERT_NE(rootNodeSet, assemblyDomain.nodeSets().end()); + EXPECT_EQ(rootNodeSet->nodeIndices, (std::vector{0U})); + EXPECT_EQ(std::count_if( + assemblyDomain.elementSets().begin(), assemblyDomain.elementSets().end(), + [](const fesa::ElementSet& set) { return set.name == "Root"; }), 1); +} + TEST(InpDomainMapping, NoOpAllowlistWarnsWithoutSemanticEffect) { auto plain = mapText("without-no-ops", supportedInventoryDeck(false)); auto withNoOps = mapText("with-no-ops", supportedInventoryDeck(true));