From 55717a78d915183f4bef26c5b7a00aafd34754c5 Mon Sep 17 00:00:00 2001 From: Guillaume Giudicelli Date: Thu, 17 Oct 2024 08:47:18 -0600 Subject: [PATCH 1/6] Clean up ParsedGenerateSideset --- .../meshgenerators/ParsedGenerateSideset.md | 8 ++++++++ .../meshgenerators/ParsedGenerateSideset.h | 7 ++++--- .../src/meshgenerators/ParsedGenerateSideset.C | 16 ++++------------ framework/src/utils/FunctionParserUtils.C | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/framework/doc/content/source/meshgenerators/ParsedGenerateSideset.md b/framework/doc/content/source/meshgenerators/ParsedGenerateSideset.md index 3faa6d766eff..9f9ffc0d2cf3 100644 --- a/framework/doc/content/source/meshgenerators/ParsedGenerateSideset.md +++ b/framework/doc/content/source/meshgenerators/ParsedGenerateSideset.md @@ -2,6 +2,14 @@ !syntax description /Mesh/ParsedGenerateSideset +Optionally, additional constraints can be imposed when examining a node based on : + +- the side's normal +- the subdomain of the element owning the side considered for the sideset +- the neighbor of this element, on the other side of the side +- whether the side is already part of (or not part of) an existing boundary +- whether the side is 'external', e.g. it lies on the mesh exterior boundary + !syntax parameters /Mesh/ParsedGenerateSideset !syntax inputs /Mesh/ParsedGenerateSideset diff --git a/framework/include/meshgenerators/ParsedGenerateSideset.h b/framework/include/meshgenerators/ParsedGenerateSideset.h index 82b41df83a75..058756b7e86b 100644 --- a/framework/include/meshgenerators/ParsedGenerateSideset.h +++ b/framework/include/meshgenerators/ParsedGenerateSideset.h @@ -14,9 +14,10 @@ #include "libmesh/point.h" /** - * MeshGenerator for defining a Sideset by a parsed expression and - * optionally by looking at the subdomain a side's element belongs to - * and the side's normal vector + * MeshGenerator for defining a sideset by a parsed expression and + * optionally by considering additional constraints on sides being included, for example + * based on their normal, on the subdomains of the element owning the side, or on pre-existing + * sidesets in the mesh */ class ParsedGenerateSideset : public SideSetsGeneratorBase, public FunctionParserUtils { diff --git a/framework/src/meshgenerators/ParsedGenerateSideset.C b/framework/src/meshgenerators/ParsedGenerateSideset.C index 835e2cff4b17..0cb55ae8ece2 100644 --- a/framework/src/meshgenerators/ParsedGenerateSideset.C +++ b/framework/src/meshgenerators/ParsedGenerateSideset.C @@ -39,13 +39,11 @@ ParsedGenerateSideset::validParams() "Vector of values for the constants in constant_names (can be an FParser expression)"); // This sideset generator can only handle a single new sideset name, not a vector of names - // This sideset generator can only handle a single new sideset name params.suppressParameter>("new_boundary"); - params.addClassDescription("A MeshGenerator that adds element sides to a sideset if the " - "centroid satisfies the `combinatorial_geometry` expression. " - "Optionally, element sides are also added if they are included in " - "`included_subdomains` and if they feature the designated normal."); + params.addClassDescription( + "A MeshGenerator that adds element sides to a sideset if the centroid of the side satisfies " + "the `combinatorial_geometry` expression."); return params; } @@ -70,12 +68,7 @@ ParsedGenerateSideset::ParsedGenerateSideset(const InputParameters & parameters) // parse function if (_func_F->Parse(_function, "x,y,z") >= 0) - mooseError("Invalid function\n", - _function, - "\nin ParsedAddSideset ", - name(), - ".\n", - _func_F->ErrorMsg()); + mooseError("Invalid function\n", _function, "\n", _func_F->ErrorMsg()); _func_params.resize(3); } @@ -129,7 +122,6 @@ ParsedGenerateSideset::generate() } finalize(); boundary_info.sideset_name(boundary_ids[0]) = _boundary_names[0]; - boundary_info.nodeset_name(boundary_ids[0]) = _boundary_names[0]; mesh->set_isnt_prepared(); return dynamic_pointer_cast(mesh); diff --git a/framework/src/utils/FunctionParserUtils.C b/framework/src/utils/FunctionParserUtils.C index 7b89a7638e94..5b2a3d1bc421 100644 --- a/framework/src/utils/FunctionParserUtils.C +++ b/framework/src/utils/FunctionParserUtils.C @@ -41,7 +41,7 @@ FunctionParserUtils::validParams() params.addParamNamesToGroup( "enable_jit enable_ad_cache enable_auto_optimize disable_fpoptimizer evalerror_behavior", - "Advanced"); + "Parsed expression advanced"); params.addParam("epsilon", FunctionParser::epsilon(), "Fuzzy comparison tolerance"); return params; } From 40494955a96e51a822639ad0958f9dc9fad43965 Mon Sep 17 00:00:00 2001 From: Guillaume Giudicelli Date: Thu, 17 Oct 2024 08:48:13 -0600 Subject: [PATCH 2/6] Add a base class for nodeset generation with a few of the commonly desirable options - included/excluded boundaries - included subdomains - external only refs #28881 --- .../meshgenerators/NodeSetsGeneratorBase.h | 100 ++++++++ .../meshgenerators/NodeSetsGeneratorBase.C | 234 ++++++++++++++++++ 2 files changed, 334 insertions(+) create mode 100644 framework/include/meshgenerators/NodeSetsGeneratorBase.h create mode 100644 framework/src/meshgenerators/NodeSetsGeneratorBase.C diff --git a/framework/include/meshgenerators/NodeSetsGeneratorBase.h b/framework/include/meshgenerators/NodeSetsGeneratorBase.h new file mode 100644 index 000000000000..487b4b7fa536 --- /dev/null +++ b/framework/include/meshgenerators/NodeSetsGeneratorBase.h @@ -0,0 +1,100 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "MeshGenerator.h" + +/* + * Base class for mesh generators that add nodesets to the mesh + */ +class NodeSetsGeneratorBase : public MeshGenerator +{ +public: + static InputParameters validParams(); + + NodeSetsGeneratorBase(const InputParameters & parameters); + +protected: + /** + * This method prepares a few attributes which are commonly needed for nodeset generation such + * as a map from nodes to elements, and checks the existence and validity of several user + * parameters + */ + void setup(MeshBase & mesh); + + /** + * Determines whether the node is on the exterior of the mesh + */ + bool nodeOnMeshExteriorBoundary(const Node * node, + const std::vector & node_elems, + const MeshBase & mesh) const; + + /** + * Determines whether any neighbor element of the node has a subdomain id is in the given + * subdomain_id_list. + */ + bool nodeElementsInIncludedSubdomains(const std::vector node_elems, + const MeshBase & mesh) const; + + /** + * Determines whether the given node of an element belongs to any nodesets in the + * included_nodesets parameter. + */ + bool nodeInIncludedNodesets(const std::vector & node_nodesets) const; + + /** + * Determines whether the given node of an element belongs to any nodesets in the + * excluded_nodesets parameter. + */ + bool nodeInExcludedNodesets(const std::vector & node_nodesets) const; + + /** + * Determines whether the given element's node satisfies the user-specified constraints + */ + bool nodeSatisfiesRequirements(const Node * node, + const std::vector & node_nodesets, + const std::vector & node_elems, + const MeshBase & mesh); + + /// the mesh to add the nodesets to + std::unique_ptr & _input; + + /// The list of new nodeset names + std::vector _nodeset_names; + + /// Whether or not to remove the old nodesets (all of them, if any) when adding nodesets + const bool _replace; + + /// whether to check nodeset ids against the included nodeset list when adding nodes or not + const bool _check_included_nodesets; + + /// whether to check nodeset ids against the excluded nodeset list when adding nodes or not + const bool _check_excluded_nodesets; + + /// whether to check subdomain ids of the element that included this node + const bool _check_included_subdomains; + + /// A list of nodeset ids that the node has to be part of, extracted from the included_nodesets parameter + std::vector _included_nodeset_ids; + + /// A list of nodeset ids that the node must not be a part of, extracted from the excluded_nodesets parameter + std::vector _excluded_nodeset_ids; + + /// A list of included subdomain ids that the node has to be part of, extracted from the included_subdomains parameter + std::vector _included_subdomain_ids; + + /// Whether to only include external node when considering nodes to add to the nodeset + const bool _include_only_external_nodes; + + /// A map from nodes (ids) to local elements (ids) which comprise the node + // Build the node to element map, which is usually provided by a MooseMesh but here we have a + // MeshBase. + std::map> _node_to_elem_map; +}; diff --git a/framework/src/meshgenerators/NodeSetsGeneratorBase.C b/framework/src/meshgenerators/NodeSetsGeneratorBase.C new file mode 100644 index 000000000000..3d659c3a0966 --- /dev/null +++ b/framework/src/meshgenerators/NodeSetsGeneratorBase.C @@ -0,0 +1,234 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "NodeSetsGeneratorBase.h" +#include "Parser.h" +#include "InputParameters.h" +#include "MooseMeshUtils.h" + +#include "libmesh/mesh_generation.h" +#include "libmesh/mesh.h" +#include "libmesh/elem.h" + +InputParameters +NodeSetsGeneratorBase::validParams() +{ + InputParameters params = MeshGenerator::validParams(); + params.addRequiredParam("input", "The mesh we want to modify"); + params.addRequiredParam>("new_nodeset", + "The list of nodeset names to create."); + + params.addParam("replace", + false, + "If true, replace the old nodesets. If false, the current nodesets (if " + "any) will be preserved."); + + params.addParam>( + "included_nodesets", + "A set of nodeset names or ids whose nodes will be included in the new nodesets. A node " + "is only added if it also belongs to one of these nodesets."); + params.addParam>( + "excluded_nodesets", + "A set of nodeset names or ids whose nodes will be excluded from the new nodesets. A node " + "is only added if does not belong to any of these nodesets."); + params.addParam>( + "included_subdomains", + "A set of subdomain names or ids whose nodes will be included in the new nodesets. A node " + "is only added if the subdomain id of the corresponding element is in this set."); + + params.addParam( + "include_only_external_nodes", + false, + "Whether to only include external nodes when considering nodes to add to the nodeset"); + + // Nodeset restriction param group + params.addParamNamesToGroup("included_nodesets excluded_nodesets included_subdomains " + "include_only_external_nodes", + "Nodeset restrictions"); + + return params; +} + +NodeSetsGeneratorBase::NodeSetsGeneratorBase(const InputParameters & parameters) + : MeshGenerator(parameters), + _input(getMesh("input")), + _nodeset_names(std::vector()), + _replace(getParam("replace")), + _check_included_nodesets(isParamValid("included_nodesets")), + _check_excluded_nodesets(isParamValid("excluded_nodesets")), + _check_included_subdomains(isParamValid("included_subdomains")), + _included_nodeset_ids(std::vector()), + _excluded_nodeset_ids(std::vector()), + _included_subdomain_ids(std::vector()), + _include_only_external_nodes(getParam("include_only_external_nodes")) +{ + if (isParamValid("new_nodeset")) + _nodeset_names = getParam>("new_nodeset"); +} + +void +NodeSetsGeneratorBase::setup(MeshBase & mesh) +{ + // Parameter checks and filling vector of ids (used instead of names for efficiency) + if (_check_included_nodesets) + { + const auto & included_nodesets = getParam>("included_nodesets"); + for (const auto & nodeset_name : _nodeset_names) + if (std::find(included_nodesets.begin(), included_nodesets.end(), nodeset_name) != + included_nodesets.end()) + paramError( + "new_nodeset", + "A nodeset cannot be both the new nodeset and be included in the list of included " + "nodesets. If you are trying to restrict an existing nodeset, you must use a " + "different name for 'new_nodeset', delete the old nodeset, and then rename the " + "new nodeset to the old nodeset."); + + _included_nodeset_ids = MooseMeshUtils::getBoundaryIDs(mesh, included_nodesets, false); + + // Check that the included nodeset ids/names exist in the mesh + for (const auto i : index_range(_included_nodeset_ids)) + if (_included_nodeset_ids[i] == Moose::INVALID_BOUNDARY_ID) + paramError("included_nodesets", + "The nodeset '", + included_nodesets[i], + "' was not found within the mesh"); + } + + if (_check_excluded_nodesets) + { + const auto & excluded_nodesets = getParam>("excluded_nodesets"); + for (const auto & nodeset_name : _nodeset_names) + if (std::find(excluded_nodesets.begin(), excluded_nodesets.end(), nodeset_name) != + excluded_nodesets.end()) + paramError( + "new_nodeset", + "A nodeset cannot be both the new nodeset and be excluded in the list of excluded " + "nodesets."); + _excluded_nodeset_ids = MooseMeshUtils::getBoundaryIDs(mesh, excluded_nodesets, false); + + // Check that the excluded nodeset ids/names exist in the mesh + for (const auto i : index_range(_excluded_nodeset_ids)) + if (_excluded_nodeset_ids[i] == Moose::INVALID_BOUNDARY_ID) + paramError("excluded_nodesets", + "The nodeset '", + excluded_nodesets[i], + "' was not found within the mesh"); + + if (_check_included_nodesets) + { + // Check that included and excluded nodeset lists do not overlap + for (const auto & nodeset_id : _included_nodeset_ids) + if (std::find(_excluded_nodeset_ids.begin(), _excluded_nodeset_ids.end(), nodeset_id) != + _excluded_nodeset_ids.end()) + paramError("excluded_nodesets", + "'included_nodesets' and 'excluded_nodesets' lists should not overlap"); + } + } + + // Get the nodeset ids from the names + if (_check_included_subdomains) + { + // check that the subdomains exist in the mesh + const auto subdomains = getParam>("included_subdomains"); + for (const auto & name : subdomains) + if (!MooseMeshUtils::hasSubdomainName(mesh, name)) + paramError("included_subdomains", "The block '", name, "' was not found in the mesh"); + + _included_subdomain_ids = MooseMeshUtils::getSubdomainIDs(mesh, subdomains); + } + + // Build the node to element map, which is usually provided by a MooseMesh but in the mesh + // generation process we are working with a MeshBase + for (const auto & elem : mesh.active_element_ptr_range()) + for (unsigned int n = 0; n < elem->n_nodes(); n++) + _node_to_elem_map[elem->node_id(n)].push_back(elem->id()); +} + +bool +NodeSetsGeneratorBase::nodeOnMeshExteriorBoundary(const Node * node, + const std::vector & node_elems, + const MeshBase & mesh) const +{ + // Loop on the elements and check whether the node is part of a side with no neighbor (exterior) + for (const auto elem_id : node_elems) + { + const auto elem = mesh.elem_ptr(elem_id); + for (const auto side_i : make_range(elem->n_sides())) + { + // Node is part of the side + if (elem->side_ptr(side_i)->get_node_index(node) != libMesh::invalid_uint) + { + // No neighbor on that side + if (!elem->neighbor_ptr(side_i)) + return true; + } + } + } + return false; +} + +bool +NodeSetsGeneratorBase::nodeElementsInIncludedSubdomains(const std::vector node_elems, + const MeshBase & mesh) const +{ + for (const auto elem_id : node_elems) + { + subdomain_id_type curr_subdomain = mesh.elem_ptr(elem_id)->subdomain_id(); + if (std ::find(_included_subdomain_ids.begin(), + _included_subdomain_ids.end(), + curr_subdomain) != _included_subdomain_ids.end()) + return true; + } + return false; +} + +bool +NodeSetsGeneratorBase::nodeInIncludedNodesets(const std::vector & node_nodesets) const +{ + for (const auto bid : node_nodesets) + if (std::find(_included_nodeset_ids.begin(), _included_nodeset_ids.end(), bid) != + _included_nodeset_ids.end()) + return true; + return false; +} + +bool +NodeSetsGeneratorBase::nodeInExcludedNodesets(const std::vector & node_nodesets) const +{ + for (const auto bid : node_nodesets) + if (std::find(_excluded_nodeset_ids.begin(), _excluded_nodeset_ids.end(), bid) != + _excluded_nodeset_ids.end()) + return true; + return false; +} + +bool +NodeSetsGeneratorBase::nodeSatisfiesRequirements(const Node * node, + const std::vector & node_nodesets, + const std::vector & node_elems, + const MeshBase & mesh) +{ + // Skip if side has neighbor and we only want external nodes + if (_include_only_external_nodes && !nodeOnMeshExteriorBoundary(node, node_elems, mesh)) + return false; + + // Skip if none of the elements owning the node are in the list of accepted subdomains + if (_check_included_subdomains && !nodeElementsInIncludedSubdomains(node_elems, mesh)) + return false; + + // Skip if side is not part of included nodesets + if (_check_included_nodesets && !nodeInIncludedNodesets(node_nodesets)) + return false; + + // Skip if side is part of excluded nodesets + if (_check_excluded_nodesets && nodeInExcludedNodesets(node_nodesets)) + return false; + + return true; +} From 4f17477ab9b92ac61d5f216c7d4bc1cb63552332 Mon Sep 17 00:00:00 2001 From: Guillaume Giudicelli Date: Thu, 17 Oct 2024 08:48:37 -0600 Subject: [PATCH 3/6] Add a nodeset generator based on a parsed expression refs #28881 --- .../meshgenerators/ParsedGenerateNodeset.md | 16 ++ .../meshgenerators/ParsedGenerateNodeset.h | 36 +++++ .../meshgenerators/ParsedGenerateNodeset.C | 142 ++++++++++++++++++ 3 files changed, 194 insertions(+) create mode 100644 framework/doc/content/source/meshgenerators/ParsedGenerateNodeset.md create mode 100644 framework/include/meshgenerators/ParsedGenerateNodeset.h create mode 100644 framework/src/meshgenerators/ParsedGenerateNodeset.C diff --git a/framework/doc/content/source/meshgenerators/ParsedGenerateNodeset.md b/framework/doc/content/source/meshgenerators/ParsedGenerateNodeset.md new file mode 100644 index 000000000000..7f875a485efe --- /dev/null +++ b/framework/doc/content/source/meshgenerators/ParsedGenerateNodeset.md @@ -0,0 +1,16 @@ +# ParsedGenerateNodeset + +!syntax description /Mesh/ParsedGenerateNodeset + +Optionally, additional constraints can be imposed when examining a node based on : + +- the subdomain of the element owning the node connodered for the nodeset +- whether the node is already part of (or not part of) an existing boundary +- whether the node is 'external', e.g. it lies on the mesh exterior boundary + +!syntax parameters /Mesh/ParsedGenerateNodeset + +!syntax inputs /Mesh/ParsedGenerateNodeset + +!syntax children /Mesh/ParsedGenerateNodeset + diff --git a/framework/include/meshgenerators/ParsedGenerateNodeset.h b/framework/include/meshgenerators/ParsedGenerateNodeset.h new file mode 100644 index 000000000000..0c7678df6325 --- /dev/null +++ b/framework/include/meshgenerators/ParsedGenerateNodeset.h @@ -0,0 +1,36 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#pragma once + +#include "FunctionParserUtils.h" +#include "NodeSetsGeneratorBase.h" +#include "libmesh/point.h" + +/** + * MeshGenerator for defining a nodeset by a parsed expression + */ +class ParsedGenerateNodeset : public NodeSetsGeneratorBase, public FunctionParserUtils +{ +public: + static InputParameters validParams(); + + ParsedGenerateNodeset(const InputParameters & parameters); + + std::unique_ptr generate() override; + +protected: + /// function expression + std::string _function; + + /// function parser object describing the combinatorial geometry + SymFunctionPtr _func_F; + + usingFunctionParserUtilsMembers(false); +}; diff --git a/framework/src/meshgenerators/ParsedGenerateNodeset.C b/framework/src/meshgenerators/ParsedGenerateNodeset.C new file mode 100644 index 000000000000..e92469db9fe1 --- /dev/null +++ b/framework/src/meshgenerators/ParsedGenerateNodeset.C @@ -0,0 +1,142 @@ +//* This file is part of the MOOSE framework +//* https://www.mooseframework.org +//* +//* All rights reserved, see COPYRIGHT for full restrictions +//* https://github.com/idaholab/moose/blob/master/COPYRIGHT +//* +//* Licensed under LGPL 2.1, please see LICENSE for details +//* https://www.gnu.org/licenses/lgpl-2.1.html + +#include "ParsedGenerateNodeset.h" +#include "Conversion.h" +#include "MooseMeshUtils.h" +#include "CastUniquePointer.h" + +#include "libmesh/fparser_ad.hh" +#include "libmesh/distributed_mesh.h" +#include "libmesh/elem.h" +#include "libmesh/fe_base.h" + +#include + +registerMooseObject("MooseApp", ParsedGenerateNodeset); + +InputParameters +ParsedGenerateNodeset::validParams() +{ + InputParameters params = NodeSetsGeneratorBase::validParams(); + params += FunctionParserUtils::validParams(); + + params.addRequiredParam("new_nodeset_name", "The name of the new nodeset"); + + params.addRequiredParam("expression", + "Function expression describing the geometric constraints " + "that the node must meet to be included in the nodeset"); + params.addParam>( + "constant_names", {}, "Vector of constants used in the parsed function"); + params.addParam>( + "constant_expressions", + {}, + "Vector of values for the constants in constant_names (can be an FParser expression)"); + + // This nodeset generator can only handle a single new nodeset name, not a vector of names + params.suppressParameter>("new_nodeset"); + + params.addClassDescription("A MeshGenerator that adds nodes to a nodeset if the " + "node satisfies the `expression` expression."); + params.addParamNamesToGroup("expression constant_names constant_expressions", + "Parsed expression"); + return params; +} + +ParsedGenerateNodeset::ParsedGenerateNodeset(const InputParameters & parameters) + : NodeSetsGeneratorBase(parameters), + FunctionParserUtils(parameters), + _function(parameters.get("expression")) +{ + _nodeset_names.push_back(getParam("new_nodeset_name")); + + // base function object + _func_F = std::make_shared(); + + // set FParser internal feature flags + setParserFeatureFlags(_func_F); + + // add the constant expressions + addFParserConstants(_func_F, + getParam>("constant_names"), + getParam>("constant_expressions")); + + // parse function + if (_func_F->Parse(_function, "x,y,z") >= 0) + mooseError("Invalid function\n", + _function, + "\nin ParsedGenerateNodeset ", + name(), + ".\n", + _func_F->ErrorMsg()); + + _func_params.resize(3); +} + +std::unique_ptr +ParsedGenerateNodeset::generate() +{ + std::unique_ptr mesh = std::move(_input); + setup(*mesh); + + if (!mesh->is_replicated()) + mooseError("Not implemented for distributed meshes"); + + // Get a reference to our BoundaryInfo object for later use + BoundaryInfo & boundary_info = mesh->get_boundary_info(); + + // Get a reference to the node to nodeset map + const auto & nodeset_map = boundary_info.get_nodeset_map(); + + // Get the BoundaryIDs from the mesh + std::vector nodeset_ids = + MooseMeshUtils::getBoundaryIDs(*mesh, _nodeset_names, true); + mooseAssert(nodeset_ids.size() == 1, "Length of nodeset_ids should be one"); + + // Loop over nodes + for (const auto node_id : make_range(mesh->n_nodes())) + { + // Get a pointer to the node + const auto curr_node = mesh->query_node_ptr(node_id); + + // Get all nodesets the node is currently a part of + const auto & node_nodesets_iters = nodeset_map.equal_range(curr_node); + + // Copy into a vector to accommodate this developer's low skills + std::vector node_nodesets; + for (auto i = node_nodesets_iters.first; i != node_nodesets_iters.second; ++i) + node_nodesets.push_back(i->second); + + // Get all the elements the node is a part of + const auto & node_elems = _node_to_elem_map[curr_node->id()]; + + // Check all the constraints specified in base class + if (!nodeSatisfiesRequirements(curr_node, node_nodesets, node_elems, *mesh)) + continue; + + // Check expression + _func_params[0] = (*curr_node)(0); + _func_params[1] = (*curr_node)(1); + _func_params[2] = (*curr_node)(2); + if (evaluate(_func_F)) + { + if (_replace) + { + for (auto i = node_nodesets_iters.first; i != node_nodesets_iters.second; ++i) + boundary_info.remove_node(curr_node, i->second); + } + boundary_info.add_node(curr_node, nodeset_ids[0]); + } + } + boundary_info.nodeset_name(nodeset_ids[0]) = _nodeset_names[0]; + + // TODO: consider if a new nodeset actually impacts preparedness + mesh->set_isnt_prepared(); + return dynamic_pointer_cast(mesh); +} From e3102e743bd9602e5ce0a1218f4bdfbc4cfa7e6b Mon Sep 17 00:00:00 2001 From: Guillaume Giudicelli Date: Fri, 18 Oct 2024 21:01:27 +0200 Subject: [PATCH 4/6] Add tests for parsed nodeset generator: - exceptions wrong parameter - exception missing bdy / subdomain (#22117) - regular test for each feature --- ...sed_generate_nodeset_exterior_limited_in.e | Bin 0 -> 4212 bytes ...sed_generate_nodeset_nodeset_excluded_in.e | Bin 0 -> 11412 bytes ...rsed_generate_nodeset_nodeset_limited_in.e | Bin 0 -> 12360 bytes ...ed_generate_nodeset_subdomain_limited_in.e | Bin 0 -> 10104 bytes ...parsed_generate_nodeset_exterior_limited.i | 28 +++++ ...parsed_generate_nodeset_nodeset_excluded.i | 40 +++++++ .../parsed_generate_nodeset_nodeset_limited.i | 39 +++++++ ...arsed_generate_nodeset_subdomain_limited.i | 31 ++++++ .../parsed_generate_nodeset/tests | 101 ++++++++++++++++++ 9 files changed, 239 insertions(+) create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/gold/parsed_generate_nodeset_exterior_limited_in.e create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/gold/parsed_generate_nodeset_nodeset_excluded_in.e create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/gold/parsed_generate_nodeset_nodeset_limited_in.e create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/gold/parsed_generate_nodeset_subdomain_limited_in.e create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_exterior_limited.i create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_nodeset_excluded.i create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_nodeset_limited.i create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_subdomain_limited.i create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/tests diff --git a/test/tests/meshgenerators/parsed_generate_nodeset/gold/parsed_generate_nodeset_exterior_limited_in.e b/test/tests/meshgenerators/parsed_generate_nodeset/gold/parsed_generate_nodeset_exterior_limited_in.e new file mode 100644 index 0000000000000000000000000000000000000000..d34c479083989e62f97a0030b730ab85e38cc7f6 GIT binary patch literal 4212 zcmeHKOHUL*5S|s5on00d#RtAuCLnFvNjlJljW0p@^yx?w)P;1ctu~|gC5XvqWSuIssn*gzTVcb5 z@W&;dIeHadWjaUhGT_5ME&ik^eT(oB-(oDtLiIuCMVKZqy(XmbqVeMkbgRa{upOm= z36mX_rD0;!ewq(d5gvgPZ<6aF+_$|QM&QN`oWVz1Z=Mtdn^^KDgLP6cn$Pj!1E1w-M)Czq{yCqt z&r;dL#OpP9>{?mB3cH;Y|Ln(_WDM`e3_kF~`w=_tejC6}ZKXKTgEBp9|yEo4|Xa##vYBrwmt(v&PWZX4h`Y_>M;%`s*^p|it$UA`9-zo2ozSBT3Y&-N<>V}^KtD@_u;W%w*{ zUw()AY|7qkzEhMr%&KRcnC8Z-ch8_XkgxHvoO!c+HoGPM@BO)_49*`}qxT)!xAm4U z64u(bvGSAHPuA}JgqA~~mbtg`+ag3;>*Q1Xq9w9geFN*Xi+62zof~&;7cX@PPPF)4 zd|kZGFL^|-{IWCA;ukG`(XQXMS1ZTZdIaBYzp|fbsY|r$udSnIUs+$Lh1WXmu5)qY z#%0}U@h)FyZM*fHH(P$^&s*OY{a!F|!9d9X?-;!A@Pfs=2=9!%>&YF7cNPAJYpwMuQQnLW@ib@G>yeyNu+_QSe~VT^sT2V&S8{n8J6q+j}CjBD8+F^q97dnLx@ z&+Xr>m)r;^= zgZSWs&wd6Tc=XXnKY$PZe=~DJ(`1-HS*2CGU3Jpa=luKJ`gC_Hov&`(d?hGaOWm8I zMlVXjq}z{zU=NaJ7WboYltlwZMLU>m^~1He&uFix$v8>ZqER95sB6HBdJ&*gqE;~u zS9;%T6a?5kWb?vNl$CQE#vjFNvb)VcApYS}N1UMMk~l$dLNrtA2?xw8+tmzPwi z-E50eGTr(N_GfX{!=M^anyN6}ii5hc;En?*(KM%i{B-CON#tqBn)i{-p2%{wP* z<@@38W?Cx5zkH*pr%|WGqqgu+Kbq0X6Q?u=OWv&EXNhk;=3Dr|Fda~Th9&=e?<@9Y z9>d;mZirLFY4iWkxS5Qev4>CAu-7gItv}T_gm>+Mt+Q9opTcf)^sGH<#Txe5qiR!g z`q2>HwFkD&p3UzFdtfzH1>MtEkrU1zYx3QWv#C2`7TEi_nEX{>4?V#?sKd^HWsO)0 z>I{Rno)$+dyczd;-*$UjMe%^aK26`|FA z6uMgEd0SiIv^l;@eU|Ri=$qz#2s!BbU9J*;Jya)_qS-u_)ig<>)r@_B-MrS&Q_gL2 zw}jdKLAgJ{?7#K(ovZ3;(r5P1y81Xw!E)cRr(Zx{@SX5#b9p?u{ioxh)~)f~D+Y7F zsc+=?QGUP^D0Z!Zoh=6E=^M@+^gQe>u%%w&0((eg&DD!9rne6JGuTou7Y%w3i>$eN ze-+d8)?pumE%kC)p?5}P&DHz2n5MS|JKqLd>gB>iFZZQ2NALU%F->nBb`xx=mrE19 zM?}_Ky+4X+dh4*ifGzgJc0IgiO4XycQ;g>ysW+^x+tEUn|8%eyjyYIc3wYLC>}@ek z?~=ZW?R5jHcd-vOHmv3Bcm?*6gS9-ou`_nzn1kgP5PUe{VcW%c;kJ77;i|sDo-Abf zPyB5cnZh z$9|`xH@#-bA3vkl)8pg)aov31?u*W^#Fu{7$^S3*>-?yb`*H4e+$j~mbnn$eRh?Dw zEiUWLZ|i-&Kkk%_%D%=w(`UWewch9Z<4(z_>|fBn>9^kesOk-8y^k}#^)D;8dA=SS zTW>h)eZD{Ll#KtZuUVg}y8XBKmXAq4o*7u_t`>jg8qe^9l{CxJ{Lh2qnSf!uvB@u? zu^2W$}Aa8fPv+*XzTh}oW zZ&SQE@s`9J5pO^IzY_mj^p@yt(L17dMQzb((R-pZqFK>d(K*rkqB+rd(Y)w_XhC#Q zv?%&O^r47%XWrX*M_Ur{?!|i+?^L`$T@!sG`c(9p=yTB*qU)lLs4jkTV>#fxiQL$G zH1AEwEGL#H%MEYG%z;l{$Q5(olOuA5jC_(WFv!R&xdTIPnP+(<$IP>QB4ZwT1%r%v z#I{dkeF?h7I? ze!SEI^Q;d1c#$!W`T*m{iwxb=4j4aPzn=VfskJMjWzl7kA1^YiJurT}%z;lmQk#Cf z$f#Rt6^tJ*wah%LV?SPG%%i@+`0*k`cSi(<_fu+=I-=I70oIJXl6!y59wjF1;+sEa z4-zAO;H$g8{90>DPW?}bsDrw5g*v8oPm1hJ!GHGOagl2a3^Ly)<2rKnxIS8r$PJh} zBCpsYhs21V>}}?=FNuZorH&2=!kl^S$jvi0E!X79{Guk&O`NvwoMW74Hs98m`IcwSq|+kXznn>zM7Dp~qh`m> zFUuvm+al)7iR`>!j_u8kzRe$Uu+!akQT#;_=M3kK?OFC+M}+@YqpU5ll1tVFefU2s zVxOT0|Jh&cEAB9hhy4bhvu9akeqPfzSljcyed-1KR$K16;>Q^g_Rov(!R+LE{{bb9 B8~XqN literal 0 HcmV?d00001 diff --git a/test/tests/meshgenerators/parsed_generate_nodeset/gold/parsed_generate_nodeset_nodeset_limited_in.e b/test/tests/meshgenerators/parsed_generate_nodeset/gold/parsed_generate_nodeset_nodeset_limited_in.e new file mode 100644 index 0000000000000000000000000000000000000000..71a8a5d1421cc92a3a39e8a7f5ae60dcdab013e2 GIT binary patch literal 12360 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 JS>9Z}{sLu) -1' + include_only_external_nodes = true + new_nodeset_name = exterior + [] +[] + diff --git a/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_nodeset_excluded.i b/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_nodeset_excluded.i new file mode 100644 index 000000000000..02b93591e249 --- /dev/null +++ b/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_nodeset_excluded.i @@ -0,0 +1,40 @@ +[Mesh] + [gmg] + type = GeneratedMeshGenerator + dim = 3 + nx = 3 + ny = 3 + nz = 3 + xmax = 3 + ymax = 3 + zmax = 3 + [] + + [subdomains] + type = ParsedSubdomainMeshGenerator + input = gmg + combinatorial_geometry = 'x < 1 & y > 1 & y < 2' + block_id = 1 + [] + + [nodeset] + type = ParsedGenerateNodeset + input = subdomains + expression = 'z < 1.6' + included_subdomains = '1' + new_nodeset_name = interior + [] + + [nodeset_further_limited] + type = ParsedGenerateNodeset + input = nodeset + expression = 'z > -1' + included_subdomains = '1' + excluded_nodesets = 'interior' + new_nodeset_name = 'none_from_interior' + [] +[] + +[Outputs] + exodus = true +[] diff --git a/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_nodeset_limited.i b/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_nodeset_limited.i new file mode 100644 index 000000000000..5c2310d1e741 --- /dev/null +++ b/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_nodeset_limited.i @@ -0,0 +1,39 @@ +[Mesh] + [gmg] + type = GeneratedMeshGenerator + dim = 3 + nx = 3 + ny = 3 + nz = 4 + xmax = 3 + ymax = 3 + zmax = 3 + [] + + [subdomains] + type = ParsedSubdomainMeshGenerator + input = gmg + combinatorial_geometry = 'x < 1 & y > 1 & y < 2' + block_id = 1 + [] + + [nodeset] + type = ParsedGenerateNodeset + input = subdomains + expression = 'z < 1.6' + included_subdomains = '1' + new_nodeset_name = interior + [] + + [nodeset_further_limited] + type = ParsedGenerateNodeset + input = nodeset + expression = 'z > 0.6' + included_nodesets = 'interior' + new_nodeset_name = interior_smaller + [] +[] + +[Outputs] + exodus = true +[] diff --git a/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_subdomain_limited.i b/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_subdomain_limited.i new file mode 100644 index 000000000000..bd442d4101ce --- /dev/null +++ b/test/tests/meshgenerators/parsed_generate_nodeset/parsed_generate_nodeset_subdomain_limited.i @@ -0,0 +1,31 @@ +[Mesh] + [gmg] + type = GeneratedMeshGenerator + dim = 3 + nx = 2 + ny = 3 + nz = 3 + xmax = 3 + ymax = 3 + zmax = 3 + [] + + [subdomains] + type = ParsedSubdomainMeshGenerator + input = gmg + combinatorial_geometry = 'x < 1 & y > 1 & y < 2' + block_id = 1 + [] + + [nodeset] + type = ParsedGenerateNodeset + input = subdomains + expression = 'z < 1' + included_subdomains = '1' + new_nodeset_name = interior + [] +[] + +[Outputs] + exodus = true +[] diff --git a/test/tests/meshgenerators/parsed_generate_nodeset/tests b/test/tests/meshgenerators/parsed_generate_nodeset/tests new file mode 100644 index 000000000000..6368a73ee901 --- /dev/null +++ b/test/tests/meshgenerators/parsed_generate_nodeset/tests @@ -0,0 +1,101 @@ +[Tests] + issues = '#28881' + design = 'meshgenerators/ParsedGenerateNodeset.md' + + [parsed_generate_nodeset_sub_id_test] + type = 'Exodiff' + input = 'parsed_generate_nodeset_subdomain_limited.i' + cli_args = '--mesh-only' + exodiff = 'parsed_generate_nodeset_subdomain_limited_in.e' + exodiff_opts = -pedantic + recover = false + mesh_mode = 'replicated' + requirement = 'The system shall have the ability to filter by neighboring subdomain id when generating nodesets using a parsed expression to describe the nodeset.' + [] + + [limit_to_one_bid] + type = 'Exodiff' + input = 'parsed_generate_nodeset_nodeset_limited.i' + cli_args = '--mesh-only' + exodiff = 'parsed_generate_nodeset_nodeset_limited_in.e' + exodiff_opts = -pedantic + recover = false + mesh_mode = 'replicated' + requirement = 'The system shall have the ability to assign mesh node sets based on parsed spatial functions, with a restriction on nodes that are also part of another nodeset.' + [] + + [exclude_bids] + type = 'Exodiff' + input = 'parsed_generate_nodeset_nodeset_excluded.i' + cli_args = '--mesh-only' + exodiff = 'parsed_generate_nodeset_nodeset_excluded_in.e' + exodiff_opts = -pedantic + recover = false + mesh_mode = 'replicated' + requirement = 'The system shall have the ability to assign mesh node sets based on parsed spatial functions, excluding nodes that are also part of another nodeset.' + [] + + [limit_to_external_nodes] + type = 'Exodiff' + input = 'parsed_generate_nodeset_exterior_limited.i' + cli_args = '--mesh-only' + exodiff = 'parsed_generate_nodeset_exterior_limited_in.e' + exodiff_opts = -pedantic + recover = false + mesh_mode = 'replicated' + requirement = 'The system shall have the ability to assign mesh node sets based on parsed spatial functions, with a restriction on using nodes that are on the exterior of the mesh only.' + [] + + [missing_errors] + requirement = 'The system shall report an error' + issues = '#22117' + [invalid_included_subdomains] + type = RunException + input = parsed_generate_nodeset_subdomain_limited.i + cli_args = 'Mesh/nodeset/included_subdomains="missing" --mesh-only' + expect_err = "The block 'missing' was not found in the mesh" + detail = 'if one of the included subdomains does not exist in the mesh,' + mesh_mode = 'replicated' + [] + [invalid_included_nodeset] + type = RunException + input = parsed_generate_nodeset_subdomain_limited.i + cli_args = 'Mesh/nodeset/included_nodesets="missing" --mesh-only' + expect_err = "The nodeset 'missing' was not found within the mesh" + detail = 'if one of the included nodesets does not exist in the mesh,' + mesh_mode = 'replicated' + [] + [invalid_excluded_nodeset] + type = RunException + input = parsed_generate_nodeset_subdomain_limited.i + cli_args = 'Mesh/nodeset/excluded_nodesets="missing" --mesh-only' + expect_err = "The nodeset 'missing' was not found within the mesh" + detail = 'if one of the excluded nodesets does not exist in the mesh,' + mesh_mode = 'replicated' + [] + [] + [overlap_included_excluded_nodeset] + type = RunException + input = parsed_generate_nodeset_subdomain_limited.i + cli_args = 'Mesh/nodeset/included_nodesets="top" Mesh/nodeset/excluded_nodesets="top" --mesh-only' + expect_err = "'included_nodesets' and 'excluded_nodesets' lists should not overlap" + requirement = 'The system shall report an error if a nodeset appears in both the list of nodesets to include and to exclude.' + mesh_mode = 'replicated' + [] + [overlap_included_target_nodeset] + type = RunException + input = parsed_generate_nodeset_subdomain_limited.i + cli_args = 'Mesh/nodeset/included_nodesets="interior" --mesh-only' + expect_err = "nodeset cannot be both the new nodeset and be included in the list of included nodesets" + requirement = 'The system shall report an error if the nodeset to create appears in the list of nodesets to include.' + mesh_mode = 'replicated' + [] + [overlap_excluded_target_nodeset] + type = RunException + input = parsed_generate_nodeset_subdomain_limited.i + cli_args = 'Mesh/nodeset/excluded_nodesets="interior" --mesh-only' + expect_err = "nodeset cannot be both the new nodeset and be excluded in the list of excluded nodesets" + requirement = 'The system shall report an error if the nodeset to create appears in the list of nodesets to exclude.' + mesh_mode = 'replicated' + [] +[] From 045450a6eda384a2977701e40641707c8106d2c3 Mon Sep 17 00:00:00 2001 From: Guillaume Giudicelli Date: Wed, 30 Oct 2024 16:36:04 -0600 Subject: [PATCH 5/6] Address Patrick's review - fix docstrings - add more param details in docstring - more const Co-authored-by: Patrick Behne <31858053+pbehne@users.noreply.github.com> --- .../meshgenerators/ParsedGenerateNodeset.md | 2 +- .../meshgenerators/NodeSetsGeneratorBase.h | 19 ++++- .../meshgenerators/NodeSetsGeneratorBase.C | 4 +- .../meshgenerators/ParsedGenerateNodeset.C | 11 +-- .../meshgenerators/ParsedGenerateSideset.C | 3 +- .../parsed_generate_nodeset/gold/replace_in.e | Bin 0 -> 12296 bytes .../parsed_generate_nodeset/tests | 73 ++++++++++++------ 7 files changed, 72 insertions(+), 40 deletions(-) create mode 100644 test/tests/meshgenerators/parsed_generate_nodeset/gold/replace_in.e diff --git a/framework/doc/content/source/meshgenerators/ParsedGenerateNodeset.md b/framework/doc/content/source/meshgenerators/ParsedGenerateNodeset.md index 7f875a485efe..29dcf2e2c562 100644 --- a/framework/doc/content/source/meshgenerators/ParsedGenerateNodeset.md +++ b/framework/doc/content/source/meshgenerators/ParsedGenerateNodeset.md @@ -4,7 +4,7 @@ Optionally, additional constraints can be imposed when examining a node based on : -- the subdomain of the element owning the node connodered for the nodeset +- the subdomain of the element owning the node considered for the nodeset - whether the node is already part of (or not part of) an existing boundary - whether the node is 'external', e.g. it lies on the mesh exterior boundary diff --git a/framework/include/meshgenerators/NodeSetsGeneratorBase.h b/framework/include/meshgenerators/NodeSetsGeneratorBase.h index 487b4b7fa536..051372c1dba3 100644 --- a/framework/include/meshgenerators/NodeSetsGeneratorBase.h +++ b/framework/include/meshgenerators/NodeSetsGeneratorBase.h @@ -31,37 +31,48 @@ class NodeSetsGeneratorBase : public MeshGenerator /** * Determines whether the node is on the exterior of the mesh + * @param node node of interest + * @param node_elems vector of the ids of all the elements sharing this node + * @param mesh mesh which contains the node */ bool nodeOnMeshExteriorBoundary(const Node * node, const std::vector & node_elems, const MeshBase & mesh) const; /** - * Determines whether any neighbor element of the node has a subdomain id is in the given + * Determines whether any neighbor element of the node has a subdomain id in the given * subdomain_id_list. + * @param node_elems vector of the ids of all the elements sharing this node + * @param mesh mesh which contains the node (and the elements) */ bool nodeElementsInIncludedSubdomains(const std::vector node_elems, const MeshBase & mesh) const; /** - * Determines whether the given node of an element belongs to any nodesets in the + * Determines whether the given node belongs to any nodesets in the * included_nodesets parameter. + * @param node_nodesets vector of the ids of all the nodesets the node is part of */ bool nodeInIncludedNodesets(const std::vector & node_nodesets) const; /** * Determines whether the given node of an element belongs to any nodesets in the * excluded_nodesets parameter. + * @param node_nodesets vector of the ids of all the nodesets the node is part of */ bool nodeInExcludedNodesets(const std::vector & node_nodesets) const; /** - * Determines whether the given element's node satisfies the user-specified constraints + * Determines whether the given node satisfies the user-specified constraints + * @param node node of interest + * @param node_nodesets vector of the ids of all the nodesets the node is part of + * @param node_elems vector of the ids of all the elements sharing this node + * @param mesh mesh which contains the node */ bool nodeSatisfiesRequirements(const Node * node, const std::vector & node_nodesets, const std::vector & node_elems, - const MeshBase & mesh); + const MeshBase & mesh) const; /// the mesh to add the nodesets to std::unique_ptr & _input; diff --git a/framework/src/meshgenerators/NodeSetsGeneratorBase.C b/framework/src/meshgenerators/NodeSetsGeneratorBase.C index 3d659c3a0966..817eada180b9 100644 --- a/framework/src/meshgenerators/NodeSetsGeneratorBase.C +++ b/framework/src/meshgenerators/NodeSetsGeneratorBase.C @@ -131,7 +131,7 @@ NodeSetsGeneratorBase::setup(MeshBase & mesh) } } - // Get the nodeset ids from the names + // Get the subdomain ids from the names if (_check_included_subdomains) { // check that the subdomains exist in the mesh @@ -212,7 +212,7 @@ bool NodeSetsGeneratorBase::nodeSatisfiesRequirements(const Node * node, const std::vector & node_nodesets, const std::vector & node_elems, - const MeshBase & mesh) + const MeshBase & mesh) const { // Skip if side has neighbor and we only want external nodes if (_include_only_external_nodes && !nodeOnMeshExteriorBoundary(node, node_elems, mesh)) diff --git a/framework/src/meshgenerators/ParsedGenerateNodeset.C b/framework/src/meshgenerators/ParsedGenerateNodeset.C index e92469db9fe1..c7de9e591649 100644 --- a/framework/src/meshgenerators/ParsedGenerateNodeset.C +++ b/framework/src/meshgenerators/ParsedGenerateNodeset.C @@ -69,12 +69,7 @@ ParsedGenerateNodeset::ParsedGenerateNodeset(const InputParameters & parameters) // parse function if (_func_F->Parse(_function, "x,y,z") >= 0) - mooseError("Invalid function\n", - _function, - "\nin ParsedGenerateNodeset ", - name(), - ".\n", - _func_F->ErrorMsg()); + paramError("expression", "Invalid function\n", _function, "\n", _func_F->ErrorMsg()); _func_params.resize(3); } @@ -128,8 +123,8 @@ ParsedGenerateNodeset::generate() { if (_replace) { - for (auto i = node_nodesets_iters.first; i != node_nodesets_iters.second; ++i) - boundary_info.remove_node(curr_node, i->second); + for (const auto nodeset_id : node_nodesets) + boundary_info.remove_node(curr_node, nodeset_id); } boundary_info.add_node(curr_node, nodeset_ids[0]); } diff --git a/framework/src/meshgenerators/ParsedGenerateSideset.C b/framework/src/meshgenerators/ParsedGenerateSideset.C index 0cb55ae8ece2..984309c8b7e5 100644 --- a/framework/src/meshgenerators/ParsedGenerateSideset.C +++ b/framework/src/meshgenerators/ParsedGenerateSideset.C @@ -68,7 +68,8 @@ ParsedGenerateSideset::ParsedGenerateSideset(const InputParameters & parameters) // parse function if (_func_F->Parse(_function, "x,y,z") >= 0) - mooseError("Invalid function\n", _function, "\n", _func_F->ErrorMsg()); + paramError( + "combinatorial_geometry", "Invalid function\n", _function, "\n", _func_F->ErrorMsg()); _func_params.resize(3); } diff --git a/test/tests/meshgenerators/parsed_generate_nodeset/gold/replace_in.e b/test/tests/meshgenerators/parsed_generate_nodeset/gold/replace_in.e new file mode 100644 index 0000000000000000000000000000000000000000..5ee854aed8a91fb3247c255f84459d993caee3ef GIT binary patch literal 12296 zcmeI2xpP!U5XM)4(C$hc1{rhNEFdnS1Di{}&+YOxZeQay}hTBS-*XtshnJy-gwk1BzSx^oj4GCG- zFD#Y64N2JDW%CNnpcTzco4i?Ck=?d@r{udM9i=L2J`MHc^t&h0Q>X_G*$fBJvzGr^ z$lviMKOBHRfF5VJiIR*bgE-*HF0LcHw2tiZIl<7v!)(fv zVb+&n)|X+{w{aC2v5Bo^0$CUr)qRW=>!reXL8Do!RT=9QdZv1Q`(AZl2l>I(a;?}Z zRUZ`UwNkZJcwB3&D8|o}U!gsc3>%r%Qd#@$24Z83@2?b}lq%$y^0J@=eb9O+aeIDF z?Exvja!H9=Y&{~C@Fh%O)xE7!tBgUFFz*^cybdB}QIE`;k2mR=i`5H4}C!a5>;_62S6>y28S{4y>%MSF)kci|ehFU&~d{IL1I zs-LMg->}D;tY9zaI@#Y#sCL|^p@jH#;O=_S<~~c}?nN(q#8!|;b2EH93azL0 z=zzlMou9owp_(Fnq#ot;EB&M+eO#7s`JQp6&6f@6OFb7~Wf*+}q5ZY~m_bOif1r^{ zoqwXAbjWXp7dY$3t`)dLt~27!Nce3_BTSf?s9sFC>)#C;Ao zS}z|G^zIg{#P$9nq3KQH{slME%f|@4dju;ny`y_2G`&gOJlsexA2jqb-%4C>T|(2F z#Qh0wq?eB(dOr}Xpm)f1M*mQ4dXu>Sz;)-Ly~q2Up70mFdDkC1sM@%;Z~NU?_zQQ@ z^~dh3Hm>c(pc@N+9v?0Sf4vSALCjaKJvJE*B}2e#^oOv#20_9 zu-<4N$NyB@)-a(q+(UvDxH;Duf2o>rK(Y3J)yCs);Nn6b_d1s%_h_fN8Vbk!dB{_f ze}`4OcD>iXoyPMKrDM%4p_1=Vn_kCyy$-^t|hQvtxR!HhJ4_B=G&{$dA^U zG;Vf`XSK<@#lHD#{#$Kwt4(gTFW+oGA5D1c+RH~jKa%>kUaQS7t9`lO&qsoeb;9~g zpVem9YG3a6^O2xq{XesB{#iZw(zQC(#nuZUe5fTdciRSW<8+MNMtlpZ{6b*Jm0*R5K; zi@i^!%E4+kZ+~jFQLA=y0Q9&1pi!zdy7ds4|Al6ySS|-$7l*Cy|JL`voA1A^@Bh~K zznk;FTfh5Tes4t}iU99b{+pD&W%1WJ-qPc5;Jh32#>;ywZ*IJE@+Qe!5+egtNjqVOTgX@Qytyj0xky1%Y>e z-aC26yd?1M$a^C1guMTKE_@+;DSRb-EnE{Og}g8&TobxgV$0h$Tg2NcPa{`?B+b8+r@2BrCdu@Bno)e3> zzl_=5lLx-P%t1~*kQ=_gjFC4Z0vzApVab?hdF1=c81u+4IKID(p_|-;#{^ z@04WMg=vBFf`^1zOuugpG z5w;1ep;y=`U>~~~AuIF?147ch%{k|69}*4=M}+vDom1b>cl_u6Iv{XI#Mc9taerO( zlMvSv_ru~$eB Date: Fri, 1 Nov 2024 13:18:47 -0600 Subject: [PATCH 6/6] Address Alex's review - use an unordered map for performance Co-authored-by: Alex Lindsay --- framework/include/meshgenerators/NodeSetsGeneratorBase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/include/meshgenerators/NodeSetsGeneratorBase.h b/framework/include/meshgenerators/NodeSetsGeneratorBase.h index 051372c1dba3..16377810c73e 100644 --- a/framework/include/meshgenerators/NodeSetsGeneratorBase.h +++ b/framework/include/meshgenerators/NodeSetsGeneratorBase.h @@ -107,5 +107,5 @@ class NodeSetsGeneratorBase : public MeshGenerator /// A map from nodes (ids) to local elements (ids) which comprise the node // Build the node to element map, which is usually provided by a MooseMesh but here we have a // MeshBase. - std::map> _node_to_elem_map; + std::unordered_map> _node_to_elem_map; };