OGS
Mesh.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "Mesh.h"
5
6#include <memory>
7#include <range/v3/algorithm/contains.hpp>
8#include <range/v3/numeric.hpp>
9#include <range/v3/numeric/accumulate.hpp>
10#include <range/v3/range/conversion.hpp>
11#include <range/v3/view/enumerate.hpp>
12#include <range/v3/view/indirect.hpp>
13#include <range/v3/view/map.hpp>
14#include <unordered_map>
15#include <utility>
16
17#include "BaseLib/RunTime.h"
18#include "Elements/Element.h"
19#include "Elements/Hex.h"
20#include "Elements/Prism.h"
21#include "Elements/Pyramid.h"
22#include "Elements/Quad.h"
23#include "Elements/Tet.h"
24#include "Elements/Tri.h"
27
29static std::size_t global_mesh_counter = 0;
30
31namespace MeshLib
32{
33using namespace ranges;
34
35std::size_t Mesh::nextID()
36{
37 return global_mesh_counter++;
38}
39
40std::vector<std::vector<Element const*>> findElementsConnectedToNodes(
41 Mesh const& mesh)
42{
43 std::vector<std::vector<Element const*>> elements_connected_to_nodes;
44 auto const& nodes = mesh.getNodes();
45 elements_connected_to_nodes.resize(nodes.size());
46
47 for (auto const* element : mesh.getElements())
48 {
49 for (auto const node_id : element->nodes() | views::ids)
50 {
51 elements_connected_to_nodes[node_id].push_back(element);
52 }
53 }
54 return elements_connected_to_nodes;
55}
56
57Mesh::Mesh(std::string name,
58 std::vector<Node*>
59 nodes,
60 std::vector<Element*>
61 elements,
62 bool const compute_element_neighbors,
63 Properties const& properties)
64 : _node_distance(std::numeric_limits<double>::max(), 0),
65 _name(std::move(name)),
66 _nodes(std::move(nodes)),
67 _elements(std::move(elements)),
68 _properties(properties),
69 _compute_element_neighbors(compute_element_neighbors)
70{
71 this->resetNodeIDs();
72 this->resetElementIDs();
73 this->setDimension();
74
76
78 {
79 this->setElementNeighbors();
80 }
81}
82
83Mesh::Mesh(const Mesh& mesh)
85 _node_distance(mesh._node_distance.first, mesh._node_distance.second),
86 _name(mesh.getName()),
91{
92 const std::vector<Node*>& nodes(mesh.getNodes());
93 const std::size_t nNodes(nodes.size());
94 for (unsigned i = 0; i < nNodes; ++i)
95 {
96 _nodes[i] = new Node(*nodes[i]);
97 }
98
99 const std::vector<Element*>& elements(mesh.getElements());
100 const std::size_t nElements(elements.size());
101 for (unsigned i = 0; i < nElements; ++i)
102 {
103 _elements[i] = elements[i]->clone();
104 for (auto const& [j, node_id] :
105 elements[i]->nodes() | views::ids | ranges::views::enumerate)
106 {
107 _elements[i]->setNode(static_cast<unsigned>(j), _nodes[node_id]);
108 }
109 }
110
111 if (_mesh_dimension == 0)
112 {
113 this->setDimension();
114 }
115
118 {
119 this->setElementNeighbors();
120 }
121}
122
123Mesh::Mesh(Mesh&& mesh) = default;
124
126{
127 _elements.clear();
128 _nodes.clear();
129}
130
132{
133 const std::size_t nElements(_elements.size());
134 for (std::size_t i = 0; i < nElements; ++i)
135 {
136 delete _elements[i];
137 }
138
139 const std::size_t nNodes(_nodes.size());
140 for (std::size_t i = 0; i < nNodes; ++i)
141 {
142 delete _nodes[i];
143 }
144}
145
147{
148 _elements.push_back(elem);
149}
150
152{
153 const std::size_t nNodes(_nodes.size());
154 for (std::size_t i = 0; i < nNodes; ++i)
155 {
156 _nodes[i]->setID(i);
157 }
158}
159
161{
162 const std::size_t nElements(this->_elements.size());
163 for (unsigned i = 0; i < nElements; ++i)
164 {
165 _elements[i]->setID(i);
166 }
167}
168
170{
171 const std::size_t nElements(_elements.size());
172 for (unsigned i = 0; i < nElements; ++i)
173 {
175 {
176 _mesh_dimension = _elements[i]->getDimension();
177 }
178 }
179}
180
181std::pair<double, double> minMaxEdgeLength(
182 std::vector<Element*> const& elements)
183{
184 auto min_max = [](auto const a, auto const b) -> std::pair<double, double> {
185 return {std::min(a.first, b.first), std::max(a.second, b.second)};
186 };
187
188 using limits = std::numeric_limits<double>;
189 auto const bounds = ranges::accumulate(
190 elements, std::pair{limits::infinity(), -limits::infinity()}, min_max,
191 [](Element const* const e) { return computeSqrEdgeLengthRange(*e); });
192
193 return {std::sqrt(bounds.first), std::sqrt(bounds.second)};
194}
195
197{
198 std::vector<Element const*> neighbors;
199 for (auto element : _elements)
200 {
201 // create vector with all elements connected to current element
202 // (includes lots of doubles!)
203 const std::size_t nNodes(element->getNumberOfBaseNodes());
204 for (unsigned n(0); n < nNodes; ++n)
205 {
206 auto const& conn_elems(
207 _elements_connected_to_nodes[element->getNode(n)->getID()]);
208 neighbors.insert(neighbors.end(), conn_elems.begin(),
209 conn_elems.end());
210 }
211 std::sort(neighbors.begin(), neighbors.end());
212 auto const neighbors_new_end =
213 std::unique(neighbors.begin(), neighbors.end());
214
215 for (auto neighbor = neighbors.begin(); neighbor != neighbors_new_end;
216 ++neighbor)
217 {
218 std::optional<unsigned> const opposite_face_id =
219 element->addNeighbor(const_cast<Element*>(*neighbor));
220 if (opposite_face_id)
221 {
222 const_cast<Element*>(*neighbor)->setNeighbor(element,
223 *opposite_face_id);
224 }
225 }
226 neighbors.clear();
227 }
228}
229
231{
232 return std::count_if(begin(_nodes), end(_nodes),
233 [this](auto const* const node) {
234 return isBaseNode(
235 *node,
236 _elements_connected_to_nodes[node->getID()]);
237 });
238}
239
241{
242 return std::any_of(
243 std::begin(_elements), std::end(_elements),
244 [](Element const* const e)
245 { return e->getNumberOfNodes() != e->getNumberOfBaseNodes(); });
246}
247
248std::vector<MeshLib::Element const*> const& Mesh::getElementsConnectedToNode(
249 std::size_t const node_id) const
250{
251 return _elements_connected_to_nodes[node_id];
252}
253
254std::vector<MeshLib::Element const*> const& Mesh::getElementsConnectedToNode(
255 Node const& node) const
256{
257 return _elements_connected_to_nodes[node.getID()];
258}
259
261{
262 auto const& properties = mesh.getProperties();
263 if (properties.existsPropertyVector<int>("MaterialIDs",
265 {
266 return properties.getPropertyVector<int>(
267 "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
268 }
269 if (properties.hasPropertyVector("MaterialIDs"))
270 {
271 WARN(
272 "The 'MaterialIDs' mesh property exists but is either of wrong "
273 "type (must be int), or it is not defined on element / cell data.");
274 }
275 return nullptr;
276}
277
279{
280 return const_cast<PropertyVector<int>*>(
281 MeshLib::materialIDs(std::as_const(mesh)));
282}
283
285{
286 auto const& properties = mesh.getProperties();
287 return properties.getPropertyVector<std::size_t>(
290}
291
293{
294 auto const& properties = mesh.getProperties();
295 return properties.getPropertyVector<std::size_t>(
298}
299
300std::vector<std::vector<Node*>> calculateNodesConnectedByElements(
301 Mesh const& mesh)
302{
303 auto const elements_connected_to_nodes = findElementsConnectedToNodes(mesh);
304
305 std::vector<std::vector<Node*>> nodes_connected_by_elements;
306 auto const& nodes = mesh.getNodes();
307 nodes_connected_by_elements.resize(nodes.size());
308 for (std::size_t i = 0; i < nodes.size(); ++i)
309 {
310 auto& adjacent_nodes = nodes_connected_by_elements[i];
311 auto const node_id = nodes[i]->getID();
312
313 // Get all elements, to which this node is connected.
314 auto const& connected_elements = elements_connected_to_nodes[node_id];
315
316 // And collect all elements' nodes.
317 for (Element const* const element : connected_elements)
318 {
319 Node* const* const single_elem_nodes = element->getNodes();
320 std::size_t const nnodes = element->getNumberOfNodes();
321 for (std::size_t n = 0; n < nnodes; n++)
322 {
323 adjacent_nodes.push_back(single_elem_nodes[n]);
324 }
325 }
326
327 // Make nodes unique and sorted by their ids.
328 // This relies on the node's id being equivalent to it's address.
329 std::sort(adjacent_nodes.begin(), adjacent_nodes.end(),
331 auto const last =
332 std::unique(adjacent_nodes.begin(), adjacent_nodes.end());
333 adjacent_nodes.erase(last, adjacent_nodes.end());
334 }
335 return nodes_connected_by_elements;
336}
337
338bool isBaseNode(Node const& node,
339 std::vector<Element const*> const& elements_connected_to_node)
340{
341 // Check if node is connected.
342 if (elements_connected_to_node.empty())
343 {
344 return true;
345 }
346
347 // In a mesh a node always belongs to at least one element.
348 auto const e = elements_connected_to_node[0];
349
350 auto const n_base_nodes = e->getNumberOfBaseNodes();
351 auto const local_index = getNodeIDinElement(*e, &node);
352 assert(local_index <= e->getNumberOfNodes());
353 return local_index < n_base_nodes;
354}
355
356Mesh& findMeshByName(std::vector<std::unique_ptr<Mesh>> const& meshes,
357 std::string_view const name)
358{
360 meshes,
361 [&name](auto const& mesh)
362 {
363 assert(mesh != nullptr);
364 return mesh->getName() == name;
365 },
366 [&]() { OGS_FATAL("Required mesh named {:s} not found.", name); });
367}
368
369} // namespace MeshLib
#define OGS_FATAL(...)
Definition Error.h:10
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:34
static std::size_t global_mesh_counter
Mesh counter used to uniquely identify meshes by id.
Definition Mesh.cpp:29
std::size_t getID() const
void setNeighbor(Element *neighbor, unsigned const face_id)
Definition Element.cpp:21
virtual unsigned getNumberOfNodes() const =0
virtual unsigned getNumberOfBaseNodes() const =0
Properties _properties
Definition Mesh.h:158
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:98
bool const _compute_element_neighbors
Definition Mesh.h:163
std::vector< std::vector< Element const * > > _elements_connected_to_nodes
Definition Mesh.h:160
void addElement(Element *elem)
Add an element to the mesh.
Definition Mesh.cpp:146
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:101
unsigned _mesh_dimension
Definition Mesh.h:151
std::size_t computeNumberOfBaseNodes() const
Get the number of base nodes.
Definition Mesh.cpp:230
std::string _name
Definition Mesh.h:155
unsigned getDimension() const
Definition Mesh.h:80
void resetNodeIDs()
Resets the IDs of all mesh-nodes to their position in the node vector.
Definition Mesh.cpp:151
Properties & getProperties()
Definition Mesh.h:127
std::vector< Element * > _elements
Definition Mesh.h:157
void setDimension()
Sets the dimension of the mesh.
Definition Mesh.cpp:169
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:95
void resetElementIDs()
Definition Mesh.cpp:160
void setElementNeighbors()
Definition Mesh.cpp:196
virtual ~Mesh()
Destructor.
Definition Mesh.cpp:131
Mesh(std::string name, std::vector< Node * > nodes, std::vector< Element * > elements, bool const compute_element_neighbors=false, Properties const &properties=Properties())
Definition Mesh.cpp:57
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:92
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition Mesh.cpp:248
std::pair< double, double > _node_distance
Definition Mesh.h:154
void shallowClean()
Definition Mesh.cpp:125
bool hasNonlinearElement() const
Check if the mesh contains any nonlinear element.
Definition Mesh.cpp:240
static std::size_t nextID()
Returns the next unused mesh id from the global mesh counter.
Definition Mesh.cpp:35
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:89
std::vector< Node * > _nodes
Definition Mesh.h:156
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
PropertyVector< T > const * getPropertyVector(std::string_view name) const
ranges::range_reference_t< Range > findElementOrError(Range &range, std::predicate< ranges::range_reference_t< Range > > auto &&predicate, std::invocable auto error_callback)
Definition Algorithm.h:75
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:223
std::vector< std::vector< Element const * > > findElementsConnectedToNodes(Mesh const &mesh)
Definition Mesh.cpp:40
std::vector< std::vector< Node * > > calculateNodesConnectedByElements(Mesh const &mesh)
Definition Mesh.cpp:300
Mesh & findMeshByName(std::vector< std::unique_ptr< Mesh > > const &meshes, std::string_view const name)
Definition Mesh.cpp:356
bool idsComparator(T const a, T const b)
Definition Mesh.h:204
PropertyVector< int > const * materialIDs(Mesh const &mesh)
Definition Mesh.cpp:260
constexpr std::string_view getBulkIDString(MeshItemType mesh_item_type)
PropertyVector< std::size_t > const * bulkElementIDs(Mesh const &mesh)
Definition Mesh.cpp:292
std::pair< double, double > computeSqrEdgeLengthRange(Element const &element)
Compute the minimum and maximum squared edge length for this element.
Definition Element.cpp:163
std::pair< double, double > minMaxEdgeLength(std::vector< Element * > const &elements)
Returns the minimum and maximum edge length for given elements.
Definition Mesh.cpp:181
unsigned getNodeIDinElement(Element const &element, const MeshLib::Node *node)
Returns the position of the given node in the node array of this element.
Definition Element.cpp:213
bool isBaseNode(Node const &node, std::vector< Element const * > const &elements_connected_to_node)
Definition Mesh.cpp:338
PropertyVector< std::size_t > const * bulkNodeIDs(Mesh const &mesh)
Definition Mesh.cpp:284