11#include <nlohmann/json.hpp>
13#include <unordered_map>
28 if (elem->material_id() < 0)
29 throw std::runtime_error(
30 "Element does not have a material ID assigned. Node ID = " +
31 std::to_string(elem->material_id()));
38 for (
auto node :
nodes)
nodes_.push_back(std::move(node));
44 }
else if (element->dimension() !=
dimension_) {
45 throw std::runtime_error(std::format(
46 "Element has dimension {} but Mesh already contains elements of "
47 "dimension {}. All elements in a Mesh must have the same "
63 auto new_nodes = element->CreateInteriorNodes(
nodes_, gll_quadrature);
69 std::unordered_map<size_t, size_t> old_to_new_id;
70 std::vector<Node> renumbered_nodes(
nodes_.size());
76 size_t new_node_id = 0;
78 for (
auto old_id : element->node_ids()) {
79 if (old_to_new_id.contains(old_id))
continue;
81 node.
id = new_node_id;
82 renumbered_nodes.at(new_node_id) = std::move(node);
83 old_to_new_id.emplace(old_id, new_node_id);
93 std::vector<size_t> new_ids;
94 for (
auto old_id : element->node_ids())
95 new_ids.push_back(old_to_new_id.at(old_id));
96 element->SetNodeIDs(std::move(new_ids));
99 nodes_ = std::move(renumbered_nodes);
103 std::vector<size_t> ids;
104 ids.reserve(
nodes_.size());
105 for (
const auto& node :
nodes_) ids.push_back(node.id);
106 std::sort(ids.begin(), ids.end());
107 for (
auto i = 0; i < ids.size(); i++)
109 throw std::runtime_error(std::format(
110 "Node ID expected to be {} but was instead {}. Previous node ID: {}.",
111 i, ids.at(i), ids.at(i - 1)));
115 std::ifstream file(msh_file);
117 throw std::runtime_error(
118 std::format(
"Could not open gmsh file: {}", msh_file));
125 const std::unordered_map<std::string, std::function<void(std::ifstream&)>>
129 {
"$Entities", [&](std::ifstream& f) {
ReadEntities(f, state); }},
130 {
"$Nodes", [&](std::ifstream& f) {
ReadNodes(f, state); }},
131 {
"$Elements", [&](std::ifstream& f) {
ReadElements(f, state); }},
135 while (std::getline(file, line)) {
136 auto handler = section_handlers.find(line);
137 if (handler != section_handlers.end()) handler->second(file);
146 for (
size_t i = 0; i < n_names; i++) {
150 file >> dim >> tag >> std::quoted(name);
158 size_t n_surfaces = 0;
159 size_t n_volumes = 0;
160 file >> n_points >> n_curves >> n_surfaces >> n_volumes;
162 if (n_surfaces > 0 || n_volumes > 0)
163 throw std::runtime_error(
164 "Mesh contains surface or volume entities. Only 1D gmsh meshes "
165 "(points and curves) are currently supported.");
167 for (
size_t i = 0; i < n_points; i++) {
172 size_t n_physical_tags = 0;
173 file >> tag >> x >> y >> z >> n_physical_tags;
175 std::vector<int> physical_tags(n_physical_tags);
176 for (
auto& physical_tag : physical_tags) file >> physical_tag;
180 for (
size_t i = 0; i < n_curves; i++) {
182 double min_x, min_y, min_z, max_x, max_y, max_z;
183 size_t n_physical_tags = 0;
184 file >> tag >> min_x >> min_y >> min_z >> max_x >> max_y >> max_z >>
187 std::vector<int> physical_tags(n_physical_tags);
188 for (
auto& physical_tag : physical_tags) file >> physical_tag;
191 size_t n_bounding_points = 0;
192 file >> n_bounding_points;
193 int bounding_point_tag = 0;
194 for (
size_t j = 0; j < n_bounding_points; j++) file >> bounding_point_tag;
203 file >> n_blocks >>
n_nodes >> min_tag >> max_tag;
205 for (
size_t block = 0; block < n_blocks; block++) {
209 size_t n_nodes_in_block = 0;
210 file >> entity_dim >> entity_tag >> parametric >> n_nodes_in_block;
212 throw std::runtime_error(
213 "Parametric node coordinates are not currently supported.");
215 std::vector<size_t> node_tags(n_nodes_in_block);
216 for (
auto& node_tag : node_tags) file >> node_tag;
218 for (
size_t i = 0; i < n_nodes_in_block; i++) {
221 file >> node.
x >> node.
y >> node.
z;
231 constexpr int kPointType = 15;
232 constexpr int kTwoNodeLineType = 1;
238 file >> n_blocks >>
n_elements >> min_tag >> max_tag;
240 for (
size_t block = 0; block < n_blocks; block++) {
243 int element_type = 0;
244 size_t n_elements_in_block = 0;
245 file >> entity_dim >> entity_tag >> element_type >> n_elements_in_block;
247 if (element_type == kPointType) {
253 size_t element_tag = 0;
255 for (
size_t i = 0; i < n_elements_in_block; i++) {
256 file >> element_tag >> node_tag;
263 if (element_type != kTwoNodeLineType)
264 throw std::runtime_error(std::format(
265 "gmsh element type {} is not yet supported. Only 1D meshes "
266 "(2-node line elements) can currently be read.",
274 size_t element_tag = 0;
275 size_t node_tag_1 = 0;
276 size_t node_tag_2 = 0;
277 for (
size_t i = 0; i < n_elements_in_block; i++) {
278 file >> element_tag >> node_tag_1 >> node_tag_2;
290 const std::vector<int>& curve_physical_tags,
291 const std::unordered_map<int, std::string>& physical_names)
const {
292 for (
int tag : curve_physical_tags)
293 if (physical_names.at(tag).starts_with(
"material:"))
return tag;
295 throw std::runtime_error(
296 "No Physical Group with a name prefixed \"material:\" was found for "
301 const std::vector<int>& curve_physical_tags,
302 const std::unordered_map<int, std::string>& physical_names)
const {
303 for (
int tag : curve_physical_tags)
304 if (physical_names.at(tag).starts_with(
"source:"))
return tag;
305 throw std::runtime_error(
306 "No Physical Group with a name prefixed \"source:\" was found for "
311 const std::vector<int>& point_physical_tags,
312 const std::unordered_map<int, std::string>& physical_names)
const {
313 for (
int tag : point_physical_tags)
314 if (physical_names.at(tag).starts_with(
"bc:"))
return tag;
315 throw std::runtime_error(
316 "No Physical Group with a name prefixed \"bc:\" was found for "
324 int source_id = element->source_id();
325 for (
const auto node_id : element->node_ids()) {
330 for (
auto n = 0; n < n_ordinates; n++)
340 const auto material_name =
343 element->SetMaterialID(material_bank.
GetIDByName(material_name));
344 }
catch (
const std::out_of_range&) {
345 throw std::runtime_error(std::format(
346 "Material \"{}\" passed to the mesh is not defined in the input "
351 const auto source_name =
353 element->SetSourceID(source_bank.
GetIDByName(source_name));
356 for (
auto& node :
nodes_) {
357 if (node.bc_id == 0)
continue;
364 return physical_name.substr(physical_name.find(
':') + 1);
368 for (
const auto& node :
nodes_)
375 throw std::runtime_error(
376 "SetOutwardNormals is only implemented for 1D meshes.");
381 arma::vec3 direction_a = {node_a.
x - node_b.
x, 0.0, 0.0};
392 const size_t n_ordinates) {
393 for (
auto i = 0; i < this->
n_nodes(); i++) {
394 for (
auto n = 0; n < n_ordinates; n++) {
395 nodes_[i].angular_fluxes[n] =
Bank holding the boundary conditions defined in the input file.
const T & GetByID(const int id) const
Get the object by its ID.
int GetIDByName(const std::string &name) const
Get the ID of an object by its name in the JSON input file.
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.
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...
std::unordered_map< int, std::string > physical_names_
Map from Physical Group tag to its name (e.g. "material:foo"), persisted from GmshReadState::physical...
void RenumberNodes()
Renumber nodes in mesh to keep node IDs near each other in a single element.
void ReadPhysicalNames(std::ifstream &file, GmshReadState &state)
Read the $PhysicalNames section into state.physical_names.
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...
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...
Mesh()=default
Construct a new Mesh object.
size_t n_nodes() const
Get the number of nodes in the mesh.
void FindBoundaryNodes()
Populates the boundary_node_ids_ member. Must be called after ResolveIDs!
size_t n_elements() const
Get the number of Elements in the mesh.
std::vector< std::unique_ptr< Element > > elements_
Elements in the mesh.
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 ...
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...
const std::vector< Node > & nodes() const
Get the Nodes in the mesh.
const std::vector< size_t > & boundary_node_ids() const
Get the boundary node IDs.
void AddNode(const Node &node)
Add node to Mesh.
void SetOutwardNormals()
Set the outward-pointing unit normal vector on each boundary node (Node::outward_normal),...
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...
void CreateInteriorElementNodes(const GaussLobattoLegendre &gll_quadrature)
Create interior nodes on elements using Gauss-Lobatto-Legendre quadrature set and add to Mesh.
void UpdateNodeScalarFluxes(const QuadratureBase< Ordinate > &angular_quad_set)
Update the nodes' scalar flux values.
void CheckMaterialIDsOnElements()
Check that the material IDs on the elements are set on construction.
unsigned int dimension_
Spatial dimension of the mesh's elements, set by the first call to AddElement. 0 if no elements have ...
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...
void Prepare(const GaussLobattoLegendre &gll_quadrature)
Prepare the mesh for running a simulation by generating interior nodes using the GLL quadrature set,...
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...
void UpdateNodeAngularFluxes(const SEMProblem &sem_problem, const size_t n_ordinates)
Update the nodes' angular flux values.
void ReadEntities(std::ifstream &file, GmshReadState &state)
Read the $Entities section into state.point_physical_tags and state.curve_physical_tags.
void ReadElements(std::ifstream &file, GmshReadState &state)
Read the $Elements section, adding Segment elements to the mesh for 2-node line elements....
std::vector< Node > nodes_
Nodes in the mesh.
void CheckNodeIDs()
Check that all Node IDs are unique and continuous from 0 to N-1 for N total nodes.
void AddElement(std::unique_ptr< Element > element)
Add element to Mesh.
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...
const std::vector< arma::Col< double > > & solution_vectors() const
Get the solution vectors.
Base class for defining a quadrature set.
T GetAbscissa(const unsigned int index) const
Get the abscissa corresponding to the index.
Wrapper class that owns a ProblemBase of the type corresponding to the given FEFormulation.
ProblemBase * get() const
Get the underlying ProblemBase object.
Bank holding the volumetric sources defined in the input file.
void UpdateScalarFlux(Node &node, const QuadratureBase< Ordinate > angular_quadrature)
Update the scalar flux of a node using the angular quadrature set.
Intermediate state accumulated while reading a gmsh file, shared across the section subroutines below...
std::unordered_map< int, std::vector< int > > curve_physical_tags
Map from curve entity tag to its Physical Group tags.
std::unordered_map< int, std::vector< int > > point_physical_tags
Map from point entity tag to its Physical Group tags.
std::unordered_map< int, std::string > physical_names
Map from Physical Group tag to its name (e.g. "material:foo").
std::unordered_map< size_t, size_t > node_tag_to_id
Map from gmsh node tag to the corresponding Node's ID in nodes_.
A point in the mesh holding its coordinates, boundary info, and flux solution values.
std::vector< double > angular_fluxes
Angular flux values in order of the SN quadrature set.
double x
X-coordinate of the node.
double scalar_flux
Scalar flux on the node.
double z
Z-coordinate of the node.
std::vector< double > source_fluxes
Source flux values in order of the SN quadrature set. These are scratch values: they are overwritten ...
arma::vec3 outward_normal
Outward pointing normal vector. This vector is only relevant if the node is on a boundary.
int bc_id
BC ID to access the boundary condition (BC) bank. ID of 0 is always NONE, meaning the node is interna...
double y
Y-coordinate of the node.
size_t id
Unique identifier for the node.