@@ -33,20 +33,17 @@ int cell_degree(mesh::CellType type, int num_nodes)
33
33
return n - 1 ;
34
34
}
35
35
case mesh::CellType::tetrahedron:
36
- // n * (n + 1) * (n + 2) = 6*A
37
- // return n - 1;
38
- switch (num_nodes)
36
+ {
37
+ int n = 0 ;
38
+ while (n * (n + 1 ) * (n + 2 ) < 6 * num_nodes)
39
+ ++n;
40
+ if (n * (n + 1 ) * (n + 2 ) != 6 * num_nodes)
39
41
{
40
- case 4 :
41
- return 1 ;
42
- case 10 :
43
- return 2 ;
44
- case 20 :
45
- return 3 ;
46
- default :
47
42
throw std::runtime_error (" Unknown tetrahedron layout. Number of nodes: "
48
43
+ std::to_string (num_nodes));
49
44
}
45
+ return n - 1 ;
46
+ }
50
47
case mesh::CellType::quadrilateral:
51
48
{
52
49
const int n = std::sqrt (num_nodes);
@@ -102,10 +99,44 @@ std::uint16_t vec_pop(std::vector<std::uint16_t>& v, int i)
102
99
return value;
103
100
}
104
101
// -----------------------------------------------------------------------------
102
+ std::vector<std::uint16_t >
103
+ vtk_triangle_remainders (std::vector<std::uint16_t > remainders)
104
+ {
105
+ std::vector<std::uint16_t > map (remainders.size ());
106
+ std::size_t j = 0 ;
107
+ int degree;
108
+ while (remainders.size () > 0 )
109
+ {
110
+ if (remainders.size () == 1 )
111
+ {
112
+ map[j++] = vec_pop (remainders, 0 );
113
+ break ;
114
+ }
115
+
116
+ degree = cell_degree (mesh::CellType::triangle, remainders.size ());
117
+
118
+ map[j++] = vec_pop (remainders, 0 );
119
+ map[j++] = vec_pop (remainders, degree - 1 );
120
+ map[j++] = vec_pop (remainders, -1 );
121
+
122
+ for (int i = 0 ; i < degree - 1 ; ++i)
123
+ map[j++] = vec_pop (remainders, 0 );
124
+
125
+ for (int i = 1 , k = degree * (degree - 1 ) / 2 ; i < degree;
126
+ k -= degree - i, ++i)
127
+ map[j++] = vec_pop (remainders, -k);
128
+
129
+ for (int i = 1 , k = 1 ; i < degree; k += i, ++i)
130
+ map[j++] = vec_pop (remainders, -k);
131
+ }
132
+
133
+ return map;
134
+ }
135
+ // -----------------------------------------------------------------------------
105
136
std::vector<std::uint16_t > vtk_triangle (int num_nodes)
106
137
{
107
- // Vertices
108
138
std::vector<std::uint16_t > map (num_nodes);
139
+ // Vertices
109
140
std::iota (map.begin (), map.begin () + 3 , 0 );
110
141
111
142
int j = 3 ;
@@ -123,51 +154,239 @@ std::vector<std::uint16_t> vtk_triangle(int num_nodes)
123
154
// Interior VTK is ordered as a lower order triangle, while FEniCS
124
155
// orders them lexicographically.
125
156
std::vector<std::uint16_t > remainders (num_nodes - j);
126
- std::iota (remainders.begin (), remainders.end (), 0 );
127
- const std::uint16_t base = 3 * degree;
157
+ std::iota (remainders.begin (), remainders.end (), 3 * degree);
158
+
159
+ for (std::uint16_t r : vtk_triangle_remainders (remainders))
160
+ {
161
+ map[j++] = r;
162
+ }
163
+ return map;
164
+ }
165
+ // -----------------------------------------------------------------------------
166
+ std::vector<std::uint16_t >
167
+ vtk_tetrahedron_remainders (std::vector<std::uint16_t > remainders)
168
+ {
169
+ std::vector<std::uint16_t > map (remainders.size ());
170
+ std::size_t j = 0 ;
128
171
129
172
while (remainders.size () > 0 )
130
173
{
131
174
if (remainders.size () == 1 )
132
175
{
133
- map[j++] = base + vec_pop (remainders, 0 );
176
+ map[j++] = vec_pop (remainders, 0 );
134
177
break ;
135
178
}
136
179
137
- degree = cell_degree (mesh::CellType::triangle, remainders.size ());
180
+ const int deg
181
+ = cell_degree (mesh::CellType::tetrahedron, remainders.size ()) + 1 ;
138
182
139
- map[j++] = base + vec_pop (remainders, 0 );
140
- map[j++] = base + vec_pop (remainders, degree - 1 );
141
- map[j++] = base + vec_pop (remainders, -1 );
183
+ map[j++] = vec_pop (remainders, 0 );
184
+ map[j++] = vec_pop (remainders, deg - 2 );
185
+ map[j++] = vec_pop (remainders, deg * (deg + 1 ) / 2 - 3 );
186
+ map[j++] = vec_pop (remainders, -1 );
142
187
143
- for (int i = 0 ; i < degree - 1 ; ++i)
144
- map[j++] = base + vec_pop (remainders, 0 );
188
+ if (deg > 2 )
189
+ {
190
+ for (int i = 0 ; i < deg - 2 ; ++i)
191
+ {
192
+ map[j++] = vec_pop (remainders, 0 );
193
+ }
194
+ int d = deg - 2 ;
195
+ for (int i = 0 ; i < deg - 2 ; ++i)
196
+ {
197
+ map[j++] = vec_pop (remainders, d);
198
+ d += deg - 3 - i;
199
+ }
200
+ d = (deg - 2 ) * (deg - 1 ) / 2 - 1 ;
201
+ for (int i = 0 ; i < deg - 2 ; ++i)
202
+ {
203
+ map[j++] = vec_pop (remainders, d);
204
+ d -= 2 + i;
205
+ }
206
+ d = (deg - 3 ) * (deg - 2 ) / 2 ;
207
+ for (int i = 0 ; i < deg - 2 ; ++i)
208
+ {
209
+ map[j++] = vec_pop (remainders, d);
210
+ d += (deg - i) * (deg - i - 1 ) / 2 - 1 ;
211
+ }
212
+ d = (deg - 3 ) * (deg - 2 ) / 2 + deg - 3 ;
213
+ for (int i = 0 ; i < deg - 2 ; ++i)
214
+ {
215
+ map[j++] = vec_pop (remainders, d);
216
+ d += (deg - 2 - i) * (deg - 1 - i) / 2 + deg - 4 - i;
217
+ }
218
+ d = (deg - 3 ) * (deg - 2 ) / 2 + deg - 3 + (deg - 2 ) * (deg - 1 ) / 2 - 1 ;
219
+ for (int i = 0 ; i < deg - 2 ; ++i)
220
+ {
221
+ map[j++] = vec_pop (remainders, d);
222
+ d += (deg - 3 - i) * (deg - 2 - i) / 2 + deg - i - 5 ;
223
+ }
224
+ }
225
+ if (deg > 3 )
226
+ {
227
+ std::vector<std::uint16_t > dofs ((deg - 3 ) * (deg - 2 ) / 2 );
228
+ int di = 0 ;
229
+ int d = (deg - 3 ) * (deg - 2 ) / 2 ;
230
+ for (int i = 0 ; i < deg - 3 ; ++i)
231
+ {
232
+ for (int ii = 0 ; ii < deg - 3 - i; ++ii)
233
+ dofs[di++] = vec_pop (remainders, d);
234
+ d += (deg - 2 - i) * (deg - 1 - i) / 2 - 1 ;
235
+ }
236
+ for (std::uint16_t r : vtk_triangle_remainders (dofs))
237
+ map[j++] = r;
145
238
146
- for (int i = 1 , k = degree * (degree - 1 ) / 2 ; i < degree;
147
- k -= degree - i, ++i)
148
- map[j++] = base + vec_pop (remainders, -k);
239
+ di = 0 ;
240
+ int start = deg * deg - 4 * deg + 2 ;
241
+ int sub_i_start = deg - 3 ;
242
+ for (int i = 0 ; i < deg - 3 ; ++i)
243
+ {
244
+ d = start;
245
+ int sub_i = sub_i_start;
246
+ for (int ii = 0 ; ii < deg - 3 - i; ++ii)
247
+ {
248
+ dofs[di++] = vec_pop (remainders, d);
249
+ d += sub_i * (sub_i + 1 ) / 2 - 2 - i;
250
+ sub_i -= 1 ;
251
+ }
252
+ start -= 2 + i;
253
+ }
254
+ for (std::uint16_t r : vtk_triangle_remainders (dofs))
255
+ map[j++] = r;
149
256
150
- for (int i = 1 , k = 1 ; i < degree; k += i, ++i)
151
- map[j++] = base + vec_pop (remainders, -k);
152
- }
257
+ di = 0 ;
258
+ start = (deg - 3 ) * (deg - 2 ) / 2 ;
259
+ sub_i_start = deg - 3 ;
260
+ for (int i = 0 ; i < deg - 3 ; ++i)
261
+ {
262
+ d = start;
263
+ int sub_i = sub_i_start;
264
+ for (int ii = 0 ; ii < deg - 3 - i; ++ii)
265
+ {
266
+ dofs[di++] = vec_pop (remainders, d);
267
+ d += sub_i * (sub_i + 1 ) / 2 - 1 - 2 * i;
268
+ sub_i -= 1 ;
269
+ }
270
+ start += deg - 4 - i;
271
+ }
272
+ for (std::uint16_t r : vtk_triangle_remainders (dofs))
273
+ map[j++] = r;
153
274
275
+ di = 0 ;
276
+ int add_start = deg - 4 ;
277
+ for (int i = 0 ; i < deg - 3 ; ++i)
278
+ {
279
+ d = 0 ;
280
+ int add = add_start;
281
+ for (int ii = 0 ; ii < deg - 3 - i; ++ii)
282
+ {
283
+ dofs[di++] = vec_pop (remainders, d);
284
+ d += add;
285
+ add -= 1 ;
286
+ }
287
+ add_start -= 1 ;
288
+ }
289
+ for (std::uint16_t r : vtk_triangle_remainders (dofs))
290
+ map[j++] = r;
291
+ }
292
+ }
154
293
return map;
155
294
}
156
295
// -----------------------------------------------------------------------------
157
296
std::vector<std::uint16_t > vtk_tetrahedron (int num_nodes)
158
297
{
159
- switch (num_nodes)
298
+ const int degree = cell_degree (mesh::CellType::tetrahedron, num_nodes);
299
+
300
+ std::vector<std::uint16_t > map (num_nodes);
301
+ // Vertices
302
+ std::iota (map.begin (), map.begin () + 4 , 0 );
303
+
304
+ if (degree < 2 )
305
+ return map;
306
+
307
+ int base = 4 ;
308
+ int j = 4 ;
309
+ const int edge_dofs = degree - 1 ;
310
+ for (int edge : std::vector<int >({5 , 2 , 4 , 3 , 1 , 0 }))
160
311
{
161
- case 4 :
162
- return {0 , 1 , 2 , 3 };
163
- case 10 :
164
- return {0 , 1 , 2 , 3 , 9 , 6 , 8 , 7 , 5 , 4 };
165
- case 20 :
166
- return {0 , 1 , 2 , 3 , 14 , 15 , 8 , 9 , 13 , 12 ,
167
- 10 , 11 , 6 , 7 , 4 , 5 , 18 , 16 , 17 , 19 };
168
- default :
169
- throw std::runtime_error (" Unknown tetrahedron layout" );
312
+ if (edge == 4 )
313
+ {
314
+ for (int i = 0 ; i < edge_dofs; ++i)
315
+ {
316
+ map[j++] = base + edge_dofs * (edge + 1 ) - 1 - i;
317
+ }
318
+ }
319
+ else
320
+ {
321
+ for (int i = 0 ; i < edge_dofs; ++i)
322
+ {
323
+ map[j++] = base + edge_dofs * edge + i;
324
+ }
325
+ }
170
326
}
327
+ base += 6 * edge_dofs;
328
+
329
+ if (degree < 3 )
330
+ return map;
331
+
332
+ const int n_face_dofs = (degree - 1 ) * (degree - 2 ) / 2 ;
333
+
334
+ for (int face : std::vector<int >({2 , 0 , 1 , 3 }))
335
+ {
336
+ std::vector<std::uint16_t > face_dofs (n_face_dofs);
337
+ std::size_t fj = 0 ;
338
+ if (face == 2 )
339
+ {
340
+ for (int i = 0 ; i < n_face_dofs; ++i)
341
+ {
342
+ face_dofs[fj++] = base + n_face_dofs * face + i;
343
+ }
344
+ }
345
+ else if (face == 0 )
346
+ {
347
+ for (int i = degree - 3 ; i >= 0 ; --i)
348
+ {
349
+ int d = i;
350
+ for (int ii = 0 ; ii <= i; ++ii)
351
+ {
352
+ face_dofs[fj++] = base + n_face_dofs * face + d;
353
+ d += degree - 3 - ii;
354
+ }
355
+ }
356
+ }
357
+ else
358
+ {
359
+ for (int i = 0 ; i < degree - 2 ; ++i)
360
+ {
361
+ int d = i;
362
+ for (int ii = 0 ; ii < degree - 2 - i; ++ii)
363
+ {
364
+ face_dofs[fj++] = base + n_face_dofs * face + d;
365
+ d += degree - 2 - ii;
366
+ }
367
+ }
368
+ }
369
+ for (std::uint16_t r : vtk_triangle_remainders (face_dofs))
370
+ {
371
+ map[j++] = r;
372
+ }
373
+ }
374
+
375
+ base += 4 * n_face_dofs;
376
+
377
+ if (degree < 4 )
378
+ return map;
379
+
380
+ std::vector<std::uint16_t > remainders ((degree - 1 ) * (degree - 2 )
381
+ * (degree - 3 ) / 6 );
382
+ std::iota (remainders.begin (), remainders.end (), base);
383
+
384
+ for (std::uint16_t r : vtk_tetrahedron_remainders (remainders))
385
+ {
386
+ map[j++] = r;
387
+ }
388
+
389
+ return map;
171
390
}
172
391
// -----------------------------------------------------------------------------
173
392
std::vector<std::uint16_t > vtk_wedge (int num_nodes)
@@ -198,13 +417,7 @@ std::vector<std::uint16_t> vtk_pyramid(int num_nodes)
198
417
// -----------------------------------------------------------------------------
199
418
std::vector<std::uint16_t > vtk_quadrilateral (int num_nodes)
200
419
{
201
- // Check that num_nodes is a square integer (since quadrilaterals are
202
- // tensor products of intervals, the number of nodes for each interval
203
- // should be an integer)
204
- assert ((std::sqrt (num_nodes) - std::floor (std::sqrt (num_nodes))) == 0 );
205
-
206
- // Number of nodes in each direction
207
- const int n = sqrt (num_nodes);
420
+ const int n = cell_degree (mesh::CellType::quadrilateral, num_nodes);
208
421
std::vector<std::uint16_t > map (num_nodes);
209
422
210
423
// Vertices
@@ -215,7 +428,7 @@ std::vector<std::uint16_t> vtk_quadrilateral(int num_nodes)
215
428
216
429
int j = 4 ;
217
430
218
- const int edge_nodes = n - 2 ;
431
+ const int edge_nodes = n - 1 ;
219
432
220
433
// Edges
221
434
for (int k = 0 ; k < edge_nodes; ++k)
@@ -235,8 +448,7 @@ std::vector<std::uint16_t> vtk_quadrilateral(int num_nodes)
235
448
// -----------------------------------------------------------------------------
236
449
std::vector<std::uint16_t > vtk_hexahedron (int num_nodes)
237
450
{
238
- const int n = std::cbrt (num_nodes);
239
- assert (n * n * n == num_nodes);
451
+ std::uint16_t n = cell_degree (mesh::CellType::hexahedron, num_nodes);
240
452
241
453
std::vector<std::uint16_t > map (num_nodes);
242
454
@@ -253,7 +465,7 @@ std::vector<std::uint16_t> vtk_hexahedron(int num_nodes)
253
465
// Edges
254
466
int j = 8 ;
255
467
int base = 8 ;
256
- const int edge_nodes = n - 2 ;
468
+ const int edge_nodes = n - 1 ;
257
469
const std::vector<int > edges = {0 , 3 , 5 , 1 , 8 , 10 , 11 , 9 , 2 , 4 , 7 , 6 };
258
470
for (int e : edges)
259
471
{
0 commit comments