LCOV - code coverage report
Current view: top level - src/meshgenerators - FillBetweenSidesetsGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 124 134 92.5 %
Date: 2026-05-29 20:35:17 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "FillBetweenSidesetsGenerator.h"
      11             : #include "FillBetweenPointVectorsTools.h"
      12             : 
      13             : #include "MooseMeshUtils.h"
      14             : #include "CastUniquePointer.h"
      15             : #include "libmesh/node.h"
      16             : #include "libmesh/mesh_serializer.h"
      17             : 
      18             : registerMooseObject("MooseApp", FillBetweenSidesetsGenerator);
      19             : 
      20             : InputParameters
      21        3212 : FillBetweenSidesetsGenerator::validParams()
      22             : {
      23        3212 :   InputParameters params = MeshGenerator::validParams();
      24       12848 :   params.addRequiredParam<MeshGeneratorName>("input_mesh_1",
      25             :                                              "The input mesh that contains boundary_1");
      26       12848 :   params.addRequiredParam<MeshGeneratorName>("input_mesh_2",
      27             :                                              "The input mesh that contains boundary_2");
      28       12848 :   params.addRequiredParam<std::vector<BoundaryName>>(
      29             :       "boundary_1", "the first boundary that needs to be connected.");
      30       12848 :   params.addRequiredParam<std::vector<BoundaryName>>(
      31             :       "boundary_2", "the second boundary that needs to be connected.");
      32        9636 :   params.addParam<Point>(
      33        6424 :       "mesh_1_shift", Point(0.0, 0.0, 0.0), "Translation vector to be applied to input_mesh_1");
      34        9636 :   params.addParam<Point>(
      35        6424 :       "mesh_2_shift", Point(0.0, 0.0, 0.0), "Translation vector to be applied to input_mesh_2");
      36       19272 :   params.addRequiredRangeCheckedParam<unsigned int>(
      37             :       "num_layers", "num_layers>0", "Number of layers of elements created between the boundaries.");
      38       12848 :   params.addParam<subdomain_id_type>("block_id", 1, "ID to be assigned to the transition layer.");
      39        9636 :   params.addParam<boundary_id_type>(
      40             :       "input_boundary_1_id",
      41        6424 :       10000,
      42             :       "Boundary ID to be assigned to the boundary defined by positions_vector_1.");
      43        9636 :   params.addParam<boundary_id_type>(
      44             :       "input_boundary_2_id",
      45        6424 :       10000,
      46             :       "Boundary ID to be assigned to the boundary defined by positions_vector_2.");
      47        9636 :   params.addParam<boundary_id_type>("begin_side_boundary_id",
      48        6424 :                                     10000,
      49             :                                     "Boundary ID to be assigned to the boundary connecting "
      50             :                                     "starting points of the positions_vectors.");
      51        9636 :   params.addParam<boundary_id_type>("end_side_boundary_id",
      52        6424 :                                     10000,
      53             :                                     "Boundary ID to be assigned to the boundary connecting ending "
      54             :                                     "points of the positions_vectors.");
      55        9636 :   params.addParam<bool>(
      56             :       "use_quad_elements",
      57        6424 :       false,
      58             :       "Whether QUAD4 instead of TRI3 elements are used to construct the transition layer.");
      59       16060 :   params.addRangeCheckedParam<Real>(
      60             :       "bias_parameter",
      61        6424 :       1.0,
      62             :       "bias_parameter>=0",
      63             :       "Parameter used to set up biasing of the layers: bias_parameter > 0.0 is used as the biasing "
      64             :       "factor; bias_parameter = 0.0 activates automatic biasing based on local node density on "
      65             :       "both input boundaries.");
      66       16060 :   params.addRangeCheckedParam<Real>(
      67             :       "gaussian_sigma",
      68        6424 :       3.0,
      69             :       "gaussian_sigma>0.0",
      70             :       "Gaussian parameter used to smoothen local node density for automatic biasing; this "
      71             :       "parameter is not used if another biasing option is selected.");
      72        9636 :   params.addParam<bool>(
      73             :       "keep_inputs",
      74        6424 :       true,
      75             :       "Whether to output the input meshes stitched with the transition layer connector.");
      76        3212 :   params.addClassDescription("This FillBetweenSidesetsGenerator object is designed to generate a "
      77             :                              "transition layer to connect two boundaries of two input meshes.");
      78        3212 :   return params;
      79           0 : }
      80             : 
      81          77 : FillBetweenSidesetsGenerator::FillBetweenSidesetsGenerator(const InputParameters & parameters)
      82             :   : MeshGenerator(parameters),
      83          77 :     _input_name_1(getParam<MeshGeneratorName>("input_mesh_1")),
      84         154 :     _input_name_2(getParam<MeshGeneratorName>("input_mesh_2")),
      85         154 :     _boundary_1(getParam<std::vector<BoundaryName>>("boundary_1")),
      86         154 :     _boundary_2(getParam<std::vector<BoundaryName>>("boundary_2")),
      87         154 :     _mesh_1_shift(getParam<Point>("mesh_1_shift")),
      88         231 :     _mesh_2_shift(getParam<Point>("mesh_2_shift")),
      89         154 :     _num_layers(getParam<unsigned int>("num_layers")),
      90         154 :     _block_id(getParam<subdomain_id_type>("block_id")),
      91         154 :     _input_boundary_1_id(getParam<boundary_id_type>("input_boundary_1_id")),
      92         154 :     _input_boundary_2_id(getParam<boundary_id_type>("input_boundary_2_id")),
      93         154 :     _begin_side_boundary_id(getParam<boundary_id_type>("begin_side_boundary_id")),
      94         154 :     _end_side_boundary_id(getParam<boundary_id_type>("end_side_boundary_id")),
      95         154 :     _use_quad_elements(getParam<bool>("use_quad_elements")),
      96         154 :     _bias_parameter(getParam<Real>("bias_parameter")),
      97         154 :     _sigma(getParam<Real>("gaussian_sigma")),
      98         154 :     _keep_inputs(getParam<bool>("keep_inputs")),
      99          77 :     _input_1(getMeshByName(_input_name_1)),
     100         154 :     _input_2(getMeshByName(_input_name_2))
     101             : {
     102          77 :   if (_input_name_1.compare(_input_name_2) == 0)
     103           6 :     paramError("input_mesh_2", "This parameter must be different from input_mesh_1.");
     104          74 : }
     105             : 
     106             : std::unique_ptr<MeshBase>
     107          71 : FillBetweenSidesetsGenerator::generate()
     108             : {
     109             :   // We're querying subdomain id caches from our input meshes
     110          71 :   if (!_input_1->preparation().has_cached_elem_data)
     111          71 :     _input_1->cache_elem_data();
     112          71 :   if (!_input_2->preparation().has_cached_elem_data)
     113          71 :     _input_2->cache_elem_data();
     114             : 
     115          71 :   auto input_mesh_1 = std::move(_input_1);
     116          71 :   auto input_mesh_2 = std::move(_input_2);
     117             : 
     118             :   // Only serialized meshes are supported right now
     119          71 :   libMesh::MeshSerializer serial_1(*input_mesh_1);
     120          71 :   libMesh::MeshSerializer serial_2(*input_mesh_2);
     121             : 
     122         142 :   if (*(input_mesh_1->elem_dimensions().begin()) != 2 ||
     123         142 :       *(input_mesh_1->elem_dimensions().rbegin()) != 2)
     124           0 :     paramError("input_mesh_1", "Only 2D meshes are supported.");
     125         142 :   if (*(input_mesh_2->elem_dimensions().begin()) != 2 ||
     126         142 :       *(input_mesh_2->elem_dimensions().rbegin()) != 2)
     127           0 :     paramError("input_mesh_2", "Only 2D meshes are supported.");
     128             : 
     129          71 :   MeshTools::Modification::translate(
     130          71 :       *input_mesh_1, _mesh_1_shift(0), _mesh_1_shift(1), _mesh_1_shift(2));
     131          71 :   MeshTools::Modification::translate(
     132          71 :       *input_mesh_2, _mesh_2_shift(0), _mesh_2_shift(1), _mesh_2_shift(2));
     133             : 
     134             :   const auto input_mesh_1_external_bids =
     135          71 :       MooseMeshUtils::getBoundaryIDs(*input_mesh_1, _boundary_1, false);
     136             :   const auto input_mesh_2_external_bids =
     137          71 :       MooseMeshUtils::getBoundaryIDs(*input_mesh_2, _boundary_2, false);
     138             : 
     139         115 :   for (unsigned int i = 1; i < input_mesh_1_external_bids.size(); i++)
     140             :   {
     141          44 :     MooseMeshUtils::changeBoundaryId(
     142          44 :         *input_mesh_1, input_mesh_1_external_bids[i], input_mesh_1_external_bids.front(), true);
     143             :   }
     144         109 :   for (unsigned int i = 1; i < input_mesh_2_external_bids.size(); i++)
     145             :   {
     146          38 :     MooseMeshUtils::changeBoundaryId(
     147          38 :         *input_mesh_2, input_mesh_2_external_bids[i], input_mesh_2_external_bids.front(), true);
     148             :   }
     149             : 
     150          71 :   if (!FillBetweenPointVectorsTools::isExternalBoundary(*input_mesh_1,
     151          71 :                                                         input_mesh_1_external_bids.front()))
     152           0 :     paramError("boundary_1", "The boundary provided is not an external boundary.");
     153          71 :   if (!FillBetweenPointVectorsTools::isExternalBoundary(*input_mesh_2,
     154          71 :                                                         input_mesh_2_external_bids.front()))
     155           0 :     paramError("boundary_2", "The boundary provided is not an external boundary.");
     156             : 
     157             :   Real max_input_mesh_1_node_radius;
     158             :   Real max_input_mesh_2_node_radius;
     159          71 :   std::vector<dof_id_type> boundary_1_ordered_nodes;
     160          71 :   std::vector<dof_id_type> boundary_2_ordered_nodes;
     161             : 
     162             :   try
     163             :   {
     164         142 :     FillBetweenPointVectorsTools::isBoundaryOpenSingleSegment(
     165          71 :         *input_mesh_1,
     166             :         max_input_mesh_1_node_radius,
     167             :         boundary_1_ordered_nodes,
     168          71 :         MooseMeshUtils::meshCentroidCalculator(*input_mesh_1),
     169          71 :         input_mesh_1_external_bids.front());
     170             :   }
     171           6 :   catch (MooseException & e)
     172             :   {
     173          12 :     paramError("boundary_1", e.what());
     174           0 :   }
     175             :   try
     176             :   {
     177         130 :     FillBetweenPointVectorsTools::isBoundaryOpenSingleSegment(
     178          65 :         *input_mesh_2,
     179             :         max_input_mesh_2_node_radius,
     180             :         boundary_2_ordered_nodes,
     181          65 :         MooseMeshUtils::meshCentroidCalculator(*input_mesh_2),
     182          65 :         input_mesh_2_external_bids.front());
     183             :   }
     184           0 :   catch (MooseException & e)
     185             :   {
     186           0 :     paramError("boundary_2", e.what());
     187           0 :   }
     188             : 
     189          65 :   std::vector<Point> positions_vector_1;
     190          65 :   std::vector<Point> positions_vector_2;
     191             : 
     192         564 :   for (auto & boundary_1_node_id : boundary_1_ordered_nodes)
     193         499 :     positions_vector_1.push_back(*input_mesh_1->node_ptr(boundary_1_node_id));
     194             : 
     195         692 :   for (auto & boundary_2_node_id : boundary_2_ordered_nodes)
     196         627 :     positions_vector_2.push_back(*input_mesh_2->node_ptr(boundary_2_node_id));
     197             : 
     198           0 :   const boundary_id_type input_boundary_1_id = _keep_inputs ? (std::max({_input_boundary_1_id,
     199          30 :                                                                          _input_boundary_2_id,
     200          30 :                                                                          _begin_side_boundary_id,
     201          30 :                                                                          _end_side_boundary_id}) +
     202             :                                                                1)
     203          95 :                                                             : _input_boundary_1_id;
     204          35 :   const boundary_id_type input_boundary_2_id =
     205          65 :       _keep_inputs ? (input_boundary_1_id + 1) : _input_boundary_2_id;
     206          65 :   auto mesh = buildReplicatedMesh(2);
     207          65 :   FillBetweenPointVectorsTools::fillBetweenPointVectorsGenerator(*mesh,
     208             :                                                                  positions_vector_1,
     209             :                                                                  positions_vector_2,
     210          65 :                                                                  _num_layers,
     211          65 :                                                                  _block_id,
     212             :                                                                  input_boundary_1_id,
     213             :                                                                  input_boundary_2_id,
     214          65 :                                                                  _begin_side_boundary_id,
     215          65 :                                                                  _end_side_boundary_id,
     216          65 :                                                                  _type,
     217          65 :                                                                  _name,
     218          65 :                                                                  _use_quad_elements,
     219          65 :                                                                  _bias_parameter,
     220          65 :                                                                  _sigma);
     221             : 
     222          65 :   if (_keep_inputs)
     223             :   {
     224          30 :     mesh->prepare_for_use();
     225          60 :     mesh->stitch_meshes(*input_mesh_1,
     226             :                         input_boundary_1_id,
     227          30 :                         input_mesh_1_external_bids.front(),
     228             :                         TOLERANCE,
     229             :                         true,
     230             :                         false,
     231             :                         true,
     232             :                         true);
     233          60 :     mesh->stitch_meshes(*input_mesh_2,
     234             :                         input_boundary_2_id,
     235          30 :                         input_mesh_2_external_bids.front(),
     236             :                         TOLERANCE,
     237             :                         true,
     238             :                         false,
     239             :                         true,
     240             :                         true);
     241             :   }
     242         130 :   return dynamic_pointer_cast<MeshBase>(mesh);
     243          65 : }

Generated by: LCOV version 1.14