libMesh
Loading...
Searching...
No Matches
reference_elem.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18
19
20// Local includes
21#include "libmesh/node.h"
22#include "libmesh/elem.h"
23#include "libmesh/reference_elem.h"
24#include "libmesh/libmesh_singleton.h"
25#include "libmesh/threads.h"
26#include "libmesh/enum_to_string.h"
27#include "libmesh/enum_elem_type.h"
28
29// C++ includes
30#include <map>
31#include <sstream>
32#include <memory> // std::unique_ptr
33
34
35//-----------------------------------------------
36// anonymous namespace for implementation details
37namespace
38{
39using namespace libMesh;
40
42{
43// GCC 5.2.0 warns about overlength strings in the auto-generated
44// reference_elem.data file.
45#pragma GCC diagnostic ignored "-Woverlength-strings"
46#include "reference_elem.data"
47#pragma GCC diagnostic warning "-Woverlength-strings"
48}
49
50typedef Threads::spin_mutex InitMutex;
51
52// Mutex for thread safety.
53InitMutex init_mtx;
54
55// map from ElemType to reference element file system object name
56typedef std::map<ElemType, const char *> FileMapType;
57FileMapType ref_elem_file;
58Elem * ref_elem_map[INVALID_ELEM];
59
60
61
62class SingletonCache : public libMesh::Singleton
63{
64public:
65 virtual ~SingletonCache() = default;
66
67 std::vector<std::unique_ptr<Node>> node_list;
68 std::vector<std::unique_ptr<Elem>> elem_list;
69};
70
71// From [0], regarding the lifetime of the singleton_cache variable:
72//
73// "All variables at namespace level, including the anonymous
74// namespace and function local static variable have static
75// storage duration unless they are declared thread_local."
76//
77// Variables with static storage duration are destroyed at the end of
78// the program execution. From [1],
79//
80// "If it is a pointer to the data which is static ... then like all
81// other dynamically allocated data, it will only be destructed when
82// you delete it. There are two frequent solutions:
83// * use a smart pointer, which has a destructor which deletes it, or
84// * don't delete it; in most cases, there's really no reason to call the
85// destructor, and if you happen to use the instance in the destructors
86// of other static objects, you'll run into an order of destruction
87// problem."
88//
89// I tried making the singleton_cache a std::unique_ptr, but this resulted
90// in a segfault during program shutdown which appeared to come from the
91// single_cache unique_ptr's destructor. I didn't investigate whether the
92// issue was caused by a double deletion or what, but it appears that the
93// first suggestion above may not be valid in general.
94//
95// [0]: https://stackoverflow.com/questions/24342393/how-anonymous-namespaces-avoids-making-global-static-variable
96// [1]: https://stackoverflow.com/questions/6850009/c-deleting-static-data
97SingletonCache * singleton_cache = nullptr;
98
99
100
101void read_ref_elem (const ElemType type_in,
102 std::istream & in)
103{
104 libmesh_assert (singleton_cache != nullptr);
105
106 std::string dummy;
107 unsigned int n_elem, n_nodes, elem_type_read, nn;
108 double x, y, z;
109
110 in >> dummy;
111 in >> n_elem; std::getline (in, dummy); libmesh_assert_equal_to (n_elem, 1);
112 in >> n_nodes; std::getline (in, dummy);
113 in >> dummy; std::getline (in, dummy);
114 in >> dummy; std::getline (in, dummy);
115 in >> dummy; std::getline (in, dummy);
116 in >> dummy; std::getline (in, dummy);
117 in >> n_elem; std::getline (in, dummy); libmesh_assert_equal_to (n_elem, 1);
118
119 in >> elem_type_read;
120
121 libmesh_assert_less (elem_type_read, INVALID_ELEM);
122 libmesh_assert_equal_to (elem_type_read, static_cast<unsigned int>(type_in));
123 libmesh_assert_equal_to (n_nodes, Elem::type_to_n_nodes_map[elem_type_read]);
124
125 // Construct elem of appropriate type, store in the elem_list
126 auto & uelem = singleton_cache->elem_list.emplace_back(Elem::build(type_in));
127
128 // We are expecting an identity map, so assert it!
129 for (unsigned int n=0; n<n_nodes; n++)
130 {
131 in >> nn;
132 libmesh_assert_equal_to (n,nn);
133 }
134
135 for (unsigned int n=0; n<n_nodes; n++)
136 {
137 in >> x >> y >> z;
138
139 auto & new_node =
140 singleton_cache->node_list.emplace_back(Node::build(x,y,z,n));
141
142 uelem->set_node(n, new_node.get());
143 }
144
145 // it is entirely possible we ran out of file or encountered
146 // another error. If so, throw an error.
147 libmesh_error_msg_if(!in, "ERROR while creating element singleton!");
148
149 // Also store a pointer to the newly created Elem in the ref_elem_map array.
150 ref_elem_map[type_in] = uelem.get();
151}
152
153
154
155void init_ref_elem_table()
156{
157 // outside mutex - if this pointer is set, we can trust it.
158 if (singleton_cache != nullptr)
159 return;
160
161 // playing with fire here - lock before touching shared
162 // data structures
163 InitMutex::scoped_lock lock(init_mtx);
164
165 // inside mutex - pointer may have changed while waiting
166 // for the lock to acquire, check it again.
167 if (singleton_cache != nullptr)
168 return;
169
170 // OK, if we get here we have the lock and we are not
171 // initialized. populate singleton. Note that we do not
172 // use a smart pointer to manage the singleton_cache variable
173 // since variables with static storage duration are destroyed
174 // automatically at the end of program execution.
175 singleton_cache = new SingletonCache;
176
177 // initialize the reference file table
178 {
179 ref_elem_file.clear();
180
181 // 0D elements
182 ref_elem_file[NODEELEM] = ElemDataStrings::one_nodeelem;
183
184 // 1D elements
185 ref_elem_file[EDGE2] = ElemDataStrings::one_edge;
186 ref_elem_file[EDGE3] = ElemDataStrings::one_edge3;
187 ref_elem_file[EDGE4] = ElemDataStrings::one_edge4;
188
189 // 2D elements
190 ref_elem_file[TRI3] = ElemDataStrings::one_tri;
191 ref_elem_file[TRI6] = ElemDataStrings::one_tri6;
192 ref_elem_file[TRI7] = ElemDataStrings::one_tri7;
193
194 ref_elem_file[QUAD4] = ElemDataStrings::one_quad;
195 ref_elem_file[QUAD8] = ElemDataStrings::one_quad8;
196 ref_elem_file[QUAD9] = ElemDataStrings::one_quad9;
197
198 // 3D elements
199 ref_elem_file[HEX8] = ElemDataStrings::one_hex;
200 ref_elem_file[HEX20] = ElemDataStrings::one_hex20;
201 ref_elem_file[HEX27] = ElemDataStrings::one_hex27;
202
203 ref_elem_file[TET4] = ElemDataStrings::one_tet;
204 ref_elem_file[TET10] = ElemDataStrings::one_tet10;
205 ref_elem_file[TET14] = ElemDataStrings::one_tet14;
206
207 ref_elem_file[PRISM6] = ElemDataStrings::one_prism;
208 ref_elem_file[PRISM15] = ElemDataStrings::one_prism15;
209 ref_elem_file[PRISM18] = ElemDataStrings::one_prism18;
210 ref_elem_file[PRISM20] = ElemDataStrings::one_prism20;
211 ref_elem_file[PRISM21] = ElemDataStrings::one_prism21;
212
213 ref_elem_file[PYRAMID5] = ElemDataStrings::one_pyramid;
214 ref_elem_file[PYRAMID13] = ElemDataStrings::one_pyramid13;
215 ref_elem_file[PYRAMID14] = ElemDataStrings::one_pyramid14;
216 ref_elem_file[PYRAMID18] = ElemDataStrings::one_pyramid18;
217
218 // No entry here for C0POLYGON or C0POLYHEDRON - the reference
219 // element there depends on the number of nodes and can't be
220 // precomputed.
221 }
222
223 // Read'em
224 for (const auto & [elem_type, filename] : ref_elem_file)
225 {
226 std::istringstream stream(filename);
227 read_ref_elem(elem_type, stream);
228 }
229}
230
231
232// no reason to do this at startup -
233// data structures will get initialized *if*
234// ReferenceElem::get() is ever called.
235// // Class to setup singleton data
236// class ReferenceElemSetup : public Singleton::Setup
237// {
238// void setup ()
239// {
240// init_ref_elem_table();
241// }
242// } reference_elem_setup;
243
244} // anonymous namespace
245
246
247
248//----------------------------------------------------------------------------
249// external API Implementation
250namespace libMesh
251{
252namespace ReferenceElem
253{
254const Elem & get (const ElemType type_in)
255{
256 ElemType base_type = type_in;
257
258 // For shell elements, use non shell type as the base type
259 if (type_in == TRISHELL3)
260 base_type = TRI3;
261
262 if (type_in == QUADSHELL4)
263 base_type = QUAD4;
264
265 if (type_in == QUADSHELL8)
266 base_type = QUAD8;
267
268 if (type_in == QUADSHELL9)
269 base_type = QUAD9;
270
271 init_ref_elem_table();
272
273 // Throw an error if the user asked for an ElemType that we don't
274 // have a reference element for.
275 libmesh_error_msg_if(ref_elem_map[base_type] == nullptr || type_in == INVALID_ELEM,
276 "No reference elem data available for ElemType " << type_in
277 << " = " << Utility::enum_to_string(type_in) << ".");
278
279 return *ref_elem_map[base_type];
280}
281} // namespace ReferenceElem
282} // namespace libMesh
This is the base class from which all geometric element types are derived.
Definition elem.h:96
static const unsigned int type_to_n_nodes_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the number of nodes in the element...
Definition elem.h:643
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
static std::unique_ptr< Node > build(const Node &n)
Definition node.h:315
Base class for all library singleton objects.
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
const Elem & get(const ElemType type_in)
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
ElemType
Defines an enum for geometric element types.
libmesh_assert(ctx)
const dof_id_type n_nodes
Definition tecplot_io.C:67