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 "OrientSurfaceMeshGenerator.h" 11 : #include "Parser.h" 12 : #include "InputParameters.h" 13 : #include "CastUniquePointer.h" 14 : 15 : #include "libmesh/fe_base.h" 16 : #include "libmesh/mesh_generation.h" 17 : #include "libmesh/mesh.h" 18 : #include "libmesh/string_to_enum.h" 19 : #include "libmesh/quadrature_gauss.h" 20 : #include "libmesh/point_locator_base.h" 21 : #include "libmesh/distributed_mesh.h" 22 : #include "libmesh/elem.h" 23 : 24 : #include <typeinfo> 25 : 26 : registerMooseObject("MooseApp", OrientSurfaceMeshGenerator); 27 : 28 : InputParameters 29 3117 : OrientSurfaceMeshGenerator::validParams() 30 : { 31 3117 : InputParameters params = SurfaceMeshGeneratorBase::validParams(); 32 : 33 : // NOTE: libmesh tetrahedralization code actually has a clever heuristic 34 : // to re-orient elements starting from the known orientation of the "bottom-most" 35 : // surface element. We could import that logic here, once we identify and separate connected 36 : // (contiguous) components of the mesh. 37 : 38 : // Which elements to apply the change on 39 12468 : params.setDocString( 40 : "included_subdomains", 41 : "Subdomain names or ids for the elements that may have their normal modified."); 42 : 43 : // How to set the normal 44 18702 : params.renameParam("normal", 45 : "normal_to_align_with", 46 : "Direction vector that element normals should be pointing in the same " 47 : "direction as (dot product > 0)"); 48 12468 : params.addParam<std::vector<dof_id_type>>( 49 : "element_ids_to_flood_from", 50 : "IDs of elements to start flooding and changing the subdomains from"); 51 : 52 : // This mesh generator does not modify the subdomains 53 6234 : params.suppressParameter<std::vector<SubdomainName>>("new_subdomain"); 54 : // This mesh generator is specifically intended to flip normals 55 6234 : params.set<bool>("flip_inverted_normals") = true; 56 6234 : params.suppressParameter<bool>("flip_inverted_normals"); 57 6234 : params.set<bool>("consider_flipped_normals") = true; 58 6234 : params.set<bool>("_using_normal") = true; 59 : 60 3117 : params.addClassDescription("Change the orientation of (part of) the surface mesh."); 61 3117 : return params; 62 0 : } 63 : 64 28 : OrientSurfaceMeshGenerator::OrientSurfaceMeshGenerator(const InputParameters & parameters) 65 28 : : SurfaceMeshGeneratorBase(parameters), _num_flipped(0) 66 : { 67 120 : if (!isParamValid("element_ids_to_flood_from") && !isParamSetByUser("normal_to_align_with")) 68 0 : paramError("normal_to_align_with", 69 : "Either a 'normal_to_align_with' or 'element_ids_to_flood_from' must be specified " 70 : "to select the behavior of this mesh generator."); 71 28 : } 72 : 73 : std::unique_ptr<MeshBase> 74 28 : OrientSurfaceMeshGenerator::generate() 75 : { 76 28 : std::unique_ptr<MeshBase> mesh = std::move(_input); 77 28 : setup(*mesh); 78 : 79 28 : auto & binfo = mesh->get_boundary_info(); 80 56 : bool normal_is_input = isParamSetByUser("normal_to_align_with"); 81 : 82 84 : if (!isParamValid("element_ids_to_flood_from")) 83 : // We'll need to loop over all of the elements to adjust normals with the fixed normal option 84 250 : for (auto & elem : mesh->element_ptr_range()) 85 : { 86 : // Nothing to do with edges or 3D elements 87 232 : if (elem->dim() != 2) 88 160 : continue; 89 : 90 : // Check if element should be used to paint from 91 424 : if (_included_subdomain_ids.size() && 92 192 : std::find(_included_subdomain_ids.begin(), 93 : _included_subdomain_ids.end(), 94 616 : elem->subdomain_id()) == _included_subdomain_ids.end()) 95 160 : continue; 96 : 97 : // Compute the normal 98 72 : const auto normal = get2DElemNormal(elem); 99 : 100 72 : if (normal * _normal < 0) 101 : { 102 72 : elem->flip(&binfo); 103 72 : _num_flipped++; 104 : } 105 18 : } 106 : else 107 : // We'll flood and re-adjust orientations starting from a few given elements 108 : // NOTE: user's responsibility to make sure these surface elements' orientations are consistent 109 40 : for (const auto eid : getParam<std::vector<dof_id_type>>("element_ids_to_flood_from")) 110 : { 111 10 : auto elem = mesh->elem_ptr(eid); 112 : 113 : // Nothing to do with edges or 3D elements 114 10 : if (elem->dim() != 2) 115 0 : continue; 116 : 117 : // Compute the normal 118 10 : const auto normal = normal_is_input ? _normal : get2DElemNormal(elem); 119 : 120 10 : flood(elem, normal, *elem, elem->subdomain_id(), *mesh); 121 : } 122 : 123 28 : if (_num_flipped) 124 28 : _console << "Flipped the orientation of " << _num_flipped << " surface elements." << std::endl; 125 : 126 56 : return dynamic_pointer_cast<MeshBase>(mesh); 127 28 : }