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 "FileMeshComponent.h" 11 : #include "THMMesh.h" 12 : #include "MooseUtils.h" 13 : #include "libmesh/exodusII_io.h" 14 : #include "libmesh/exodusII_io_helper.h" 15 : 16 : registerMooseObject("ThermalHydraulicsApp", FileMeshComponent); 17 : 18 : InputParameters 19 466 : FileMeshComponent::validParams() 20 : { 21 466 : InputParameters params = GeometricalComponent::validParams(); 22 : 23 932 : params.addRequiredParam<FileName>("file", "The ExodusII mesh file name"); 24 932 : params.addRequiredParam<Point>("position", "Translation vector for the file mesh [m]"); 25 : 26 466 : params.addClassDescription("Loads a mesh from an ExodusII file without adding physics."); 27 : 28 466 : return params; 29 0 : } 30 : 31 234 : FileMeshComponent::FileMeshComponent(const InputParameters & parameters) 32 : : GeometricalComponent(parameters), 33 234 : _file_name(getParam<FileName>("file")), 34 466 : _file_is_readable(MooseUtils::pathExists(_file_name) && 35 232 : MooseUtils::checkFileReadable(_file_name, false, false)), 36 702 : _position(getParam<Point>("position")) 37 : { 38 : // The following is a mooseError instead of logError because the 'add_variable' 39 : // and 'add_aux_variable' tasks must execute before the integrity check, so if 40 : // the file is unreadable, the user would just get an error message about variables 41 : // being added to non-existent blocks. 42 234 : if (!_file_is_readable) 43 2 : mooseError("The file '", 44 : _file_name, 45 : "' could not be opened. Check that the file exists and that " 46 : "you have permission to open it."); 47 232 : } 48 : 49 : void 50 35 : FileMeshComponent::setupMesh() 51 : { 52 35 : if (_file_is_readable) 53 : { 54 35 : buildMesh(); 55 : 56 : // apply translation vector to all nodes 57 3701 : for (auto && node_id : _node_ids) 58 : { 59 3666 : Node & node = mesh().nodeRef(node_id); 60 : RealVectorValue p(node(0), node(1), node(2)); 61 3666 : node = p + _position; 62 : } 63 : } 64 35 : } 65 : 66 : std::vector<std::string> 67 232 : FileMeshComponent::buildMesh() 68 : { 69 : std::vector<std::string> subdomain_names; 70 : 71 232 : auto & thm_mesh = mesh(); 72 : 73 232 : libMesh::ExodusII_IO_Helper exio_helper(*this, false, true, false); 74 232 : exio_helper.open(_file_name.c_str(), true); 75 232 : exio_helper.read_and_store_header_info(); 76 : 77 : // maps from Exodus IDs to THMMesh IDs 78 : std::map<int, unsigned int> node_id_map; 79 : std::map<int, unsigned int> elem_id_map; 80 : std::map<int, unsigned int> boundary_id_map; 81 : 82 : // Loop over nodes: 83 : // - Add the nodes into THMMesh 84 : // - Populate node_id_map 85 232 : exio_helper.read_nodes(); 86 232 : exio_helper.read_node_num_map(); 87 71326 : for (int i = 0; i < exio_helper.num_nodes; i++) 88 : { 89 71094 : int exodus_id = exio_helper.node_num_map[i]; 90 : 91 71094 : Point p(exio_helper.x[i], exio_helper.y[i], exio_helper.z[i]); 92 71094 : const Node * node = addNode(p); 93 71094 : node_id_map[exodus_id] = node->id(); 94 : } 95 : 96 : // Loop over blocks: 97 : // - Populate subdomain_names 98 : // - Set the blocks in THMMesh 99 : // - Add the elements into THMMesh 100 232 : exio_helper.read_block_info(); 101 232 : exio_helper.read_elem_num_map(); 102 : int jmax_last_block = 0; 103 480 : for (int i = 0; i < exio_helper.num_elem_blk; i++) 104 : { 105 248 : exio_helper.read_elem_in_block(i); 106 : 107 : // Get subdomain name from file (or ID if no name) and populate subdomain_names 108 248 : std::string subdomain_name = exio_helper.get_block_name(i); 109 248 : if (subdomain_name.empty()) 110 339 : subdomain_name = Moose::stringify(exio_helper.get_block_id(i)); 111 248 : subdomain_names.push_back(subdomain_name); 112 : 113 : // Generate the subdomain name and ID for THMMesh, and set them 114 248 : const std::string component_subdomain_name = genName(_name, subdomain_name); 115 248 : SubdomainID sid = thm_mesh.getNextSubdomainId(); 116 248 : setSubdomainInfo(sid, component_subdomain_name, Moose::COORD_XYZ); 117 : 118 248 : const std::string type_str(exio_helper.get_elem_type()); 119 248 : const auto & conv = exio_helper.get_conversion(type_str); 120 : 121 : // Loop over elements in block 122 248 : int jmax = jmax_last_block + exio_helper.num_elem_this_blk; 123 51088 : for (int j = jmax_last_block; j < jmax; j++) 124 : { 125 : // Loop over nodes on element: 126 : // - Get the node IDs on the element 127 50840 : std::vector<dof_id_type> node_ids(exio_helper.num_nodes_per_elem); 128 446088 : for (int k = 0; k < exio_helper.num_nodes_per_elem; k++) 129 : { 130 395248 : int gi = (j - jmax_last_block) * exio_helper.num_nodes_per_elem + conv.get_node_map(k); 131 395248 : int ex_node_id = exio_helper.node_num_map[exio_helper.connect[gi] - 1]; 132 395248 : node_ids[k] = node_id_map[ex_node_id]; 133 : } 134 : 135 : // Add the element and set its subdomain 136 50840 : Elem * elem = addElement(conv.libmesh_elem_type(), node_ids); 137 50840 : elem->subdomain_id() = sid; 138 : 139 : // Populate elem_id_map 140 50840 : int exodus_id = exio_helper.elem_num_map[j]; 141 50840 : elem_id_map[exodus_id] = elem->id(); 142 50840 : } 143 248 : jmax_last_block += exio_helper.num_elem_this_blk; 144 : } 145 : 146 : // Loop over boundaries: 147 : // - Get the Exodus boundary names and store them 148 : // - Generate the boundary IDs 149 232 : exio_helper.read_sideset_info(); 150 : int offset = 0; 151 : std::unordered_map<BoundaryID, BoundaryName> new_ids_to_names; 152 1406 : for (int i = 0; i < exio_helper.num_side_sets; i++) 153 : { 154 : // Compute new offset 155 1174 : offset += (i > 0 ? exio_helper.num_sides_per_set[i - 1] : 0); 156 1174 : exio_helper.read_sideset(i, offset); 157 : 158 : // Get boundary name from file (or ID if no name) 159 1174 : int ex_sideset_id = exio_helper.get_side_set_id(i); 160 1174 : std::string sideset_name = exio_helper.get_side_set_name(i); 161 1174 : if (sideset_name.empty()) 162 288 : sideset_name = Moose::stringify(ex_sideset_id); 163 : 164 : // Generate the boundary ID for THMMesh and populate boundary_id_map 165 1174 : unsigned int bc_id = thm_mesh.getNextBoundaryId(); 166 1174 : boundary_id_map[ex_sideset_id] = bc_id; 167 2348 : new_ids_to_names.emplace(bc_id, genName(_name, sideset_name)); 168 : } 169 : 170 232 : auto & boundary_info = thm_mesh.getMesh().get_boundary_info(); 171 : 172 : // Loop over the elements on boundaries 173 : // Add the boundary elem/side pairs to the boundary 174 36278 : for (auto e : index_range(exio_helper.elem_list)) 175 : { 176 : // Get the element 177 36046 : int ex_elem_id = exio_helper.elem_num_map[exio_helper.elem_list[e] - 1]; 178 36046 : dof_id_type elem_id = elem_id_map[ex_elem_id]; 179 36046 : Elem * elem = thm_mesh.elemPtr(elem_id); 180 : 181 : // Get the side index 182 36046 : const auto & conv = exio_helper.get_conversion(elem->type()); 183 : // Map the zero-based Exodus side numbering to the libmesh side numbering 184 36046 : unsigned int raw_side_index = exio_helper.side_list[e] - 1; 185 36046 : std::size_t side_index_offset = conv.get_shellface_index_offset(); 186 36046 : unsigned int side_index = static_cast<unsigned int>(raw_side_index - side_index_offset); 187 36046 : int mapped_side = conv.get_side_map(side_index); 188 : 189 : // Get the boundary ID and add the elem/side pair to the boundary 190 36046 : unsigned int bc_id = boundary_id_map[exio_helper.id_list[e]]; 191 36046 : boundary_info.add_side(elem, mapped_side, bc_id); 192 36046 : _boundary_info[new_ids_to_names[bc_id]].push_back( 193 36046 : std::tuple<dof_id_type, unsigned short int>(elem->id(), mapped_side)); 194 : } 195 : 196 : // Generate and set the boundary name 197 1406 : for (const auto & id_and_name : new_ids_to_names) 198 : { 199 1174 : boundary_info.sideset_name(id_and_name.first) = id_and_name.second; 200 1174 : boundary_info.nodeset_name(id_and_name.first) = id_and_name.second; 201 1174 : _boundary_names.push_back(id_and_name.second); 202 : } 203 : 204 : // This appears to be necessary to get the nodesets named correctly, despite 205 : // the fact that it gets called later. 206 232 : boundary_info.build_node_list_from_side_list(); 207 : 208 232 : return subdomain_names; 209 232 : } 210 : 211 : bool 212 225 : FileMeshComponent::hasBoundary(const BoundaryName & boundary_name) const 213 : { 214 225 : checkSetupStatus(MESH_PREPARED); 215 : 216 225 : return std::find(_boundary_names.begin(), _boundary_names.end(), boundary_name) != 217 225 : _boundary_names.end(); 218 : } 219 : 220 : const std::vector<std::tuple<dof_id_type, unsigned short int>> & 221 109 : FileMeshComponent::getBoundaryInfo(const BoundaryName & boundary_name) const 222 : { 223 109 : checkSetupStatus(MESH_PREPARED); 224 : 225 109 : if (_boundary_info.find(boundary_name) != _boundary_info.end()) 226 109 : return _boundary_info.at(boundary_name); 227 : else 228 0 : mooseError(name(), 229 : ": No boundary info exists for the boundary '", 230 : boundary_name, 231 : "' on this component."); 232 : }