hummingbird
Solving the self-adjoint angular flux transport equation using spectral elements on Cartesian geometry
Loading...
Searching...
No Matches
mesh.h
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2// Copyright (c) 2026, Liam Pohlmann
3
4#ifndef HUMMINGBIRD_MESH_MESH_H_
5#define HUMMINGBIRD_MESH_MESH_H_
6
7#include <fstream>
8#include <string>
9#include <unordered_map>
10#include <vector>
11
12#include "banks/bc_bank.h"
13#include "banks/material_bank.h"
14#include "banks/source_bank.h"
15#include "mesh/element.h"
16#include "mesh/node.h"
18
19namespace hummingbird {
20
21class SEMProblem;
22
23/**
24 * @brief Class defing a mesh
25 *
26 */
27class Mesh {
28 public:
29 /**
30 * @brief Construct a new Mesh object
31 *
32 */
33 Mesh() = default;
34
35 /**
36 * @brief Construct a new Mesh object from a gmsh .msh file
37 *
38 * @param msh_file gmsh .msh file
39 */
40 Mesh(const std::string& msh_file);
41
42 /**
43 * @brief Add node to Mesh
44 *
45 * @param node Node
46 */
47 void AddNode(const Node& node);
48
49 /**
50 * @brief Add nodes in a vector to Mesh
51 *
52 * @param nodes Nodes
53 */
54 void AddNodes(const std::vector<Node>& nodes);
55
56 /**
57 * @brief Add element to Mesh
58 *
59 * @param element Element
60 */
61 void AddElement(std::unique_ptr<Element> element);
62
63 /**
64 * @brief Create interior nodes on elements using Gauss-Lobatto-Legendre
65 * quadrature set and add to Mesh
66 *
67 * @param gll_quadrature Gauss-Lobatto-Legendre quadrature set
68 */
69 void CreateInteriorElementNodes(const GaussLobattoLegendre& gll_quadrature);
70
71 /**
72 * @brief Get the Nodes in the mesh
73 *
74 * @return const std::vector<Node>&
75 */
76 const std::vector<Node>& nodes() const { return nodes_; }
77
78 /**
79 * @brief Get the elements in the mesh
80 *
81 * @return const std::vector<std::unique_ptr<Element>>&
82 */
83 const std::vector<std::unique_ptr<Element>>& elements() const {
84 return elements_;
85 }
86
87 /**
88 * @brief Get Node by ID
89 *
90 * @param id NodeID
91 * @return const Node&
92 */
93 const Node& GetNode(const size_t id) const { return nodes_.at(id); }
94
95 /**
96 * @brief Get the number of Elements in the mesh
97 *
98 * @return size_t
99 */
100 size_t n_elements() const { return elements_.size(); }
101
102 /**
103 * @brief Get the number of nodes in the mesh
104 *
105 * @return size_t
106 */
107 size_t n_nodes() const { return nodes_.size(); }
108
109 /**
110 * @brief Get the spatial dimension of the mesh, derived from the elements
111 * it contains (e.g. 1 for a mesh of Segments). 0 if no elements have been
112 * added yet.
113 *
114 * @return unsigned int
115 */
116 unsigned int dimension() const { return dimension_; }
117
118 /**
119 * @brief Get the boundary node IDs
120 *
121 * @return const std::vector<size_t>&
122 */
123 const std::vector<size_t>& boundary_node_ids() const {
124 return boundary_node_ids_;
125 }
126
127 /**
128 * @brief Get an Element by index
129 *
130 * @param index Index of the element
131 * @return const Element&
132 */
133 const Element& GetElement(const size_t index) const {
134 return *elements_.at(index);
135 }
136
137 /**
138 * @brief Initialize node solution vectors to the correct lengths. Scalar and
139 * angular fluxes are set to 0 and source fluxes are set to the element's
140 * external source
141 *
142 * @param n_ordinates Number of ordinates
143 * @param angular_quad_set Angular quadrature set
144 * @param source_bank Source bank
145 */
146 void InitializeNodeSolutions(const size_t n_ordinates,
147 const QuadratureBase<Ordinate>& angular_quad_set,
148 const SourceBank& source_bank);
149
150 /**
151 * @brief Prepare the mesh for running a simulation by generating interior
152 * nodes using the GLL quadrature set, renumbering nodes, then checking these
153 * nodes.
154 *
155 * @param gll_quadrature GaussLegendreLobatto quadrature set
156 */
157 void Prepare(const GaussLobattoLegendre& gll_quadrature);
158
159 /**
160 * @brief Resolve the raw gmsh Physical Group tags currently stored in
161 * material_id()/source_id()/bc_id (set from the .msh file alone, with no
162 * bank access) into the real IDs assigned by the given banks, by looking
163 * up the name each tag's Physical Group carries (e.g. "mms_material" from
164 * "material:mms_material") via BankBase::GetIDByName. Nodes with
165 * bc_id == 0 (never tagged by a point element) are left alone.
166 *
167 * @throw std::runtime_error if a material name from the mesh has no match
168 * in material_bank
169 *
170 * @param material_bank Material bank
171 * @param source_bank Source bank
172 * @param bc_bank BC bank
173 */
174 void ResolveIDs(const MaterialBank& material_bank,
175 const SourceBank& source_bank, const BCBank& bc_bank);
176
177 /**
178 * @brief Populates the boundary_node_ids_ member. Must be called after
179 * ResolveIDs!
180 *
181 */
182 void FindBoundaryNodes();
183
184 /**
185 * @brief Set the outward-pointing unit normal vector on each boundary
186 * node (Node::outward_normal), normalized via arma::normalise. Must be
187 * called after FindBoundaryNodes (needs boundary_node_ids_ populated) and
188 * after Prepare (needs final, renumbered node ids).
189 *
190 * @throw std::runtime_error if the mesh is not 1D (not yet implemented for
191 * other dimensions)
192 */
193 void SetOutwardNormals();
194
195 /**
196 * @brief Update the nodes' scalar flux values
197 *
198 * @param angular_quad_set Angular quadrature set
199 */
200 void UpdateNodeScalarFluxes(const QuadratureBase<Ordinate>& angular_quad_set);
201
202 /**
203 * @brief Update the nodes' angular flux values
204 *
205 * @param sem_problem SEMProblem object containing updated flux values
206 * @param n_ordinates Number of ordinates
207 */
208 void UpdateNodeAngularFluxes(const SEMProblem& sem_problem,
209 const size_t n_ordinates);
210
211 /**
212 * @brief Set the Node's source flux values
213 *
214 * @param node_id Node ID
215 * @param source_fluxes Source fluxes
216 */
217 void SetNodeSourceFluxes(const size_t node_id,
218 const std::vector<double>& source_fluxes) {
219 nodes_.at(node_id).source_fluxes = source_fluxes;
220 }
221
222 private:
223 /// @brief Nodes in the mesh
224 std::vector<Node> nodes_;
225
226 /// @brief Nodes in the mesh that exist on the mesh boundaries (that is, they
227 /// have a boundary condition assigned)
228 std::vector<size_t> boundary_node_ids_;
229
230 /// @brief Elements in the mesh
231 std::vector<std::unique_ptr<Element>> elements_;
232
233 /// @brief Spatial dimension of the mesh's elements, set by the first call
234 /// to AddElement. 0 if no elements have been added yet.
235 unsigned int dimension_ = 0;
236
237 /// @brief Map from Physical Group tag to its name (e.g. "material:foo"),
238 /// persisted from GmshReadState::physical_names for use by ResolveIDs
239 /// after reading is done.
240 std::unordered_map<int, std::string> physical_names_;
241
242 /**
243 * @brief Renumber nodes in mesh to keep node IDs near each other in a single
244 * element
245 *
246 */
247 void RenumberNodes();
248
249 /**
250 * @brief Check that all Node IDs are unique and continuous from 0 to N-1 for
251 * N total nodes
252 *
253 * @throw std::runtime_error Prints expected ID, found ID, and previous ID.
254 *
255 */
256 void CheckNodeIDs();
257
258 /**
259 * @brief Intermediate state accumulated while reading a gmsh file, shared
260 * across the section subroutines below.
261 *
262 */
264 /// @brief Map from Physical Group tag to its name (e.g. "material:foo")
265 std::unordered_map<int, std::string> physical_names;
266
267 /// @brief Map from point entity tag to its Physical Group tags
268 std::unordered_map<int, std::vector<int>> point_physical_tags;
269
270 /// @brief Map from curve entity tag to its Physical Group tags
271 std::unordered_map<int, std::vector<int>> curve_physical_tags;
272
273 /// @brief Map from gmsh node tag to the corresponding Node's ID in
274 /// nodes_
275 std::unordered_map<size_t, size_t> node_tag_to_id;
276 };
277
278 /**
279 * @brief Construct a Mesh from a gmsh ASCII (format 4.1) .msh file. Reading
280 * routes to a section-specific subroutine using an unordered_map keyed by
281 * the gmsh section header (e.g. "$Nodes"). Only the sections needed to
282 * build 1D meshes (Segment elements, from 2-node line elements and Physical
283 * Point/Curve groups) are currently handled; support for 2D quad elements
284 * can be added later by extending ReadElements without needing to
285 * restructure this dispatch.
286 *
287 * @param msh_file Path to the gmsh .msh file
288 */
289 void ReadGMSH(const std::string& msh_file);
290
291 /**
292 * @brief Read the $PhysicalNames section into state.physical_names
293 *
294 * @param file gmsh file stream, positioned just after the section header
295 * @param state Shared gmsh read state
296 */
297 void ReadPhysicalNames(std::ifstream& file, GmshReadState& state);
298
299 /**
300 * @brief Read the $Entities section into state.point_physical_tags and
301 * state.curve_physical_tags
302 *
303 * @throw std::runtime_error if the mesh contains surface or volume
304 * entities, since only 1D (point/curve) meshes are currently supported
305 *
306 * @param file gmsh file stream, positioned just after the section header
307 * @param state Shared gmsh read state
308 */
309 void ReadEntities(std::ifstream& file, GmshReadState& state);
310
311 /**
312 * @brief Read the $Nodes section, adding Node objects to the mesh and
313 * recording the gmsh tag to Node ID mapping in state.node_tag_to_id
314 *
315 * @param file gmsh file stream, positioned just after the section header
316 * @param state Shared gmsh read state
317 */
318 void ReadNodes(std::ifstream& file, GmshReadState& state);
319
320 /**
321 * @brief Read the $Elements section, adding Segment elements to the mesh
322 * for 2-node line elements. Point elements are consumed and used to tag
323 * the boundary/bc_id of the Node they reference, since they mark boundary
324 * entities in gmsh.
325 *
326 * @throw std::runtime_error for any element type other than a point or a
327 * 2-node line, since only 1D meshes are currently supported
328 *
329 * @param file gmsh file stream, positioned just after the section header
330 * @param state Shared gmsh read state
331 */
332 void ReadElements(std::ifstream& file, GmshReadState& state);
333
334 /**
335 * @brief Find the material ID for a curve entity, defined as the tag of
336 * the Physical Group on that curve whose name is prefixed with
337 * "material:" (see cases/README.md)
338 *
339 * @throw std::runtime_error if no such Physical Group is found
340 *
341 * @param curve_physical_tags Physical Group tags assigned to the curve
342 * @param physical_names Map from Physical Group tag to name
343 * @return int
344 */
345 int GetMaterialID(
346 const std::vector<int>& curve_physical_tags,
347 const std::unordered_map<int, std::string>& physical_names) const;
348
349 /**
350 * @brief Find the source ID for a curve entity, defined as the tag of the
351 * Physical Group on the curve whose name is prefixed with "source:" (see
352 * cases/README.md)
353 *
354 * @throw std::runtime_error if no such Physical Group is found
355 *
356 * @param curve_physical_tags Physical Group tags assigned to the curve
357 * @param physical_names Map from Physical Group tag to name
358 * @return int
359 */
360 int GetSourceID(
361 const std::vector<int>& curve_physical_tags,
362 const std::unordered_map<int, std::string>& physical_names) const;
363
364 /**
365 * @brief Find the BC ID for a point entity, defined as the tag of the
366 * Physical Group on that point whose name is prefixed with "bc:" (see
367 * cases/README.md)
368 *
369 * @throw std::runtime_error if no such Physical Group is found
370 *
371 * @param point_physical_tags Physical Group tags assigned to the point
372 * @param physical_names Map from Physical Group tag to name
373 * @return int
374 */
375 int GetBCID(const std::vector<int>& point_physical_tags,
376 const std::unordered_map<int, std::string>& physical_names) const;
377
378 /**
379 * @brief Extract the name after the ":" in a Physical Group name (e.g.
380 * "mms_material" from "material:mms_material")
381 *
382 * @param physical_name Physical Group name
383 * @return std::string
384 */
385 std::string ExtractName(const std::string& physical_name) const;
386
387 /**
388 * @brief Check that the material IDs on the elements are set on construction
389 *
390 */
392};
393} // namespace hummingbird
394
395#endif // HUMMINGBIRD_MESH_MESH_H_
Bank holding the boundary conditions defined in the input file.
Definition bc_bank.h:21
Defines a subset of the domain (an "element").
Definition element.h:25
Class defining a 1D Gauss-Legendre-Lobatto quadrature set on [-1,1]. The quadrature set approximates ...
Bank holding the materials defined in the input file.
void AddNodes(const std::vector< Node > &nodes)
Add nodes in a vector to Mesh.
Definition mesh.cc:37
const Node & GetNode(const size_t id) const
Get Node by ID.
Definition mesh.h:93
void ResolveIDs(const MaterialBank &material_bank, const SourceBank &source_bank, const BCBank &bc_bank)
Resolve the raw gmsh Physical Group tags currently stored in material_id()/source_id()/bc_id (set fro...
Definition mesh.cc:337
std::unordered_map< int, std::string > physical_names_
Map from Physical Group tag to its name (e.g. "material:foo"), persisted from GmshReadState::physical...
Definition mesh.h:240
void RenumberNodes()
Renumber nodes in mesh to keep node IDs near each other in a single element.
Definition mesh.cc:68
void ReadPhysicalNames(std::ifstream &file, GmshReadState &state)
Read the $PhysicalNames section into state.physical_names.
Definition mesh.cc:143
void ReadGMSH(const std::string &msh_file)
Construct a Mesh from a gmsh ASCII (format 4.1) .msh file. Reading routes to a section-specific subro...
Definition mesh.cc:114
std::string ExtractName(const std::string &physical_name) const
Extract the name after the ":" in a Physical Group name (e.g. "mms_material" from "material:mms_mater...
Definition mesh.cc:363
Mesh()=default
Construct a new Mesh object.
size_t n_nodes() const
Get the number of nodes in the mesh.
Definition mesh.h:107
void FindBoundaryNodes()
Populates the boundary_node_ids_ member. Must be called after ResolveIDs!
Definition mesh.cc:367
size_t n_elements() const
Get the number of Elements in the mesh.
Definition mesh.h:100
std::vector< std::unique_ptr< Element > > elements_
Elements in the mesh.
Definition mesh.h:231
int GetBCID(const std::vector< int > &point_physical_tags, const std::unordered_map< int, std::string > &physical_names) const
Find the BC ID for a point entity, defined as the tag of the Physical Group on that point whose name ...
Definition mesh.cc:310
void ReadNodes(std::ifstream &file, GmshReadState &state)
Read the $Nodes section, adding Node objects to the mesh and recording the gmsh tag to Node ID mappin...
Definition mesh.cc:198
const std::vector< Node > & nodes() const
Get the Nodes in the mesh.
Definition mesh.h:76
const std::vector< size_t > & boundary_node_ids() const
Get the boundary node IDs.
Definition mesh.h:123
void SetNodeSourceFluxes(const size_t node_id, const std::vector< double > &source_fluxes)
Set the Node's source flux values.
Definition mesh.h:217
void AddNode(const Node &node)
Add node to Mesh.
Definition mesh.cc:35
void SetOutwardNormals()
Set the outward-pointing unit normal vector on each boundary node (Node::outward_normal),...
Definition mesh.cc:373
void InitializeNodeSolutions(const size_t n_ordinates, const QuadratureBase< Ordinate > &angular_quad_set, const SourceBank &source_bank)
Initialize node solution vectors to the correct lengths. Scalar and angular fluxes are set to 0 and s...
Definition mesh.cc:320
void CreateInteriorElementNodes(const GaussLobattoLegendre &gll_quadrature)
Create interior nodes on elements using Gauss-Lobatto-Legendre quadrature set and add to Mesh.
Definition mesh.cc:60
void UpdateNodeScalarFluxes(const QuadratureBase< Ordinate > &angular_quad_set)
Update the nodes' scalar flux values.
Definition mesh.cc:386
void CheckMaterialIDsOnElements()
Check that the material IDs on the elements are set on construction.
Definition mesh.cc:26
unsigned int dimension_
Spatial dimension of the mesh's elements, set by the first call to AddElement. 0 if no elements have ...
Definition mesh.h:235
int GetMaterialID(const std::vector< int > &curve_physical_tags, const std::unordered_map< int, std::string > &physical_names) const
Find the material ID for a curve entity, defined as the tag of the Physical Group on that curve whose...
Definition mesh.cc:289
void Prepare(const GaussLobattoLegendre &gll_quadrature)
Prepare the mesh for running a simulation by generating interior nodes using the GLL quadrature set,...
Definition mesh.cc:54
int GetSourceID(const std::vector< int > &curve_physical_tags, const std::unordered_map< int, std::string > &physical_names) const
Find the source ID for a curve entity, defined as the tag of the Physical Group on the curve whose na...
Definition mesh.cc:300
void UpdateNodeAngularFluxes(const SEMProblem &sem_problem, const size_t n_ordinates)
Update the nodes' angular flux values.
Definition mesh.cc:391
unsigned int dimension() const
Get the spatial dimension of the mesh, derived from the elements it contains (e.g....
Definition mesh.h:116
void ReadEntities(std::ifstream &file, GmshReadState &state)
Read the $Entities section into state.point_physical_tags and state.curve_physical_tags.
Definition mesh.cc:155
const std::vector< std::unique_ptr< Element > > & elements() const
Get the elements in the mesh.
Definition mesh.h:83
const Element & GetElement(const size_t index) const
Get an Element by index.
Definition mesh.h:133
void ReadElements(std::ifstream &file, GmshReadState &state)
Read the $Elements section, adding Segment elements to the mesh for 2-node line elements....
Definition mesh.cc:228
std::vector< Node > nodes_
Nodes in the mesh.
Definition mesh.h:224
void CheckNodeIDs()
Check that all Node IDs are unique and continuous from 0 to N-1 for N total nodes.
Definition mesh.cc:102
void AddElement(std::unique_ptr< Element > element)
Add element to Mesh.
Definition mesh.cc:41
std::vector< size_t > boundary_node_ids_
Nodes in the mesh that exist on the mesh boundaries (that is, they have a boundary condition assigned...
Definition mesh.h:228
Base class for defining a quadrature set.
Wrapper class that owns a ProblemBase of the type corresponding to the given FEFormulation.
Definition sem_problem.h:18
Bank holding the volumetric sources defined in the input file.
Definition source_bank.h:25
Intermediate state accumulated while reading a gmsh file, shared across the section subroutines below...
Definition mesh.h:263
std::unordered_map< int, std::vector< int > > curve_physical_tags
Map from curve entity tag to its Physical Group tags.
Definition mesh.h:271
std::unordered_map< int, std::vector< int > > point_physical_tags
Map from point entity tag to its Physical Group tags.
Definition mesh.h:268
std::unordered_map< int, std::string > physical_names
Map from Physical Group tag to its name (e.g. "material:foo").
Definition mesh.h:265
std::unordered_map< size_t, size_t > node_tag_to_id
Map from gmsh node tag to the corresponding Node's ID in nodes_.
Definition mesh.h:275
A point in the mesh holding its coordinates, boundary info, and flux solution values.
Definition node.h:26