LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
Loading...
Searching...
No Matches
mesh_factory.cc
1#include "mesh_factory.h"
2
3#include <spdlog/spdlog.h>
4
5#include <iostream>
6
7#include "hybrid2d.h"
8#include "lf/base/base.h"
9
10namespace lf::mesh::hybrid2d {
11
12std::shared_ptr<spdlog::logger>& MeshFactory::Logger() {
13 static auto logger =
14 lf::base::InitLogger("lf::mesh::hybrid2d::MeshFactory::Logger");
15 return logger;
16}
17
19 LF_ASSERT_MSG(coord.rows() == dim_world_,
20 "coord has incompatible number of rows.");
21 // Create default geometry object for a point from location vector
23 std::make_unique<geometry::Point>(coord);
24 nodes_.emplace_back(std::move(point_geo));
25 return nodes_.size() - 1;
26}
27
29 std::unique_ptr<geometry::Geometry>&& geometry) {
30 // Note: For the sake of purely topological computations meshes without
31 // any geometry information may make sense.
32 // Moreover, the location of a point can in principle be deduced from
33 // geometry information supplied for edges or cells.
34 // Hence the next assertion should be removed in the medium run.
35 LF_ASSERT_MSG(geometry != nullptr,
36 "No creation of a point without a valid geometry");
37 LF_ASSERT_MSG(geometry->DimGlobal() == dim_world_,
38 "geometry->DimGlobal() != dim_world_");
39 LF_ASSERT_MSG(geometry->RefEl() == lf::base::RefEl::kPoint(),
40 "Geometry object must belong to a point");
41 nodes_.emplace_back(std::move(geometry));
42 return nodes_.size() - 1;
43}
44
46 base::RefEl ref_el, const std::span<const size_type>& nodes,
47 std::unique_ptr<geometry::Geometry>&& geometry) {
48 LF_ASSERT_MSG(ref_el.Dimension() > 0,
49 "Use AddPoint() to add a node to a mesh.");
50 LF_ASSERT_MSG(ref_el.Dimension() <= 2, "ref_el.Dimension > 2");
51 if (geometry != nullptr) {
52 LF_ASSERT_MSG(geometry->DimGlobal() == dim_world_,
53 "geometry->DimGlobal() != dim_world_");
54 LF_ASSERT_MSG(geometry->RefEl() == ref_el, "ref_el != geometry->RefEl()");
55 }
56
57 // Add an edge
58 if (ref_el == base::RefEl::kSegment()) {
59 std::array<size_type, 2> ns{};
60 unsigned char count = 0;
61 for (const auto& n : nodes) {
62 LF_ASSERT_MSG(n < nodes_.size(),
63 "node " << n
64 << " specified in call to AddEntity must be "
65 "inserted with AddPoint() first.");
66 LF_ASSERT_MSG(
67 count < 2,
68 "ref_el = segment, but nodes contains more than 2 node indices");
69 ns[count] = n;
70 ++count;
71 }
72 LF_ASSERT_MSG(count == 2,
73 "ref_el = segment but size of nodes was " << count);
74 edges_.emplace_back(ns, std::move(geometry));
75 return edges_.size() - 1;
76 } // end insertion of an edge
77
78 // otherwise its an element:
79 // LF_ASSERT_MSG(geometry, "Geometry is required for elements (codim=0)");
80 std::array<size_type, 4> ns{};
81 unsigned char count = 0;
82 for (const auto& n : nodes) {
83 LF_ASSERT_MSG(count < ref_el.NumNodes(),
84 "ref_el = " << ref_el << ", but nodes contains " << count + 1
85 << "node indices");
86 LF_ASSERT_MSG(n < nodes_.size(),
87 " Node " << n << " for " << ref_el.ToString()
88 << " must be inserted with AddNode() first.");
89 ns[count] = n;
90 ++count;
91 }
92 LF_ASSERT_MSG(count == ref_el.NumNodes(),
93 "ref_el.NumNodes() = " << ref_el.NumNodes()
94 << ", but argument nodes contained "
95 << count << " nodes");
96
97 // if we have added a triangle, set the fourth node to -1.
98 if (count == 3) {
99 ns[3] = -1;
100 }
101 elements_.emplace_back(ns, std::move(geometry));
102 return elements_.size() - 1;
103}
104
105std::shared_ptr<mesh::Mesh> MeshFactory::Build() {
106 // DIAGNOSTICS
107 if (Logger()->should_log(spdlog::level::trace)) {
108 std::stringstream ss;
109 PrintLists(ss);
110 SPDLOG_LOGGER_TRACE(Logger(), ss.str());
111 }
112
113 // Obtain points to new mesh object; the actual construction of the
114 // mesh is done by the constructor of that object
115 mesh::Mesh* mesh_ptr =
116 new hybrid2d::Mesh(dim_world_, std::move(nodes_), std::move(edges_),
117 std::move(elements_), check_completeness_);
118
119 // Clear all information supplied to the MeshFactory object
120 nodes_ = hybrid2d::Mesh::NodeCoordList{}; // .clear();
121 edges_ = hybrid2d::Mesh::EdgeList{}; // .clear();
122 elements_ = hybrid2d::Mesh::CellList{}; // clear();
123
124 return std::shared_ptr<mesh::Mesh>(mesh_ptr);
125}
126
127// For diagnostic output
128void MeshFactory::PrintLists(std::ostream& o) const {
129 o << "hybrid2d::MeshFactory: Internal information" << '\n';
130 o << nodes_.size() << " nodes:" << '\n';
131 for (std::size_t j = 0; j < nodes_.size(); j++) {
132 o << "Node " << j << " at ";
133 if (nodes_[j] != nullptr) {
134 o << (nodes_[j]->Global(Eigen::Matrix<double, 0, 1>())).transpose()
135 << '\n';
136 } else {
137 o << "with unknown location!" << '\n';
138 }
139 }
140 o << edges_.size() << " edges " << '\n';
141 for (std::size_t j = 0; j < edges_.size(); j++) {
142 o << "Edge " << j << ": " << edges_[j].first[0] << " <-> "
143 << edges_[j].first[1];
144 if (edges_[j].second) {
145 o << " with geometry";
146 }
147 o << '\n';
148 }
149
150 std::cout << elements_.size() << " cells " << '\n';
151 for (std::size_t j = 0; j < elements_.size(); j++) {
152 o << "Cell " << j << " : ";
153 for (int l = 0; l < 4; l++) {
154 if (elements_[j].first[l] != static_cast<size_type>(-1)) {
155 o << elements_[j].first[l] << " ";
156 }
157 }
158 if (elements_[j].second) {
159 o << " with geometry";
160 } else {
161 o << "[no geometry]";
162 }
163 o << '\n';
164 }
165}
166
167} // namespace lf::mesh::hybrid2d
Represents a reference element with all its properties.
Definition ref_el.h:109
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition ref_el.h:153
constexpr dim_t Dimension() const
Return the dimension of this reference element.
Definition ref_el.h:204
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
Definition ref_el.h:144
constexpr size_type NumNodes() const
The number of nodes of this reference element.
Definition ref_el.h:213
std::string ToString() const
Return a string representation of this Reference element.
Definition ref_el.h:458
Eigen::VectorXd coord_t
Coordinate type of a point.
unsigned int size_type
Abstract interface for objects representing a single mesh.
hybrid2d::Mesh::CellList elements_
static std::shared_ptr< spdlog::logger > & Logger()
logger that is used by the build method to output additional information to the command line.
std::shared_ptr< mesh::Mesh > Build() override
Construct a mesh out of the specified nodes and elements.
size_type AddEntity(base::RefEl ref_el, const std::span< const size_type > &nodes, std::unique_ptr< geometry::Geometry > &&geometry) override
Add an an entity (codim>0) to the mesh.
void PrintLists(std::ostream &o=std::cout) const
output function printing assembled lists of entity information
hybrid2d::Mesh::NodeCoordList nodes_
hybrid2d::Mesh::EdgeList edges_
size_type AddPoint(coord_t coord) override
Add a point to the mesh.
Basis 2D mesh type compliant with abstract mesh interface.
Definition mesh.h:35
std::vector< std::pair< std::array< size_type, 4 >, GeometryPtr > > CellList
Definition mesh.h:74
std::unique_ptr< geometry::Geometry > GeometryPtr
Data types for passing information about mesh intities.
Definition mesh.h:70
std::vector< std::pair< std::array< size_type, 2 >, GeometryPtr > > EdgeList
Definition mesh.h:72
std::vector< GeometryPtr > NodeCoordList
Definition mesh.h:71
std::shared_ptr< spdlog::logger > InitLogger(const std::string &name)
Create a spdlog logger, register it in the spdlog registry and initialize it with LehrFEM++ specific ...
An alternative implementation of a hybrid2d mesh manager that uses Pointers to store sub-entity relat...
Definition hybrid2d.h:11