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 464 : FileMeshComponent::validParams() 20 : { 21 464 : InputParameters params = GeometricalComponent::validParams(); 22 : 23 928 : params.addRequiredParam<FileName>("file", "The ExodusII mesh file name"); 24 928 : params.addRequiredParam<Point>("position", "Translation vector for the file mesh [m]"); 25 : 26 464 : params.addClassDescription("Loads a mesh from an ExodusII file without adding physics."); 27 : 28 464 : return params; 29 0 : } 30 : 31 233 : FileMeshComponent::FileMeshComponent(const InputParameters & parameters) 32 : : GeometricalComponent(parameters), 33 233 : _file_name(getParam<FileName>("file")), 34 464 : _file_is_readable(MooseUtils::pathExists(_file_name) && 35 231 : MooseUtils::checkFileReadable(_file_name, false, false)), 36 699 : _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 233 : 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 231 : } 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 231 : FileMeshComponent::buildMesh() 68 : { 69 : std::vector<std::string> subdomain_names; 70 : 71 231 : auto & thm_mesh = mesh(); 72 : 73 231 : libMesh::ExodusII_IO_Helper exio_helper(*this, false, true, false); 74 231 : exio_helper.open(_file_name.c_str(), true); 75 231 : 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 231 : exio_helper.read_nodes(); 86 231 : exio_helper.read_node_num_map(); 87 70665 : for (int i = 0; i < exio_helper.num_nodes; i++) 88 : { 89 70434 : int exodus_id = exio_helper.node_num_map[i]; 90 : 91 70434 : Point p(exio_helper.x[i], exio_helper.y[i], exio_helper.z[i]); 92 70434 : const Node * node = addNode(p); 93 70434 : 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 231 : exio_helper.read_block_info(); 101 231 : exio_helper.read_elem_num_map(); 102 : int jmax_last_block = 0; 103 478 : for (int i = 0; i < exio_helper.num_elem_blk; i++) 104 : { 105 247 : exio_helper.read_elem_in_block(i); 106 : 107 : // Get subdomain name from file (or ID if no name) and populate subdomain_names 108 247 : std::string subdomain_name = exio_helper.get_block_name(i); 109 247 : if (subdomain_name.empty()) 110 336 : subdomain_name = Moose::stringify(exio_helper.get_block_id(i)); 111 247 : subdomain_names.push_back(subdomain_name); 112 : 113 : // Generate the subdomain name and ID for THMMesh, and set them 114 247 : const std::string component_subdomain_name = genName(_name, subdomain_name); 115 247 : SubdomainID sid = thm_mesh.getNextSubdomainId(); 116 247 : setSubdomainInfo(sid, component_subdomain_name, Moose::COORD_XYZ); 117 : 118 247 : const std::string type_str(exio_helper.get_elem_type()); 119 247 : const auto & conv = exio_helper.get_conversion(type_str); 120 : 121 : // Loop over elements in block 122 247 : int jmax = jmax_last_block + exio_helper.num_elem_this_blk; 123 50587 : 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 50340 : std::vector<dof_id_type> node_ids(exio_helper.num_nodes_per_elem); 128 441588 : for (int k = 0; k < exio_helper.num_nodes_per_elem; k++) 129 : { 130 391248 : int gi = (j - jmax_last_block) * exio_helper.num_nodes_per_elem + conv.get_node_map(k); 131 391248 : int ex_node_id = exio_helper.node_num_map[exio_helper.connect[gi] - 1]; 132 391248 : node_ids[k] = node_id_map[ex_node_id]; 133 : } 134 : 135 : // Add the element and set its subdomain 136 50340 : Elem * elem = addElement(conv.libmesh_elem_type(), node_ids); 137 50340 : elem->subdomain_id() = sid; 138 : 139 : // Populate elem_id_map 140 50340 : int exodus_id = exio_helper.elem_num_map[j]; 141 50340 : elem_id_map[exodus_id] = elem->id(); 142 : } 143 247 : 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 231 : exio_helper.read_sideset_info(); 150 : int offset = 0; 151 : std::unordered_map<BoundaryID, BoundaryName> new_ids_to_names; 152 1401 : for (int i = 0; i < exio_helper.num_side_sets; i++) 153 : { 154 : // Compute new offset 155 1170 : offset += (i > 0 ? exio_helper.num_sides_per_set[i - 1] : 0); 156 1170 : exio_helper.read_sideset(i, offset); 157 : 158 : // Get boundary name from file (or ID if no name) 159 1170 : int ex_sideset_id = exio_helper.get_side_set_id(i); 160 1170 : std::string sideset_name = exio_helper.get_side_set_name(i); 161 1170 : if (sideset_name.empty()) 162 284 : sideset_name = Moose::stringify(ex_sideset_id); 163 : 164 : // Generate the boundary ID for THMMesh and populate boundary_id_map 165 1170 : unsigned int bc_id = thm_mesh.getNextBoundaryId(); 166 1170 : boundary_id_map[ex_sideset_id] = bc_id; 167 2340 : new_ids_to_names.emplace(bc_id, genName(_name, sideset_name)); 168 : } 169 : 170 231 : 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 35977 : for (auto e : index_range(exio_helper.elem_list)) 175 : { 176 : // Get the element 177 35746 : int ex_elem_id = exio_helper.elem_num_map[exio_helper.elem_list[e] - 1]; 178 35746 : dof_id_type elem_id = elem_id_map[ex_elem_id]; 179 35746 : Elem * elem = thm_mesh.elemPtr(elem_id); 180 : 181 : // Get the side index 182 35746 : const auto & conv = exio_helper.get_conversion(elem->type()); 183 : // Map the zero-based Exodus side numbering to the libmesh side numbering 184 35746 : unsigned int raw_side_index = exio_helper.side_list[e] - 1; 185 35746 : std::size_t side_index_offset = conv.get_shellface_index_offset(); 186 35746 : unsigned int side_index = static_cast<unsigned int>(raw_side_index - side_index_offset); 187 35746 : 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 35746 : unsigned int bc_id = boundary_id_map[exio_helper.id_list[e]]; 191 35746 : boundary_info.add_side(elem, mapped_side, bc_id); 192 35746 : _boundary_info[new_ids_to_names[bc_id]].push_back( 193 35746 : std::tuple<dof_id_type, unsigned short int>(elem->id(), mapped_side)); 194 : } 195 : 196 : // Generate and set the boundary name 197 1401 : for (const auto & id_and_name : new_ids_to_names) 198 : { 199 1170 : boundary_info.sideset_name(id_and_name.first) = id_and_name.second; 200 1170 : boundary_info.nodeset_name(id_and_name.first) = id_and_name.second; 201 1170 : _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 231 : boundary_info.build_node_list_from_side_list(); 207 : 208 231 : return subdomain_names; 209 231 : } 210 : 211 : bool 212 223 : FileMeshComponent::hasBoundary(const BoundaryName & boundary_name) const 213 : { 214 223 : checkSetupStatus(MESH_PREPARED); 215 : 216 223 : return std::find(_boundary_names.begin(), _boundary_names.end(), boundary_name) != 217 223 : _boundary_names.end(); 218 : } 219 : 220 : const std::vector<std::tuple<dof_id_type, unsigned short int>> & 221 108 : FileMeshComponent::getBoundaryInfo(const BoundaryName & boundary_name) const 222 : { 223 108 : checkSetupStatus(MESH_PREPARED); 224 : 225 108 : if (_boundary_info.find(boundary_name) != _boundary_info.end()) 226 108 : 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 : }