https://mooseframework.inl.gov
FileMeshComponent.C
Go to the documentation of this file.
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 
20 {
22 
23  params.addRequiredParam<FileName>("file", "The ExodusII mesh file name");
24  params.addRequiredParam<Point>("position", "Translation vector for the file mesh [m]");
25 
26  params.addClassDescription("Loads a mesh from an ExodusII file without adding physics.");
27 
28  return params;
29 }
30 
32  : GeometricalComponent(parameters),
33  _file_name(getParam<FileName>("file")),
34  _file_is_readable(MooseUtils::pathExists(_file_name) &&
35  MooseUtils::checkFileReadable(_file_name, false, false)),
36  _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  if (!_file_is_readable)
43  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 }
48 
49 void
51 {
53  {
54  buildMesh();
55 
56  // apply translation vector to all nodes
57  for (auto && node_id : _node_ids)
58  {
59  Node & node = mesh().nodeRef(node_id);
60  RealVectorValue p(node(0), node(1), node(2));
61  node = p + _position;
62  }
63  }
64 }
65 
66 std::vector<std::string>
68 {
69  std::vector<std::string> subdomain_names;
70 
71  auto & thm_mesh = mesh();
72 
73  libMesh::ExodusII_IO_Helper exio_helper(*this, false, true, false);
74  exio_helper.open(_file_name.c_str(), true);
75  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  exio_helper.read_nodes();
86  exio_helper.read_node_num_map();
87  for (int i = 0; i < exio_helper.num_nodes; i++)
88  {
89  int exodus_id = exio_helper.node_num_map[i];
90 
91  Point p(exio_helper.x[i], exio_helper.y[i], exio_helper.z[i]);
92  const Node * node = addNode(p);
93  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  exio_helper.read_block_info();
101  exio_helper.read_elem_num_map();
102  int jmax_last_block = 0;
103  for (int i = 0; i < exio_helper.num_elem_blk; i++)
104  {
105  exio_helper.read_elem_in_block(i);
106 
107  // Get subdomain name from file (or ID if no name) and populate subdomain_names
108  std::string subdomain_name = exio_helper.get_block_name(i);
109  if (subdomain_name.empty())
110  subdomain_name = Moose::stringify(exio_helper.get_block_id(i));
111  subdomain_names.push_back(subdomain_name);
112 
113  // Generate the subdomain name and ID for THMMesh, and set them
114  const std::string component_subdomain_name = genName(_name, subdomain_name);
115  SubdomainID sid = thm_mesh.getNextSubdomainId();
116  setSubdomainInfo(sid, component_subdomain_name, Moose::COORD_XYZ);
117 
118  const std::string type_str(exio_helper.get_elem_type());
119  const auto & conv = exio_helper.get_conversion(type_str);
120 
121  // Loop over elements in block
122  int jmax = jmax_last_block + exio_helper.num_elem_this_blk;
123  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  std::vector<dof_id_type> node_ids(exio_helper.num_nodes_per_elem);
128  for (int k = 0; k < exio_helper.num_nodes_per_elem; k++)
129  {
130  int gi = (j - jmax_last_block) * exio_helper.num_nodes_per_elem + conv.get_node_map(k);
131  int ex_node_id = exio_helper.node_num_map[exio_helper.connect[gi] - 1];
132  node_ids[k] = node_id_map[ex_node_id];
133  }
134 
135  // Add the element and set its subdomain
136  Elem * elem = addElement(conv.libmesh_elem_type(), node_ids);
137  elem->subdomain_id() = sid;
138 
139  // Populate elem_id_map
140  int exodus_id = exio_helper.elem_num_map[j];
141  elem_id_map[exodus_id] = elem->id();
142  }
143  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  exio_helper.read_sideset_info();
150  int offset = 0;
151  std::unordered_map<BoundaryID, BoundaryName> new_ids_to_names;
152  for (int i = 0; i < exio_helper.num_side_sets; i++)
153  {
154  // Compute new offset
155  offset += (i > 0 ? exio_helper.num_sides_per_set[i - 1] : 0);
156  exio_helper.read_sideset(i, offset);
157 
158  // Get boundary name from file (or ID if no name)
159  int ex_sideset_id = exio_helper.get_side_set_id(i);
160  std::string sideset_name = exio_helper.get_side_set_name(i);
161  if (sideset_name.empty())
162  sideset_name = Moose::stringify(ex_sideset_id);
163 
164  // Generate the boundary ID for THMMesh and populate boundary_id_map
165  unsigned int bc_id = thm_mesh.getNextBoundaryId();
166  boundary_id_map[ex_sideset_id] = bc_id;
167  new_ids_to_names.emplace(bc_id, genName(_name, sideset_name));
168  }
169 
170  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  for (auto e : index_range(exio_helper.elem_list))
175  {
176  // Get the element
177  int ex_elem_id = exio_helper.elem_num_map[exio_helper.elem_list[e] - 1];
178  dof_id_type elem_id = elem_id_map[ex_elem_id];
179  Elem * elem = thm_mesh.elemPtr(elem_id);
180 
181  // Get the side index
182  const auto & conv = exio_helper.get_conversion(elem->type());
183  // Map the zero-based Exodus side numbering to the libmesh side numbering
184  unsigned int raw_side_index = exio_helper.side_list[e] - 1;
185  std::size_t side_index_offset = conv.get_shellface_index_offset();
186  unsigned int side_index = static_cast<unsigned int>(raw_side_index - side_index_offset);
187  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  unsigned int bc_id = boundary_id_map[exio_helper.id_list[e]];
191  boundary_info.add_side(elem, mapped_side, bc_id);
192  _boundary_info[new_ids_to_names[bc_id]].push_back(
193  std::tuple<dof_id_type, unsigned short int>(elem->id(), mapped_side));
194  }
195 
196  // Generate and set the boundary name
197  for (const auto & id_and_name : new_ids_to_names)
198  {
199  boundary_info.sideset_name(id_and_name.first) = id_and_name.second;
200  boundary_info.nodeset_name(id_and_name.first) = id_and_name.second;
201  _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  boundary_info.build_node_list_from_side_list();
207 
208  return subdomain_names;
209 }
210 
211 bool
212 FileMeshComponent::hasBoundary(const BoundaryName & boundary_name) const
213 {
215 
216  return std::find(_boundary_names.begin(), _boundary_names.end(), boundary_name) !=
217  _boundary_names.end();
218 }
219 
220 const std::vector<std::tuple<dof_id_type, unsigned short int>> &
221 FileMeshComponent::getBoundaryInfo(const BoundaryName & boundary_name) const
222 {
224 
225  if (_boundary_info.find(boundary_name) != _boundary_info.end())
226  return _boundary_info.at(boundary_name);
227  else
228  mooseError(name(),
229  ": No boundary info exists for the boundary '",
230  boundary_name,
231  "' on this component.");
232 }
std::vector< int > id_list
std::vector< int > node_num_map
std::vector< int > num_sides_per_set
const char * get_elem_type() const
std::string genName(const std::string &prefix, unsigned int id, const std::string &suffix="") const
Build a name from a prefix, number and possible suffix.
static InputParameters validParams()
std::vector< Real > x
std::string get_block_name(int index)
std::vector< BoundaryName > _boundary_names
Boundary names for this component.
std::string get_side_set_name(int index)
Elem * addElement(libMesh::ElemType elem_type, const std::vector< dof_id_type > &node_ids)
std::vector< int > side_list
const ExodusII_IO_Helper::Conversion & get_conversion(const ElemType type) const
virtual void setSubdomainInfo(SubdomainID subdomain_id, const std::string &subdomain_name, const Moose::CoordinateSystemType &coord_system=Moose::COORD_XYZ)
Sets the next subdomain ID, name, and coordinate system.
Definition: Component.C:229
Node * addNode(const Point &pt)
Definition: Component.C:213
virtual const Node & nodeRef(const dof_id_type i) const
virtual const std::string & name() const
void addRequiredParam(const std::string &name, const std::string &doc_string)
registerMooseObject("ThermalHydraulicsApp", FileMeshComponent)
void open(const char *filename, bool read_only)
std::vector< Real > z
bool hasBoundary(const BoundaryName &boundary_name) const
Returns true if this component has the supplied boundary.
std::vector< int > elem_list
Loads a mesh from an ExodusII file without adding physics.
const bool _file_is_readable
Is the file readable?
const Point & _position
Translation vector for the file mesh.
std::vector< dof_id_type > _node_ids
Node IDs of this component.
Definition: Component.h:455
const FileName & _file_name
The name of the ExodusII file to load the mesh from.
bool checkFileReadable(const std::string &filename, bool check_line_endings=false, bool throw_on_unreadable=true, bool check_for_git_lfs_pointer=true)
std::vector< int > connect
std::string stringify(const T &t)
const std::string _name
void read_elem_in_block(int block)
THMMesh & mesh()
Non-const reference to THM mesh, which can only be called before the end of mesh setup.
Definition: Component.C:60
FileMeshComponent(const InputParameters &parameters)
Intermediate class for components that have mesh.
void checkSetupStatus(const EComponentSetupStatus &status) const
Throws an error if the supplied setup status of this component has not been reached.
Definition: Component.C:117
std::map< BoundaryName, std::vector< std::tuple< dof_id_type, unsigned short int > > > _boundary_info
Map of boundary name to list of tuples of element and side IDs for that boundary. ...
const std::vector< std::tuple< dof_id_type, unsigned short int > > & getBoundaryInfo(const BoundaryName &boundary_name) const
Gets boundary info associated with the component boundary.
void read_sideset(int id, int offset)
void mooseError(Args &&... args) const
std::vector< int > elem_num_map
void addClassDescription(const std::string &doc_string)
int get_side_set_id(int index)
std::vector< Real > y
virtual void setupMesh() override
Performs mesh setup such as creating mesh or naming mesh sets.
static const std::complex< double > j(0, 1)
Complex number "j" (also known as "i")
static InputParameters validParams()
std::vector< std::string > buildMesh()
Loads the ExodusII file into the global mesh and returns the subdomain names (before prepending compo...
bool pathExists(const std::string &path)
static const std::string k
Definition: NS.h:130
auto index_range(const T &sizable)
uint8_t dof_id_type