diff --git a/framework/doc/content/source/meshgenerators/MeshExtruderGenerator.md b/framework/doc/content/source/meshgenerators/MeshExtruderGenerator.md index 4b10ed9b9c53..f6b431c90c0a 100644 --- a/framework/doc/content/source/meshgenerators/MeshExtruderGenerator.md +++ b/framework/doc/content/source/meshgenerators/MeshExtruderGenerator.md @@ -8,6 +8,10 @@ The mesh extruder generator is a tool for increasing the dimensionality of a low to one or more copies of its corresponding higher dimensional element along the specified axis. The Mesh Extruder can also add in the extra sidesets resulting from increasing the dimensionality of the original mesh. Existing sidesets are extruded. +Through the `existing_subdomains`, `layers`, and `new_ids` options, it is possible to specify that an extruded block exists in some layers, + but not others. This allows for serrated patterns and gaps. Note that no error will be thrown if the resulting blocks overlap. These three + options must have the same number of values given to them. The extrusion vector may use decimal values. + ## Visual Example ### Input 2D Mesh diff --git a/framework/doc/content/source/meshgenerators/SideSetExtruderGenerator.md b/framework/doc/content/source/meshgenerators/SideSetExtruderGenerator.md new file mode 100644 index 000000000000..a59fc67ab9b9 --- /dev/null +++ b/framework/doc/content/source/meshgenerators/SideSetExtruderGenerator.md @@ -0,0 +1,65 @@ +# SideSetExtruderGenerator + +!syntax description /Mesh/SideSetExtruderGenerator + +## Overview + +The SideSetExtruder Generator is for "pulling" mesh in a direction. Given a sideset and a direction(vector), it adds to the mesh. SideSetExtruder differs from [MeshExtruderGenerator](MeshExtruderGenerator.md) in that the extrusion stays in the same dimension as the sideset it is pulling on (MeshExtruderGenerator is for pulling 2 dimensional shapes into 3 dimensions). + +SideSetExtruder will not throw any errors if you extrude a mesh through (collide with) another mesh. It will throw an error if the extrusion vector would create a mesh with a negative determinant (or rather, [MeshExtruderGenerator](MeshExtruderGenerator.md) throws the error). The extrusion vector is applied relative to the sideset given, not from the origin point of the mesh. The extrusion vector must be a 3D vector even if you are only extruding a 2D mesh; in such a case, let the z component be 0 (e.g., `extrusion_vector = '1 0.5 0'`) + +The output will have no sidesets, even the sideset you extruded from will be gone. The user is expected to use the other side-set generating generators on the output if sidesets are needed. + +## Visual Example + +### Input 2D Mesh + +!media large_media/framework/meshgenerators/sideset_extruder_before.png caption=Before: a square, with sidesets on each side. + +### Output of SideSetExtruderGenerator + +!media large_media/framework/meshgenerators/sideset_extruder_after.png caption=After, the right sideset has been extruded in the < 1, 0.5, 0> direction. + +SideSetExtruderGenerator is actually a mere wrapper of 4 other generators: [LowerDBlockFromSidesetGenerator](LowerDBlockFromSidesetGenerator.md), [BlockToMeshConverterGenerator](BlockToMeshConverterGenerator.md), [MeshExtruderGenerator](MeshExtruderGenerator.md), and [StitchedMeshGenerator](StitchedMeshGenerator.md). SideSetExtruderGenerator's output from the example above is exactly equivalent to the output of a recipe like this: + +``` +[Mesh] + [square] + type = GeneratedMeshGenerator + dim = 2 + [] + [lowerDblock] + type = LowerDBlockFromSidesetGenerator + input = square + new_block_name = "extrusions0" + sidesets = "right" + [] + [separateMesh] + type = BlockToMeshConverterGenerator + input = lowerDblock + target_blocks = extrusions0 + [] + [extrude] + type = MeshExtruderGenerator + input = separateMesh + num_layers = 3 + extrusion_vector = '1 0.5 0' + bottom_sideset = 'new_bottom' + top_sideset = 'new_top' + [] + [stitch] + type = StitchedMeshGenerator + inputs = 'square extrude' + stitch_boundaries_pairs = 'right new_bottom' + [] +[] + +``` + +If you are needing to tweak the output of SideSetExtruderGenerator, you may be better off manually running these operations instead. SideSetExtruderGenerator uses the defaults of these sub-generators. + +!syntax parameters /Mesh/SideSetExtruderGenerator + +!syntax inputs /Mesh/SideSetExtruderGenerator + +!syntax children /Mesh/SideSetExtruderGenerator diff --git a/framework/doc/content/source/meshgenerators/StitchedMeshGenerator.md b/framework/doc/content/source/meshgenerators/StitchedMeshGenerator.md index c3f9c6a9c197..31adf408260d 100644 --- a/framework/doc/content/source/meshgenerators/StitchedMeshGenerator.md +++ b/framework/doc/content/source/meshgenerators/StitchedMeshGenerator.md @@ -15,6 +15,8 @@ Consider the following three meshes. Using the `StitchedMeshGenerator` object from within the [Mesh](/Mesh/index.md) block of the input file, as shown in the input file snippet below, these three square meshes are joined into a single mesh as shown in Figure 4. +Note that the way that the meshes are merged gives precedence to the left-most mesh listed in terms of sidesets: the sidesets of the second, third, etc meshes will be subsumed into the sidesets of the first mesh. The names of the sidesets in the first mesh are what the names that will remain in the outputted mesh. + !listing test/tests/meshgenerators/stitched_mesh_generator/stitched_mesh_generator.i block=Mesh !media media/mesh/stitched_mesh_out.png caption=Fig. 4: Resulting "stitched" mesh from combination of three square meshes. diff --git a/framework/include/meshgenerators/SideSetExtruderGenerator.h b/framework/include/meshgenerators/SideSetExtruderGenerator.h new file mode 100644 index 000000000000..dff33c4e2b18 --- /dev/null +++ b/framework/include/meshgenerators/SideSetExtruderGenerator.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 "MeshGenerator.h" + +#include "libmesh/mesh_generation.h" + +/** + * Extrude a 1D, 2D, or 3D mesh outward within the same dimension + */ +class SideSetExtruderGenerator : public MeshGenerator +{ +public: + static InputParameters validParams(); + + SideSetExtruderGenerator(const InputParameters & parameters); + + std::unique_ptr generate() override; + +protected: + /// Mesh that comes from another generator + std::unique_ptr * _build_mesh; + + const MeshGeneratorName _original_input; + const RealVectorValue _extrusion_vector; + const unsigned int _num_layers; + const BoundaryName _sideset_name; +}; diff --git a/framework/src/meshgenerators/SideSetExtruderGenerator.C b/framework/src/meshgenerators/SideSetExtruderGenerator.C new file mode 100644 index 000000000000..79efc17a8dea --- /dev/null +++ b/framework/src/meshgenerators/SideSetExtruderGenerator.C @@ -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 + +#include "SideSetExtruderGenerator.h" +#include "CastUniquePointer.h" + +registerMooseObject("MooseApp", SideSetExtruderGenerator); + +InputParameters +SideSetExtruderGenerator::validParams() +{ + InputParameters params = MeshGenerator::validParams(); + + params.addClassDescription("Takes a 1D or 2D mesh and extrudes the entire structure along the " + "specified axis increasing the dimensionality of the mesh."); + + // list params + params.addRequiredParam("input", "The mesh we want to modify"); + params.addRequiredParam("extrusion_vector", + "The direction and length of the extrusion"); + params.addParam("num_layers", 1, "The number of layers in the extruded mesh"); + params.addRequiredParam("sideset", + "The side set (boundary) that will be extruded from"); + + return params; +} + +SideSetExtruderGenerator::SideSetExtruderGenerator(const InputParameters & parameters) + : MeshGenerator(parameters), + _original_input(getParam("input")), + _extrusion_vector(getParam("extrusion_vector")), + _num_layers(getParam("num_layers")), + _sideset_name(getParam("sideset")) +{ + // constants needed only temporarily + const BoundaryName _EXTRUDED_BLOCK_NAME = "extruded_block"; + const BoundaryName _SIDESET_TO_BE_STITCHED = "to_be_stitched"; + + // sub generators + { + auto params = _app.getFactory().getValidParams("LowerDBlockFromSidesetGenerator"); + + params.set("input") = _original_input; + params.set("new_block_name") = _EXTRUDED_BLOCK_NAME; + params.set>("sidesets") = {_sideset_name}; + + // generate lower dimensional mesh from the given sidesets + _build_mesh = &addMeshSubgenerator( + "LowerDBlockFromSidesetGenerator", name() + "_lowerDgeneration", params); + } + + { + auto params = _app.getFactory().getValidParams("BlockToMeshConverterGenerator"); + + params.set("input") = name() + "_lowerDgeneration"; + params.set>("target_blocks") = {_EXTRUDED_BLOCK_NAME}; + + // convert lower dimensional block to a separate mesh + _build_mesh = + &addMeshSubgenerator("BlockToMeshConverterGenerator", name() + "_blockToMesh", params); + } + + { + auto params = _app.getFactory().getValidParams("MeshExtruderGenerator"); + + params.set("input") = name() + "_blockToMesh"; + params.set("extrusion_vector") = _extrusion_vector; + params.set("num_layers") = _num_layers; + params.set>("bottom_sideset") = {_SIDESET_TO_BE_STITCHED}; + + // extrude the new, separate mesh into a higher dimension + _build_mesh = &addMeshSubgenerator("MeshExtruderGenerator", name() + "_extruder", params); + } + + { + auto params = _app.getFactory().getValidParams("StitchedMeshGenerator"); + + // order of vector elements matters for this generator + // here order by: original mesh first, our custom mesh second + params.set>("inputs") = {_original_input, name() + "_extruder"}; + + params.set>>("stitch_boundaries_pairs") = { + {_sideset_name, _SIDESET_TO_BE_STITCHED}}; + + // stitch the newly made high-dimensional mesh back to the original mesh + _build_mesh = &addMeshSubgenerator("StitchedMeshGenerator", name() + "_stitched", params); + } +} + +std::unique_ptr +SideSetExtruderGenerator::generate() +{ + return dynamic_pointer_cast(*_build_mesh); +} diff --git a/test/tests/meshgenerators/sideset_extruder_generator/3d_serrated_multiblock.e b/test/tests/meshgenerators/sideset_extruder_generator/3d_serrated_multiblock.e new file mode 100644 index 000000000000..ff87de49503d Binary files /dev/null and b/test/tests/meshgenerators/sideset_extruder_generator/3d_serrated_multiblock.e differ diff --git a/test/tests/meshgenerators/sideset_extruder_generator/external_generators.i b/test/tests/meshgenerators/sideset_extruder_generator/external_generators.i new file mode 100644 index 000000000000..14ebff9f43f6 --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/external_generators.i @@ -0,0 +1,32 @@ +[Mesh] + # Note: don't change the parameters without also changing extrude_square, + # as they should be using identical file(s) in gold + [square] + type = GeneratedMeshGenerator + dim = 2 + [] + [lowerDblock] + type = LowerDBlockFromSidesetGenerator + input = square + new_block_name = "extrusions0" + sidesets = "right" + [] + [separateMesh] + type = BlockToMeshConverterGenerator + input = lowerDblock + target_blocks = extrusions0 + [] + [extrude] + type = MeshExtruderGenerator + input = separateMesh + num_layers = 3 + extrusion_vector = '1 0.5 0' + bottom_sideset = 'new_bottom' + top_sideset = 'new_top' + [] + [stitch] + type = StitchedMeshGenerator + inputs = 'square extrude' + stitch_boundaries_pairs = 'right new_bottom' + [] +[] diff --git a/test/tests/meshgenerators/sideset_extruder_generator/extrude_cube.i b/test/tests/meshgenerators/sideset_extruder_generator/extrude_cube.i new file mode 100644 index 000000000000..149932a0dcad --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/extrude_cube.i @@ -0,0 +1,13 @@ +[Mesh] + [cube] + type = GeneratedMeshGenerator + dim = 3 + [] + [extrude_top] + type = SideSetExtruderGenerator + input = cube + sideset = 'top' + extrusion_vector = '3 3 3' + num_layers = 3 + [] +[] diff --git a/test/tests/meshgenerators/sideset_extruder_generator/extrude_cube.i-e b/test/tests/meshgenerators/sideset_extruder_generator/extrude_cube.i-e new file mode 100644 index 000000000000..3301096b5d96 --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/extrude_cube.i-e @@ -0,0 +1,13 @@ +[Mesh] + [cube] + type = GeneratedMeshGenerator + dim = 3 + [] + [extrude_top] + type = SideSetExtruderGenerator + input = cube + sideset = 'top' + extrusion_vector = '3 3 3' + num_layers = 3 + [] +[] \ No newline at end of file diff --git a/test/tests/meshgenerators/sideset_extruder_generator/extrude_multiblock.i b/test/tests/meshgenerators/sideset_extruder_generator/extrude_multiblock.i new file mode 100644 index 000000000000..c04ca266676d --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/extrude_multiblock.i @@ -0,0 +1,13 @@ +[Mesh] + [file] + type = FileMeshGenerator + file = 3d_serrated_multiblock.e + [] + [extrude] + type = SideSetExtruderGenerator + input = file + sideset = '6' + extrusion_vector = '1 1 0.5' + num_layers = 3 + [] +[] diff --git a/test/tests/meshgenerators/sideset_extruder_generator/extrude_multiblock.i-e b/test/tests/meshgenerators/sideset_extruder_generator/extrude_multiblock.i-e new file mode 100644 index 000000000000..bfbdb82341a1 --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/extrude_multiblock.i-e @@ -0,0 +1,13 @@ +[Mesh] + [file] + type = FileMeshGenerator + file = 3d_serrated_multiblock.e + [] + [extrude] + type = SideSetExtruderGenerator + input = file + sideset = '6' + extrusion_vector = '1 1 0.5' + num_layers = 3 + [] +[] \ No newline at end of file diff --git a/test/tests/meshgenerators/sideset_extruder_generator/extrude_square.i b/test/tests/meshgenerators/sideset_extruder_generator/extrude_square.i new file mode 100644 index 000000000000..5fc07bf503f3 --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/extrude_square.i @@ -0,0 +1,15 @@ +[Mesh] + # Note: don't change the parameters without also changing extrude_square, + # as they should be using identical file(s) in gold + [square] + type = GeneratedMeshGenerator + dim = 2 + [] + [extrude_right] + type = SideSetExtruderGenerator + input = square + sideset = 'right' + extrusion_vector = '1 0.5 0' + num_layers = 3 + [] +[] diff --git a/test/tests/meshgenerators/sideset_extruder_generator/extrude_square.i-e b/test/tests/meshgenerators/sideset_extruder_generator/extrude_square.i-e new file mode 100644 index 000000000000..b8feb3511004 --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/extrude_square.i-e @@ -0,0 +1,15 @@ +[Mesh] + # Note: don't change the parameters without also changing extrude_square, + # as they should be using identical file(s) in gold + [square] + type = GeneratedMeshGenerator + dim = 2 + [] + [extrude_right] + type = SideSetExtruderGenerator + input = square + sideset = 'right' + extrusion_vector = '1 0.5 0' + num_layers = 3 + [] +[] \ No newline at end of file diff --git a/test/tests/meshgenerators/sideset_extruder_generator/gen_extrude.i b/test/tests/meshgenerators/sideset_extruder_generator/gen_extrude.i new file mode 100644 index 000000000000..54c6adbdff5b --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/gen_extrude.i @@ -0,0 +1,61 @@ +[Mesh] + [./gmg] + type = GeneratedMeshGenerator + dim = 2 + nx = 6 + ny = 6 + nz = 0 + zmin = 0 + zmax = 0 + elem_type = QUAD4 + [] + + [./extrude] + type = MeshExtruderGenerator + input = gmg + num_layers = 6 + extrusion_vector = '1 0 1' + bottom_sideset = 'new_front' + top_sideset = 'new_back' + [] +[] + +[Variables] + [./u] + order = FIRST + family = LAGRANGE + [../] +[] + +[Kernels] + [./diff] + type = Diffusion + variable = u + [../] +[] + +[BCs] + [./first] + type = DirichletBC + variable = u + boundary = 'new_front' + value = 0 + [../] + + [./second] + type = DirichletBC + variable = u + boundary = 'new_back' + value = 1 + [../] +[] + +[Executioner] + type = Steady + + solve_type = 'PJFNK' +[] + +[Outputs] + exodus = true +[] diff --git a/test/tests/meshgenerators/sideset_extruder_generator/gold/external_generators_in.e b/test/tests/meshgenerators/sideset_extruder_generator/gold/external_generators_in.e new file mode 100644 index 000000000000..ea88f6c291b1 Binary files /dev/null and b/test/tests/meshgenerators/sideset_extruder_generator/gold/external_generators_in.e differ diff --git a/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_cube_in.e b/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_cube_in.e new file mode 100644 index 000000000000..4d1d5b2cc612 Binary files /dev/null and b/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_cube_in.e differ diff --git a/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_multiblock_in.e b/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_multiblock_in.e new file mode 100644 index 000000000000..feeb2409807b Binary files /dev/null and b/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_multiblock_in.e differ diff --git a/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_square_in.e b/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_square_in.e new file mode 100644 index 000000000000..ea88f6c291b1 Binary files /dev/null and b/test/tests/meshgenerators/sideset_extruder_generator/gold/extrude_square_in.e differ diff --git a/test/tests/meshgenerators/sideset_extruder_generator/tests b/test/tests/meshgenerators/sideset_extruder_generator/tests new file mode 100644 index 000000000000..93d31d096df2 --- /dev/null +++ b/test/tests/meshgenerators/sideset_extruder_generator/tests @@ -0,0 +1,52 @@ +[Tests] + design = 'meshgenerators/SideSetExtruderGenerator.md' + issues = '#20880' + + [extruder] + requirement = 'The system shall have the capability of extruding the sideset of a mesh ' + 'in a given direction' + + [control] + type = 'Exodiff' + input = 'external_generators.i' + exodiff = 'external_generators_in.e' + recover = false + mesh_mode = 'REPLICATED' + cli_args = '--mesh-only' + + detail = 'SideSetExtruderGenerator is essentially just a wrapper for 4 other generators used in sequence. + The output of the 4 other generators should be identical to SideSetExtruderGenerator, or SideSetExtruderGenerator + has changed behavior' + [] + [square] + type = 'Exodiff' + input = 'extrude_square.i' + exodiff = 'extrude_square_in.e' + recover = false + mesh_mode = 'REPLICATED' + cli_args = '--mesh-only' + + detail = 'A simple case, extruding the right side of a square out at an upward angle' + [] + [cube] + type = 'Exodiff' + input = 'extrude_cube.i' + exodiff = 'extrude_cube_in.e' + recover = false + mesh_mode = 'REPLICATED' + cli_args = '--mesh-only' + + detail = 'Extruding the top side of a cube out a side-ways angle' + [] + [multiblock] + type = 'Exodiff' + input = 'extrude_multiblock.i' + exodiff = 'extrude_multiblock_in.e' + recover = false + mesh_mode = 'REPLICATED' + cli_args = '--mesh-only' + + detail = 'extruding an entangled block in a complicated 3d geomitry' + [] + [] +[]