MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
tetrahedron.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12// Implementation of class Tetrahedron
13
14#include "mesh_headers.hpp"
15
16namespace mfem
17{
18
19Tetrahedron::Tetrahedron(const int *ind, int attr)
20 : Element(Geometry::TETRAHEDRON)
21{
22 attribute = attr;
23 for (int i = 0; i < 4; i++)
24 {
25 indices[i] = ind[i];
26 }
28 transform = 0;
29}
30
31Tetrahedron::Tetrahedron(int ind1, int ind2, int ind3, int ind4, int attr)
32 : Element(Geometry::TETRAHEDRON)
33{
34 attribute = attr;
35 indices[0] = ind1;
36 indices[1] = ind2;
37 indices[2] = ind3;
38 indices[3] = ind4;
40 transform = 0;
41}
42
43void Tetrahedron::Init(int ind1, int ind2, int ind3, int ind4, int attr,
44 int ref_flag)
45{
46 attribute = attr;
47 indices[0] = ind1;
48 indices[1] = ind2;
49 indices[2] = ind3;
50 indices[3] = ind4;
51 refinement_flag = ref_flag;
52 transform = 0;
53}
54
55void Tetrahedron::ParseRefinementFlag(int refinement_edges[2], int &type,
56 int &flag) const
57{
58 int i, f = refinement_flag;
59
60 MFEM_VERIFY(f != 0, "tetrahedron is not marked");
61
62 for (i = 0; i < 2; i++)
63 {
64 refinement_edges[i] = f & 7;
65 f = f >> 3;
66 }
67 type = f & 7;
68 flag = (f >> 3);
69}
70
71void Tetrahedron::CreateRefinementFlag(int refinement_edges[2], int type,
72 int flag)
73{
74 // Check for correct type
75#ifdef MFEM_DEBUG
76 int e1, e2;
77 e1 = refinement_edges[0];
78 e2 = refinement_edges[1];
79 // if (e1 > e2) e1 = e2, e2 = refinement_edges[0];
80 switch (type)
81 {
83 if (e1 == 2 && e2 == 1) { break; }
84 // if (e1 == 3 && e2 == 4) break;
85 mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #1");
86 break;
88 if (e1 == 3 && e2 == 1) { break; }
89 if (e1 == 2 && e2 == 4) { break; }
90 // if (flag == 0) // flag is assumed to be the generation
91 // if (e2 == 5)
92 // if (e1 >= 1 && e1 <= 5) break; // type is actually O or M
93 // // ==> ok for generation = 0
94 mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #2");
95 break;
97 if (flag > 0) // PF is ok only for generation > 0
98 {
99 if (e1 == 2 && e2 == 1) { break; }
100 // if (e1 == 3 && e2 == 4) break;
101 }
102 mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #3");
103 break;
105 if (flag == 0 && e1 == 5 && e2 == 5)
106 {
107 break;
108 }
109 mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #4");
110 break;
112 if (flag == 0)
113 {
114 if (e1 == 5 && e2 == 1) { break; }
115 if (e1 == 2 && e2 == 5) { break; }
116 }
117 mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #5");
118 break;
119 default:
120 mfem_error("Error in Tetrahedron::CreateRefinementFlag(...) #6");
121 break;
122 }
123#endif
124
125 refinement_flag = flag;
126 refinement_flag <<= 3;
127
128 refinement_flag |= type;
129 refinement_flag <<= 3;
130
131 refinement_flag |= refinement_edges[1];
132 refinement_flag <<= 3;
133
134 refinement_flag |= refinement_edges[0];
135}
136
137void Tetrahedron::GetMarkedFace(const int face, int *fv) const
138{
139 int re[2], type, flag;
140 const int *tv = this->indices;
141 ParseRefinementFlag(re, type, flag);
142 switch (face)
143 {
144 case 0:
145 switch (re[1])
146 {
147 case 1: fv[0] = tv[1]; fv[1] = tv[2]; fv[2] = tv[3]; break;
148 case 4: fv[0] = tv[3]; fv[1] = tv[1]; fv[2] = tv[2]; break;
149 case 5: fv[0] = tv[2]; fv[1] = tv[3]; fv[2] = tv[1]; break;
150 }
151 break;
152 case 1:
153 switch (re[0])
154 {
155 case 2: fv[0] = tv[2]; fv[1] = tv[0]; fv[2] = tv[3]; break;
156 case 3: fv[0] = tv[0]; fv[1] = tv[3]; fv[2] = tv[2]; break;
157 case 5: fv[0] = tv[3]; fv[1] = tv[2]; fv[2] = tv[0]; break;
158 }
159 break;
160 case 2:
161 fv[0] = tv[0]; fv[1] = tv[1]; fv[2] = tv[3];
162 break;
163 case 3:
164 fv[0] = tv[1]; fv[1] = tv[0]; fv[2] = tv[2];
165 break;
166 }
167}
168
170{
171 if (v_to_v.FindId(indices[0], indices[1]) != -1) { return 1; }
172 if (v_to_v.FindId(indices[1], indices[2]) != -1) { return 1; }
173 if (v_to_v.FindId(indices[2], indices[0]) != -1) { return 1; }
174 if (v_to_v.FindId(indices[0], indices[3]) != -1) { return 1; }
175 if (v_to_v.FindId(indices[1], indices[3]) != -1) { return 1; }
176 if (v_to_v.FindId(indices[2], indices[3]) != -1) { return 1; }
177 return 0;
178}
179
180void Tetrahedron::SetVertices(const int *ind)
181{
182 for (int i = 0; i < 4; i++)
183 {
184 indices[i] = ind[i];
185 }
186}
187
188void Tetrahedron::MarkEdge(const DSTable &v_to_v, const int *length)
189{
190 int ind[4], i, j, l, L, type;
191
192 // determine the longest edge
193 L = length[v_to_v(indices[0], indices[1])]; j = 0;
194 if ((l = length[v_to_v(indices[1], indices[2])]) > L) { L = l; j = 1; }
195 if ((l = length[v_to_v(indices[2], indices[0])]) > L) { L = l; j = 2; }
196 if ((l = length[v_to_v(indices[0], indices[3])]) > L) { L = l; j = 3; }
197 if ((l = length[v_to_v(indices[1], indices[3])]) > L) { L = l; j = 4; }
198 if ((l = length[v_to_v(indices[2], indices[3])]) > L) { j = 5; }
199
200 for (i = 0; i < 4; i++)
201 {
202 ind[i] = indices[i];
203 }
204
205 switch (j)
206 {
207 case 1:
208 indices[0] = ind[1]; indices[1] = ind[2];
209 indices[2] = ind[0]; indices[3] = ind[3];
210 break;
211 case 2:
212 indices[0] = ind[2]; indices[1] = ind[0];
213 indices[2] = ind[1]; indices[3] = ind[3];
214 break;
215 case 3:
216 indices[0] = ind[3]; indices[1] = ind[0];
217 indices[2] = ind[2]; indices[3] = ind[1];
218 break;
219 case 4:
220 indices[0] = ind[1]; indices[1] = ind[3];
221 indices[2] = ind[2]; indices[3] = ind[0];
222 break;
223 case 5:
224 indices[0] = ind[2]; indices[1] = ind[3];
225 indices[2] = ind[0]; indices[3] = ind[1];
226 break;
227 }
228
229 // Determine the two longest edges for the other two faces and
230 // store them in ind[0] and ind[1]
231 ind[0] = 2; ind[1] = 1;
232 L = length[v_to_v(indices[0], indices[2])];
233 if ((l = length[v_to_v(indices[0], indices[3])]) > L) { L = l; ind[0] = 3; }
234 if ((l = length[v_to_v(indices[2], indices[3])]) > L) { ind[0] = 5; }
235
236 L = length[v_to_v(indices[1], indices[2])];
237 if ((l = length[v_to_v(indices[1], indices[3])]) > L) { L = l; ind[1] = 4; }
238 if ((l = length[v_to_v(indices[2], indices[3])]) > L) { ind[1] = 5; }
239
240 j = 0;
241 switch (ind[0])
242 {
243 case 2:
244 switch (ind[1])
245 {
246 case 1: type = Tetrahedron::TYPE_PU; break;
247 case 4: type = Tetrahedron::TYPE_A; break;
248 case 5:
249 default: type = Tetrahedron::TYPE_M;
250 }
251 break;
252 case 3:
253 switch (ind[1])
254 {
255 case 1: type = Tetrahedron::TYPE_A; break;
256 case 4: type = Tetrahedron::TYPE_PU;
257 j = 1; ind[0] = 2; ind[1] = 1; break;
258 case 5:
259 default: type = Tetrahedron::TYPE_M;
260 j = 1; ind[0] = 5; ind[1] = 1;
261 }
262 break;
263 case 5:
264 default:
265 switch (ind[1])
266 {
267 case 1: type = Tetrahedron::TYPE_M; break;
268 case 4: type = Tetrahedron::TYPE_M;
269 j = 1; ind[0] = 2; ind[1] = 5; break;
270 case 5:
271 default: type = Tetrahedron::TYPE_O;
272 }
273 }
274
275 if (j)
276 {
277 mfem::Swap(indices[0], indices[1]);
278 mfem::Swap(indices[2], indices[3]);
279 }
280
281 CreateRefinementFlag(ind, type);
282}
283
284// static method
285void Tetrahedron::GetPointMatrix(unsigned transform, DenseMatrix &pm)
286{
287 real_t *a = &pm(0,0), *b = &pm(0,1), *c = &pm(0,2), *d = &pm(0,3);
288
289 // initialize to identity
290 a[0] = 0.0, a[1] = 0.0, a[2] = 0.0;
291 b[0] = 1.0, b[1] = 0.0, b[2] = 0.0;
292 c[0] = 0.0, c[1] = 1.0, c[2] = 0.0;
293 d[0] = 0.0, d[1] = 0.0, d[2] = 1.0;
294
295 int chain[12], n = 0;
296 while (transform)
297 {
298 chain[n++] = (transform & 7) - 1;
299 transform >>= 3;
300 }
301
302 /* The transformations and orientations here match the six cases in
303 Mesh::Bisection for tetrahedra. */
304 while (n)
305 {
306#define ASGN(a, b) (a[0] = b[0], a[1] = b[1], a[2] = b[2])
307#define SWAP(a, b) for (int i = 0; i < 3; i++) { std::swap(a[i], b[i]); }
308#define AVG(a, b, c) for (int i = 0; i < 3; i++) { a[i] = (b[i]+c[i])*0.5; }
309
310 real_t e[3];
311 AVG(e, a, b);
312 switch (chain[--n])
313 {
314 case 0: ASGN(b, c); ASGN(c, d); break;
315 case 1: ASGN(a, c); ASGN(c, d); break;
316 case 2: ASGN(b, a); ASGN(a, d); break;
317 case 3: ASGN(a, b); ASGN(b, d); break;
318 case 4: SWAP(a, c); ASGN(b, d); break;
319 case 5: SWAP(b, c); ASGN(a, d); break;
320 default:
321 MFEM_ABORT("Invalid transform.");
322 }
323 ASGN(d, e);
324 }
325}
326
328{
329 v.SetSize(4);
330 std::copy(indices, indices + 4, v.begin());
331}
332
334{
335 MFEM_ASSERT(v.Size() == 4, "!");
336 std::copy(v.begin(), v.end(), indices);
337}
338
340{
341#ifdef MFEM_USE_MEMALLOC
342 Tetrahedron *tet = m->TetMemory.Alloc();
343#else
344 Tetrahedron *tet = new Tetrahedron;
345#endif
346 tet->SetVertices(indices);
349 return tet;
350}
351
352}
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:697
int Size() const
Return the logical size of the array.
Definition array.hpp:144
T * end()
STL-like end. Returns pointer after the last element of the array.
Definition array.hpp:305
T * begin()
STL-like begin. Returns pointer to the first element of the array.
Definition array.hpp:302
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
Abstract data type element.
Definition element.hpp:29
int attribute
Element's attribute (specifying material property, etc).
Definition element.hpp:33
void SetAttribute(const int attr)
Set element's attribute.
Definition element.hpp:58
int FindId(int p1, int p2) const
Find id of item whose parents are p1, p2... Return -1 if it doesn't exist.
Definition hash.hpp:702
Mesh data type.
Definition mesh.hpp:56
MemAlloc< Tetrahedron, 1024 > TetMemory
Definition mesh.hpp:262
Data type tetrahedron element.
void Init(int ind1, int ind2, int ind3, int ind4, int attr=1, int ref_flag=0)
Initialize the vertex indices and the attribute of a Tetrahedron.
int NeedRefinement(HashTable< Hashed2 > &v_to_v) const override
Return 1 if the element needs refinement in order to get conforming mesh.
void ParseRefinementFlag(int refinement_edges[2], int &type, int &flag) const
int * GetVertices() override
Element * Duplicate(Mesh *m) const override
void SetRefinementFlag(int rf)
void SetVertices(const Array< int > &v) override
Set the indices defining the vertices.
static void GetPointMatrix(unsigned transform, DenseMatrix &pm)
Calculate point matrix corresponding to a chain of transformations.
void MarkEdge(const DSTable &v_to_v, const int *length) override
void GetMarkedFace(const int face, int *fv) const
void CreateRefinementFlag(int refinement_edges[2], int type, int flag=0)
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
void Swap(Array< T > &, Array< T > &)
Definition array.hpp:648
void mfem_error(const char *msg)
Definition error.cpp:154
float real_t
Definition config.hpp:43
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30