2
/// This file is part of Rheolef.
4
/// Copyright (C) 2000-2009 Pierre Saramito <Pierre.Saramito@imag.fr>
6
/// Rheolef is free software; you can redistribute it and/or modify
7
/// it under the terms of the GNU General Public License as published by
8
/// the Free Software Foundation; either version 2 of the License, or
9
/// (at your option) any later version.
11
/// Rheolef is distributed in the hope that it will be useful,
12
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
/// GNU General Public License for more details.
16
/// You should have received a copy of the GNU General Public License
17
/// along with Rheolef; if not, write to the Free Software
18
/// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
/// =========================================================================
22
#include "reference_element.h"
23
#include "rheolef/point.h"
32
namespace hexahedron {
33
#include "hexahedron.icc"
34
} // namespace hexahedron
36
#include "reference_element_declare.cc"
39
// static data members:
40
const reference_element::dof_family_type
41
reference_element::Lagrange = 0,
42
reference_element::Hermite = 1,
43
reference_element::dof_family_max = 2;
46
// ==============================================================================
48
// ==============================================================================
50
reference_element::set_name (char name)
53
check_macro (_x != max_variant, "undefined reference element `" << name << "'");
56
measure (reference_element hat_K) {
57
return hat_K_measure [hat_K.variant()];
59
reference_element::variant_type
60
reference_element::variant (char name)
62
for (size_type i = 0; i < max_variant; i++) {
63
if (_name [i] == name) return variant_type(i);
65
return variant_type(max_variant);
67
reference_element::variant_type
68
reference_element::variant (size_type n_vertex, size_type dim)
70
size_type variant = 0;
71
for (; variant < max_variant; variant++) {
72
if (_dimension[variant] == dim && _n_vertex[variant] == n_vertex) {
73
return variant_type(variant);
76
error_macro ("undefined "<<dim<<"d reference element with "<<n_vertex << " vertices");
78
reference_element::size_type
79
reference_element::n_sub_edge (variant_type variant)
82
case reference_element::p: return 0;
83
case reference_element::e: return 0;
84
case reference_element::t: return 3;
85
case reference_element::q: return 4;
86
case reference_element::T: return 6;
87
case reference_element::P: return 9;
88
case reference_element::H: return 12;
89
default: error_macro ("unexpected element variant `"<<variant<<"'"); return 0;
92
reference_element::size_type
93
reference_element::n_sub_face (variant_type variant)
96
case reference_element::p: return 0;
97
case reference_element::e: return 0;
98
case reference_element::t: return 0;
99
case reference_element::q: return 0;
100
case reference_element::T: return 4;
101
case reference_element::P: return 5;
102
case reference_element::H: return 6;
103
default: error_macro ("unexpected element variant `"<<variant<<"'"); return 0;
106
reference_element::size_type
107
reference_element::n_subgeo (variant_type variant, size_type subgeo_dim)
109
#define _RHEOLEF_reference_element_case(VARIANT) \
110
case reference_element::VARIANT: \
111
return reference_element_##VARIANT::n_subgeo (subgeo_dim);
114
_RHEOLEF_reference_element_case(p)
115
_RHEOLEF_reference_element_case(e)
116
_RHEOLEF_reference_element_case(t)
117
_RHEOLEF_reference_element_case(q)
118
_RHEOLEF_reference_element_case(T)
119
_RHEOLEF_reference_element_case(P)
120
_RHEOLEF_reference_element_case(H)
121
default: error_macro ("unexpected element variant `"<<variant<<"'"); return 0;
123
#undef _RHEOLEF_reference_element_case
125
reference_element::size_type
126
reference_element::subgeo_n_node (
127
variant_type variant,
129
size_type subgeo_dim,
132
#define _RHEOLEF_geo_element_auto_case(VARIANT) \
133
case reference_element::VARIANT: \
134
return reference_element_##VARIANT::subgeo_n_node (order, subgeo_dim, loc_isid);
137
_RHEOLEF_geo_element_auto_case(p)
138
_RHEOLEF_geo_element_auto_case(e)
139
_RHEOLEF_geo_element_auto_case(t)
140
_RHEOLEF_geo_element_auto_case(q)
141
_RHEOLEF_geo_element_auto_case(T)
142
_RHEOLEF_geo_element_auto_case(P)
143
_RHEOLEF_geo_element_auto_case(H)
144
default: error_macro ("unexpected element variant `"<<variant<<"'"); return 0;
146
#undef _RHEOLEF_geo_element_auto_case
148
reference_element::size_type
149
reference_element::subgeo_local_node (
150
variant_type variant,
152
size_type subgeo_dim,
154
size_type loc_jsidnod)
156
#define _RHEOLEF_geo_element_auto_case(VARIANT) \
157
case reference_element::VARIANT: \
158
return reference_element_##VARIANT::subgeo_local_node (order, subgeo_dim, loc_isid, loc_jsidnod);
161
_RHEOLEF_geo_element_auto_case(p)
162
_RHEOLEF_geo_element_auto_case(e)
163
_RHEOLEF_geo_element_auto_case(t)
164
_RHEOLEF_geo_element_auto_case(q)
165
_RHEOLEF_geo_element_auto_case(T)
166
_RHEOLEF_geo_element_auto_case(P)
167
_RHEOLEF_geo_element_auto_case(H)
168
default: error_macro ("unexpected element variant `"<<variant<<"'"); return 0;
170
#undef _RHEOLEF_geo_element_auto_case
172
reference_element::size_type
173
reference_element::first_inod_by_variant (
174
variant_type variant,
176
variant_type subgeo_variant)
178
#define _RHEOLEF_geo_element_auto_case(VARIANT) \
179
case reference_element::VARIANT: \
180
return reference_element_##VARIANT::first_inod_by_variant (order, subgeo_variant);
183
_RHEOLEF_geo_element_auto_case(p)
184
_RHEOLEF_geo_element_auto_case(e)
185
_RHEOLEF_geo_element_auto_case(t)
186
_RHEOLEF_geo_element_auto_case(q)
187
_RHEOLEF_geo_element_auto_case(T)
188
_RHEOLEF_geo_element_auto_case(P)
189
_RHEOLEF_geo_element_auto_case(H)
190
default: error_macro ("unexpected element variant `"<<variant<<"'"); return 0;
192
#undef _RHEOLEF_geo_element_auto_case
194
reference_element::size_type
195
reference_element::n_node (variant_type variant, size_type order)
198
case reference_element::p: return 1;
199
case reference_element::e: return order+1;
200
case reference_element::t: return (order+1)*(order+2)/2;
201
case reference_element::q: return (order+1)*(order+1);
202
case reference_element::T: return (order+1)*(order+2)*(order+3)/6;
203
case reference_element::P: return (order+1)*(order+1)*(order+2)/2;
204
case reference_element::H: return (order+1)*(order+1)*(order+1);
205
default: error_macro ("unexpected element variant `"<<variant<<"'"); return 0;
209
reference_element::init_local_nnode_by_variant (
211
boost::array<size_type,reference_element::max_variant>& sz)
213
sz [reference_element::p] = 1;
214
sz [reference_element::e] = order-1;
215
sz [reference_element::t] = (order-1)*(order-2)/2;
216
sz [reference_element::q] = (order-1)*(order-1);
217
sz [reference_element::T] = (order-1)*(order-2)*(order-3)/6;
218
sz [reference_element::P] = (order-1)*(order-1)*(order-2)/2;
219
sz [reference_element::H] = (order-1)*(order-1)*(order-1);
221
// ==============================================================================
223
// ==============================================================================
224
reference_element_p::size_type
225
reference_element_p::n_subgeo (size_type side_dim)
227
return (side_dim == 0) ? 1 : 0;
229
reference_element_p::size_type
230
reference_element_p::subgeo_n_node (size_type order, size_type side_dim, size_type loc_isid)
232
return (side_dim == 0) ? 1 : 0;
234
reference_element_p::size_type
235
reference_element_p::subgeo_local_node (size_type order, size_type side_dim, size_type loc_isid, size_type loc_jsidnod)
239
// edge 0d-lattice for high order elements, i <= 0
240
// convert to local inod geo_element number for rheolef
241
reference_element_p::size_type
242
reference_element_p::ilat2loc_inod (size_type order, const point_basic<size_type>& ilat)
246
reference_element_p::size_type
247
reference_element_p::first_inod_by_variant (
249
size_type subgeo_variant)
251
if (subgeo_variant == reference_element::p) return 0;
254
// ==============================================================================
256
// ==============================================================================
257
reference_element_e::size_type
258
reference_element_e::n_subgeo (size_type side_dim)
266
reference_element_e::size_type
267
reference_element_e::subgeo_n_node (size_type order, size_type side_dim, size_type loc_isid)
271
case 1: return order+1;
275
reference_element_e::size_type
276
reference_element_e::subgeo_local_node (size_type order, size_type side_dim, size_type loc_isid, size_type loc_jsidnod)
279
case 0: return loc_isid;
280
case 1: return loc_jsidnod;
284
// edge 1d-lattice (i) for high order elements, i <= order
285
// convert to local inod geo_element number for rheolef
286
reference_element_e::size_type
287
reference_element_e::ilat2loc_inod (size_type order, const point_basic<size_type>& ilat)
289
size_type i = ilat[0];
290
if (i == 0) return 0;
291
if (i == order) return 1;
294
reference_element_e::size_type
295
reference_element_e::first_inod_by_variant (
297
size_type subgeo_variant)
299
if (subgeo_variant == reference_element::p) return 0;
300
if (subgeo_variant == reference_element::e) return 2;
303
// ==============================================================================
305
// ==============================================================================
306
reference_element_t::size_type
307
reference_element_t::n_subgeo (size_type side_dim)
316
reference_element_t::size_type
317
reference_element_t::subgeo_n_node (size_type order, size_type side_dim, size_type loc_isid)
321
case 1: return order+1;
322
case 2: return ((order+1)*(order+2))/2;
326
reference_element_t::size_type
327
reference_element_t::subgeo_local_node (size_type order, size_type side_dim, size_type loc_isid, size_type loc_jsidnod)
330
case 0: return loc_isid;
331
case 1: if (loc_jsidnod < 2) return (loc_isid + loc_jsidnod) % 3; // edge-node is a vertex
332
else return (order-1)*loc_isid + loc_jsidnod + 1; // edge-node is edge-internal
333
case 2: return loc_jsidnod;
337
// triangle lattice (i,j) for high order elements, i+j <= order
338
// convert to local inod geo_element number for rheolef
339
reference_element_t::size_type
340
reference_element_t::ilat2loc_inod (size_type order, const point_basic<size_type>& ilat)
342
size_type i = ilat[0];
343
size_type j = ilat[1];
344
if (j == 0) { // horizontal edge [0,1]
345
if (i == 0) return 0;
346
if (i == order) return 1;
347
return 3 + 0*(order-1) + (i - 1);
349
if (i + j == order) { // oblique edge ]1,2]
350
if (j == order) return 2;
351
return 3 + 1*(order-1) + (j - 1);
353
size_type j1 = order - j;
354
if (i == 0) { // vertical edge ]2,0[
355
return 3 + 2*(order-1) + (j1 - 1);
357
// internal face ]0,1[x]0,2[: i, then j
358
size_type n_face_node = (order-1)*(order-2)/2;
359
size_type ij = (n_face_node - (j1-1)*j1/2) + (i - 1);
360
return 3 + 3*(order-1) + ij;
362
reference_element_t::size_type
363
reference_element_t::first_inod_by_variant (
365
size_type subgeo_variant)
367
if (subgeo_variant == reference_element::p) return 0;
368
if (subgeo_variant == reference_element::e) return 3;
369
if (subgeo_variant == reference_element::t) return 3 + 3*(order-1);
370
return (order+1)*(order+2)/2;
372
// ==============================================================================
374
// ==============================================================================
375
reference_element_q::size_type
376
reference_element_q::n_subgeo (size_type side_dim)
385
reference_element_q::size_type
386
reference_element_q::subgeo_n_node (size_type order, size_type side_dim, size_type loc_isid)
390
case 1: return order+1;
391
case 2: return (order+1)*(order+1);
395
reference_element_q::size_type
396
reference_element_q::subgeo_local_node (size_type order, size_type side_dim, size_type loc_isid, size_type loc_jsidnod)
399
case 0: return loc_isid;
400
case 1: if (loc_jsidnod < 2) return (loc_isid + loc_jsidnod) % 4; // edge-node is a vertex
401
else return (order-1)*loc_isid + loc_jsidnod + 2; // edge-node is edge-internal
402
case 2: return loc_jsidnod;
406
// quadrangle lattice (i,j) for high order elements, 0 <= i,j <= order
407
// convert to local inod geo_element number for rheolef
408
reference_element_q::size_type
409
reference_element_q::ilat2loc_inod (size_type order, const point_basic<size_type>& ilat)
411
size_type i = ilat[0];
412
size_type j = ilat[1];
413
if (j == 0) { // horizontal edge [0,1]
414
if (i == 0) return 0;
415
if (i == order) return 1;
416
return 4 + 0*(order-1) + (i - 1);
418
if (i == order) { // vertical edge ]1,2]
419
if (j == order) return 2;
420
return 4 + 1*(order-1) + (j - 1);
422
size_type i1 = order - i;
423
if (j == order) { // horizontal edge ]2,3]
424
if (i == 0) return 3;
425
return 4 + 2*(order-1) + (i1 - 1);
427
size_type j1 = order - j;
428
if (i == 0) { // vertical edge ]3,0[
429
return 4 + 3*(order-1) + (j1 - 1);
431
// internal face ]0,1[x]0,3[: i, then j
432
size_type ij = (order-1)*(j-1) + (i-1);
433
size_type n_bdry_node = 4 + 4*(order-1);
434
return n_bdry_node + ij;
436
reference_element_q::size_type
437
reference_element_q::first_inod_by_variant (
439
size_type subgeo_variant)
441
if (subgeo_variant == reference_element::p) return 0;
442
if (subgeo_variant == reference_element::e) return 4;
443
if (subgeo_variant == reference_element::t) return 4 + 4*(order-1);
444
if (subgeo_variant == reference_element::q) return 4 + 4*(order-1);
445
return (order+1)*(order+1);
447
// ==============================================================================
449
// ==============================================================================
450
reference_element_T::size_type
451
reference_element_T::n_subgeo (size_type side_dim)
461
reference_element_T::size_type
462
reference_element_T::subgeo_n_node (size_type order, size_type side_dim, size_type loc_isid)
466
case 1: return order+1;
467
case 2: return (order+1)*(order+2)/2;
468
case 3: return ((order+1)*(order+2)*(order+3))/6;
472
reference_element_T::size_type
473
reference_element_T::subgeo_local_node (size_type order, size_type side_dim, size_type loc_isid, size_type loc_jsidnod)
476
case 0: return loc_isid;
477
case 1: if (loc_jsidnod < 2) { // edge-node is a vertex
478
if (loc_isid < 3) return (loc_isid + loc_jsidnod) % 3;
479
else return loc_jsidnod == 0 ? loc_isid - 3 : 3;
480
} else { // edge-node is internal to the edge
481
return loc_isid*(order-1) + loc_jsidnod + 2;
484
if (loc_jsidnod < 3) { // face-node is a vertex
485
if (loc_isid == 3) return loc_jsidnod + 1;
486
if (loc_jsidnod == 0) return 0;
487
if (loc_jsidnod == 2) return loc_isid + 1;
488
return ((loc_isid + 1) % 3) + 1;
490
// face-node is edge-internal(P2) or face-internal(P3) ; volume-internal(P4) impossible
491
size_type last_edge_node_iloc = 3 + 3*(order-1);
492
if (loc_jsidnod < last_edge_node_iloc) { // edge-internal
494
extern const size_type geo_element_T_fac2edg_idx [4][3];
495
extern const int geo_element_T_fac2edg_orient [4][3];
497
size_type order1 = order - 1; // avoid div by zero compiler error
498
size_type loc_jedg = (loc_jsidnod-3) / order1;
499
size_type loc_kedg = (loc_jsidnod-3) % order1;
500
if (geo_element_T_fac2edg_orient [loc_isid][loc_jedg] < 0) {
501
loc_kedg = order - loc_kedg - 2;
503
return (order-1)*geo_element_T_fac2edg_idx [loc_isid][loc_jedg] + loc_kedg + 4;
505
// face-node is face-internal(P3)
506
size_type ij_loc = (loc_jsidnod - last_edge_node_iloc);
507
return 4 + 6*(order-1) + loc_isid*(order-1)*(order-2)/2 + ij_loc;
509
case 3: return loc_jsidnod;
513
// tetrahedron lattice (i,j,k) for high order elements, i+j+k <= order
514
// convert to local inod geo_element number for rheolef
515
reference_element_T::size_type
516
reference_element_T::ilat2loc_inod (size_type order, const point_basic<size_type>& ilat)
518
size_type i = ilat[0];
519
size_type j = ilat[1];
520
size_type k = ilat[2];
521
size_type n_tot_edge_node = 6*(order-1);
522
size_type n_face_node = (order-1)*(order-2)/2;
524
// horizontal face 021 = [0,2]x[0,1]
525
if (j == 0) { // left edge [0,1]
526
if (i == 0) return 0;
527
if (i == order) return 1;
528
return 4 + 0*(order-1) + (i - 1);
530
if (i + j == order) { // oblique edge ]1,2[
531
if (j == order) return 2;
532
return 4 + 1*(order-1) + (j - 1);
534
size_type j1 = order - j;
535
if (i == 0) { // right edge ]0,2[
536
return 4 + 2*(order-1) + (j1 - 1);
538
// internal face 021 = ]0,2[x]0,1[: j, then i
539
size_type i1 = order - i;
540
size_type ji = (n_face_node - i1*(i1-1)/2) + (j - 1);
541
return 4 + n_tot_edge_node + 0*n_face_node + ji;
544
// back face 032 =]0,3]x]0,2[
545
if (j == 0) { // vertical edge ]0,3]
546
if (k == order) return 3;
547
return 4 + 3*(order-1) + (k - 1);
549
if (j + k == order) { // oblique edge ]2,3[
550
return 4 + 5*(order-1) + (k - 1);
552
// internal face 032 =]0,3]x]0,2[, k, then j
553
size_type j1 = order - j;
554
size_type kj = (n_face_node - j1*(j1-1)/2) + (k - 1);
555
return 4 + n_tot_edge_node + 1*n_face_node + kj;
558
// left face 013 = ]0,1[x]0,3[
559
if (i + k == order) { // oblique edge ]1,3[
560
return 4 + 4*(order-1) + (k - 1);
562
// internal face 013 = ]0,1[x]0,3[: i, then k
563
size_type k1 = order - k;
564
size_type ik = (n_face_node - k1*(k1-1)/2) + (i - 1);
565
return 4 + n_tot_edge_node + 2*n_face_node + ik;
567
if (i + j + k == order) {
568
// internal to oblique face 123 = ]1,2[x]1,3], j, then k
569
size_type k1 = order - k;
570
size_type jk = (n_face_node - k1*(k1-1)/2) + (j - 1);
571
return 4 + n_tot_edge_node + 3*n_face_node + jk;
573
// internal to volume: i, then j, then k
574
size_type n_tot_face_node = 4*n_face_node;
575
size_type n_tot_node = (order+1)*(order+2)*(order+3)/6;
576
size_type n_volume_node = (order-1)*(order-2)*(order-3)/6;
577
size_type k1 = order - k;
578
size_type j1 = order - j - k;
579
size_type n_level_k_node = (k1-1)*(k1-2)/2;
580
size_type ijk = (n_volume_node - k1*(k1-1)*(k1-2)/6)
581
+ (n_level_k_node - j1*(j1-1)/2)
583
return 4 + n_tot_edge_node + n_tot_face_node + ijk;
585
reference_element_T::size_type
586
reference_element_T::first_inod_by_variant (
588
size_type subgeo_variant)
590
if (subgeo_variant == reference_element::p) return 0;
591
if (subgeo_variant == reference_element::e) return 4;
592
if (subgeo_variant == reference_element::t) return 4 + 6*(order-1);
593
if (subgeo_variant == reference_element::q) return 4 + 6*(order-1) + 4*((order-1)*(order-2)/2);
594
if (subgeo_variant == reference_element::T) return 4 + 6*(order-1) + 4*((order-1)*(order-2)/2);
595
return (order+1)*(order+2)*(order+3)/6;
597
reference_element_T::size_type
598
reference_element_T::face2edge (size_type loc_iface, size_type loc_iface_jedg)
600
return geo_element_T_fac2edg_idx [loc_iface][loc_iface_jedg];
603
reference_element_T::face2edge_orient (size_type loc_iface, size_type loc_iface_jedg)
605
return geo_element_T_fac2edg_orient [loc_iface][loc_iface_jedg];
607
// ==============================================================================
609
// ==============================================================================
610
reference_element_P::size_type
611
reference_element_P::n_subgeo (size_type side_dim)
621
reference_element_P::size_type
622
reference_element_P::subgeo_n_node (size_type order, size_type side_dim, size_type loc_isid)
626
case 1: return order+1;
627
case 2: return (loc_isid < 2) ? (order+1)*(order+2)/2 : (order+1)*(order+1);
628
case 3: return ((order+1)*(order+1)*(order+2))/2;
632
reference_element_P::size_type
633
reference_element_P::subgeo_local_node (size_type order, size_type side_dim, size_type loc_isid, size_type loc_jsidnod)
636
case 0: return loc_isid;
637
case 1: if (loc_jsidnod < 2) { // edge-node is a vertex
638
return prism::edge [loc_isid] [loc_jsidnod];
639
} else { // edge-node is internal to the edge
640
return 6 + loc_isid*(order-1) + (loc_jsidnod - 2);
643
size_type n_vert_on_side = (loc_isid < 2) ? 3 : 4;
644
if (loc_jsidnod < n_vert_on_side) { // face-node is a vertex
645
return prism::face [loc_isid] [loc_jsidnod];
647
// face-node is edge-internal(P2) or face-internal(P3) ; volume-internal is impossible
648
size_type last_edge_node_iloc = n_vert_on_side + n_vert_on_side*(order-1);
649
if (loc_jsidnod < last_edge_node_iloc) { // edge-internal
651
extern const size_type geo_element_P_fac2edg_idx [5][4];
652
extern const int geo_element_P_fac2edg_orient [5][4];
654
size_type order1 = order - 1; // avoid div by zero compiler error
655
size_type loc_jedg = (loc_jsidnod - n_vert_on_side) / order1;
656
size_type loc_kedg = (loc_jsidnod - n_vert_on_side) % order1;
657
if (geo_element_P_fac2edg_orient [loc_isid][loc_jedg] < 0) {
658
loc_kedg = order - loc_kedg - 2;
660
return 6 + (order-1)*geo_element_P_fac2edg_idx [loc_isid][loc_jedg] + loc_kedg;
662
// face-node is face-internal(P3)
663
size_type ij_loc = (loc_jsidnod - last_edge_node_iloc);
664
size_type shift_prev_faces;
666
shift_prev_faces = loc_isid*(order-1)*(order-2)/2;
668
shift_prev_faces = 2*(order-1)*(order-2)/2 + (loc_isid-2)*(order-1)*(order-1);
670
return 6 + 9*(order-1) + shift_prev_faces + ij_loc;
672
case 3: return loc_jsidnod;
676
reference_element_P::size_type
677
reference_element_P::ilat2loc_inod (size_type order, const point_basic<size_type>& ilat)
679
size_type i = ilat[0];
680
size_type j = ilat[1];
681
size_type k = ilat[2];
682
size_type i1 = order - i;
683
size_type j1 = order - j;
684
size_type k1 = order - k;
685
size_type n_node_edge = order-1;
686
size_type n_tot_edge_node = 9*(order-1);
687
size_type n_node_face_tri = (order-1)*(order-2)/2;
688
size_type n_node_face_qua = (order-1)*(order-1);
690
// horizontal face 021 = [0,1]x[0,2]
691
if (j == 0) { // left edge [0,1]
692
if (i == 0) return 0;
693
if (i == order) return 1;
694
return 6 + 0*(order-1) + (i - 1);
696
if (i + j == order) { // oblique edge ]1,2[
697
if (j == order) return 2;
698
return 6 + 1*(order-1) + (j - 1);
700
if (i == 0) { // right edge ]0,2[
701
return 6 + 2*(order-1) + (j1 - 1);
703
// internal face 021 = ]0,2[x]0,1[: j, then i
704
size_type ji = (n_node_face_tri - i1*(i1-1)/2) + (j - 1);
705
return 6 + n_tot_edge_node + 0*n_node_face_tri + ji;
708
// horizontal face 354 = [3,4]x[3,5]
709
if (j == 0) { // left edge [3,4]
710
if (i == 0) return 3;
711
if (i == order) return 4;
712
return 6 + 6*(order-1) + (i - 1);
714
if (i + j == order) { // oblique edge ]4,5[
715
if (j == order) return 5;
716
return 6 + 7*(order-1) + (j - 1);
718
if (i == 0) { // right edge ]3,5[
719
return 6 + 8*(order-1) + (j1 - 1);
721
// internal face 354 = ]3,4[x]3,5[: i, then j
722
size_type ij = (n_node_face_tri - j1*(j1-1)/2) + (i - 1);
723
return 6 + n_tot_edge_node + 1*n_node_face_tri + ij;
726
// left face 0143 = [0,1]x]0,3[
728
// vertical edge ]0,3[
729
return 6 + 3*(order-1) + (k - 1);
732
// vertical edge ]1,4[
733
return 6 + 4*(order-1) + (k - 1);
735
// internal face 01243 = ]0,1[x]0,3[: i then k
736
size_type ik = n_node_edge*(k-1) + (i-1);
737
return 6 + n_tot_edge_node + 2*n_node_face_tri + 0*n_node_face_qua + ik;
740
// back face 0352 = ]0,2]x]0,3[
742
// vertical edge ]2,5[
743
return 6 + 5*(order-1) + (k - 1);
745
// internal face 0352 = ]0,2[x]0,3[: k then j
746
size_type kj = n_node_edge*(j-1) + (k-1);
747
return 6 + n_tot_edge_node + 2*n_node_face_tri + 2*n_node_face_qua + kj;
749
if (i + j == order) {
750
// internal face 1254 = ]1,2[x]1,4[: j then k
751
size_type jk = n_node_edge*(k-1) + (j-1);
752
return 6 + n_tot_edge_node + 2*n_node_face_tri + 1*n_node_face_qua + jk;
754
// internal volume ]0,1[x]0,2[x][0,3[: i, then j, then k
755
size_type n_tot_face_node = 2*n_node_face_tri + 3*n_node_face_qua;
756
size_type ij = (n_node_face_tri - (j1-1)*j1/2) + (i - 1);
757
size_type ijk = n_node_face_tri*(k-1) + ij;
758
return 6 + n_tot_edge_node + n_tot_face_node + ijk;
760
reference_element_P::size_type
761
reference_element_P::first_inod_by_variant (
763
size_type subgeo_variant)
765
if (subgeo_variant == reference_element::p) return 0;
766
if (subgeo_variant == reference_element::e) return 6;
767
if (subgeo_variant == reference_element::t) return 6 + 9*(order-1);
768
if (subgeo_variant == reference_element::q) return 6 + 9*(order-1) + 2*((order-1)*(order-2)/2);
769
if (subgeo_variant == reference_element::T) return 6 + 9*(order-1) + 2*((order-1)*(order-2)/2) + 3*(order-1)*(order-1);
770
if (subgeo_variant == reference_element::P) return 6 + 9*(order-1) + 2*((order-1)*(order-2)/2) + 3*(order-1)*(order-1);
771
return ((order+1)*(order+1)*(order+2))/2;
773
// ==============================================================================
775
// ==============================================================================
777
reference_element_H::size_type
778
reference_element_H::n_subgeo (size_type side_dim)
788
reference_element_H::size_type
789
reference_element_H::subgeo_n_node (size_type order, size_type side_dim, size_type loc_isid)
793
case 1: return order+1;
794
case 2: return (order+1)*(order+1);
795
case 3: return (order+1)*(order+1)*(order+1);
799
reference_element_H::size_type
800
reference_element_H::subgeo_local_node (size_type order, size_type side_dim, size_type loc_isid, size_type loc_jsidnod)
803
case 0: return loc_isid;
804
case 1: if (loc_jsidnod < 2) { // edge-node is a vertex
805
if (loc_isid < 4) return (loc_isid + loc_jsidnod) % 4;
806
else if (loc_isid < 8) return loc_isid - 4 + loc_jsidnod*4;
807
else return loc_jsidnod == 0 ? loc_isid - 4 : (loc_isid - 7)%4 + 4;
808
} else { // edge-node is internal to the edge
809
return loc_isid*(order-1) + loc_jsidnod + 6; // TODO : BUG? +8 a la place de +6 ??
812
if (loc_jsidnod < 4) { // face-node is a vertex
813
return hexahedron::face [loc_isid][loc_jsidnod];
815
// face-node is edge-internal(P2) or face-internal(P2) ; volume-internal(P2) impossible
816
size_type last_edge_node_iloc = 4 + 4*(order-1);
817
if (loc_jsidnod < last_edge_node_iloc) { // edge-internal
819
extern const size_t geo_element_H_fac2edg_idx [6][4];
820
extern const int geo_element_H_fac2edg_orient [6][4];
822
size_type order1 = order - 1; // avoid div by zero compiler error
823
size_type loc_jedg = (loc_jsidnod-4) / order1;
824
size_type loc_kedg = (loc_jsidnod-4) % order1;
825
if (geo_element_H_fac2edg_orient [loc_isid][loc_jedg] < 0) {
826
loc_kedg = order - loc_kedg - 2;
828
return (order-1)*geo_element_H_fac2edg_idx [loc_isid][loc_jedg] + loc_kedg + 8;
830
// face-node is face-internal(P2)
831
return 8 + 12*(order-1) + (order-1)*(order-1)*loc_isid + (loc_jsidnod - last_edge_node_iloc);
833
case 3: return loc_jsidnod;
837
// edge 0d-lattice for high order elements, i <= 0
838
// convert to local inod geo_element number for rheolef
839
typedef reference_element_H::size_type size_type;
841
reference_element_H::size_type
842
H_ilat2loc_inod (size_type order, const point_basic<size_type>& ilat)
844
size_type i = ilat[0];
845
size_type j = ilat[1];
846
size_type k = ilat[2];
847
size_type i1 = order - i;
848
size_type j1 = order - j;
849
size_type k1 = order - k;
850
size_type n_node_edge = order-1;
851
size_type n_node_face = (order-1)*(order-1);
852
if (k == 0) { // bottom face [0,3]x[0,1]
853
if (j == 0) { // bottom-left edge [0,1]
854
if (i == 0) return 0;
855
if (i == order) return 1;
856
return 8 + 0*n_node_edge + (i - 1);
858
if (j == order) { // bottom-right edge [3,2]
859
if (i == 0) return 3;
860
if (i == order) return 2;
861
return 8 + 2*n_node_edge + (i1 - 1);
863
if (i == 0) { // bottom-back edge ]3,0[
864
return 8 + 3*n_node_edge + (j1 - 1);
866
if (i == order) { // bottom-front edge ]1,2[
867
return 8 + 1*n_node_edge + (j - 1);
869
// internal face ]0,3[x]0,1[: j then i (TODO: not checked since Pk(H) only with k <= 2 yet
870
size_type ji = n_node_edge*(i-1) + (j-1);
871
return 8 + 12*n_node_edge + 0*n_node_face + ji;
873
if (k == order) { // top face [4,5]x[4,7]
874
if (j == 0) { // top-left edge [4,5]
875
if (i == 0) return 4;
876
if (i == order) return 5;
877
return 8 + 8*n_node_edge + (i - 1);
879
if (j == order) { // top-right edge [7,6]
880
if (i == 0) return 7;
881
if (i == order) return 6;
882
return 8 + 10*n_node_edge + (i1 - 1);
884
if (i == 0) { // top-back edge ]7,4[
885
return 8 + 11*n_node_edge + (j1 - 1);
887
if (i == order) { // top-front edge ]5,6[
888
return 8 + 9*n_node_edge + (j - 1);
890
// internal face ]4,5[x]4,7[: i then j
891
size_type ij = n_node_edge*(j-1) + (i-1);
892
return 8 + 12*n_node_edge + 3*n_node_face + ij;
894
if (j == 0) { // left face ]0,1[x[0,4]
895
if (i == 0) { // left-back edge [0,4]
896
return 8 + 4*n_node_edge + (k - 1);
898
if (i == order) { // left-front edge [1,5]
899
return 8 + 5*n_node_edge + (k - 1);
901
// internal face ]0,1[x]0,4[: i then k
902
size_type ik = n_node_edge*(k-1) + (i-1);
903
return 8 + 12*n_node_edge + 2*n_node_face + ik;
905
if (j == order) { // right face ]2,3[x[2,6]
906
if (i == 0) { // right-back edge [3,7]
907
return 8 + 7*n_node_edge + (k - 1);
909
if (i == order) { // right-front edge [2,6]
910
return 8 + 6*n_node_edge + (k - 1);
912
// internal face ]2,3[x]2,6[: i1 then k
913
size_type i1k = n_node_edge*(k-1) + (i1-1);
914
return 8 + 12*n_node_edge + 5*n_node_face + i1k;
916
if (i == 0) { // internal back face ]0,4[x[0,3]: k then j
917
size_type kj = n_node_edge*(j-1) + (k-1);
918
return 8 + 12*n_node_edge + 1*n_node_face + kj;
920
if (i == order) { // internal front face ]1,2[x[1,5]: j then k
921
size_type jk = n_node_edge*(k-1) + (j-1);
922
return 8 + 12*n_node_edge + 4*n_node_face + jk;
924
// internal volume: i then j then k
925
size_type n_node_bdry = 8 + 12*n_node_edge + 6*n_node_face;
926
size_type ijk = (order-1)*((order-1)*(k-1) + (j-1)) + (i-1);
927
return n_node_bdry + ijk;
929
reference_element_H::size_type
930
reference_element_H::ilat2loc_inod (size_type order, const point_basic<size_type>& ilat)
932
size_type loc_inod = H_ilat2loc_inod (order, ilat);
933
return H_ilat2loc_inod (order, ilat);
935
reference_element_H::size_type
936
reference_element_H::first_inod_by_variant (
938
size_type subgeo_variant)
940
if (subgeo_variant == reference_element::p) return 0;
941
if (subgeo_variant == reference_element::e) return 8;
942
if (subgeo_variant == reference_element::t) return 8 + 12*(order-1);
943
if (subgeo_variant == reference_element::q) return 8 + 12*(order-1);
944
if (subgeo_variant == reference_element::T) return 8 + 12*(order-1) + 6*(order-1)*(order-1);
945
if (subgeo_variant == reference_element::P) return 8 + 12*(order-1) + 6*(order-1)*(order-1);
946
if (subgeo_variant == reference_element::H) return 8 + 12*(order-1) + 6*(order-1)*(order-1);
947
return (order+1)*(order+1)*(order+1);
950
} // namespace rheolef