Compare commits
155
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bca9363172 | ||
|
|
85785a1d51 | ||
|
|
4f4c8bb000 | ||
|
|
c3eb769a2a | ||
|
|
9286d89b0e | ||
|
|
fca4c314d4 | ||
|
|
459def6d79 | ||
|
|
6245cb6df3 | ||
|
|
a5d230f199 | ||
|
|
84ce403ffb | ||
|
|
df09aea4da | ||
|
|
d2840464ba | ||
|
|
3839122306 | ||
|
|
7be65f6362 | ||
|
|
7c580696ed | ||
|
|
7efaaddb48 | ||
|
|
91ea8c521f | ||
|
|
98f3cf0b7d | ||
|
|
6fc5954c83 | ||
|
|
b27f142a8d | ||
|
|
b7ac27d6a5 | ||
|
|
5cede87cc3 | ||
|
|
b44ba89cc1 | ||
|
|
20c7ddd40f | ||
|
|
d2507c2d19 | ||
|
|
daef4a707f | ||
|
|
3f4f2b5d7d | ||
|
|
b2e381995b | ||
|
|
ffac92f50f | ||
|
|
3ac0713e7d | ||
|
|
91e2a491ac | ||
|
|
e1dc14506a | ||
|
|
b2a5a8818c | ||
|
|
9a7d02214f | ||
|
|
e69123dbb2 | ||
|
|
1b23c0b85f | ||
|
|
a80a46a45e | ||
|
|
58e416cd4c | ||
|
|
5431f28f2b | ||
|
|
fc3775d549 | ||
|
|
ee8f81e9b7 | ||
|
|
ea5cbfa45d | ||
|
|
0a178223f4 | ||
|
|
15b369d120 | ||
|
|
10d543419a | ||
|
|
2a2b5b3314 | ||
|
|
0e2670e6ba | ||
|
|
9cb6ac90f4 | ||
|
|
dc92de7607 | ||
|
|
838f32d052 | ||
|
|
6edbdb10b6 | ||
|
|
051dd436a7 | ||
|
|
ed0a53fc21 | ||
|
|
bc3b20756a | ||
|
|
2ec070cfcd | ||
|
|
e247a48496 | ||
|
|
ce357b3d31 | ||
|
|
3b93842ed4 | ||
|
|
7247a056c0 | ||
|
|
1d5c78afaf | ||
|
|
51cabe4530 | ||
|
|
b5ad79948a | ||
|
|
13087639e4 | ||
|
|
8bb3c1f88f | ||
|
|
1fb24abeb7 | ||
|
|
3c84979ae1 | ||
|
|
cc77cad832 | ||
|
|
39b4d088fc | ||
|
|
994bf59afa | ||
|
|
051642a9b8 | ||
|
|
f27dbc30d5 | ||
|
|
e945f6cf49 | ||
|
|
89f7f93f36 | ||
|
|
6da740baf0 | ||
|
|
61f084e34c | ||
|
|
a426d939a3 | ||
|
|
f7e6beb99f | ||
|
|
d9824c7578 | ||
|
|
23b3e7dcbc | ||
|
|
8f94150a3e | ||
|
|
0a19f04474 | ||
|
|
aa1cb6f840 | ||
|
|
ac6016dd0c | ||
|
|
ca4bd46f2f | ||
|
|
801430150b | ||
|
|
9008f02d15 | ||
|
|
80f0b1f2d5 | ||
|
|
13ba92ccf1 | ||
|
|
67480e6ca5 | ||
|
|
e4c43532b4 | ||
|
|
3b2604e582 | ||
|
|
42db0cd988 | ||
|
|
0f7e0de3d5 | ||
|
|
5c58758fda | ||
|
|
de79f0243f | ||
|
|
247b4d9fdf | ||
|
|
0eabd62aa9 | ||
|
|
179e702e5b | ||
|
|
3dfaa64744 | ||
|
|
bf6262daf4 | ||
|
|
d09acbceff | ||
|
|
e4f2b4fd0d | ||
|
|
d60393edb0 | ||
|
|
03bffe438b | ||
|
|
e249c0889b | ||
|
|
be90d1179e | ||
|
|
2da040c52a | ||
|
|
9fdf71b028 | ||
|
|
ecf5954f66 | ||
|
|
08cbd00509 | ||
|
|
ceb7c8efbc | ||
|
|
b8aa9b705c | ||
|
|
3ea14703e2 | ||
|
|
cc74c87a1a | ||
|
|
031722a50c | ||
|
|
4cac7186b3 | ||
|
|
92d12f61a2 | ||
|
|
da86aaa1fe | ||
|
|
0f0d05726b | ||
|
|
90b7c2275b | ||
|
|
fcf1e7ae09 | ||
|
|
5adf8ca172 | ||
|
|
827eafe635 | ||
|
|
b2a3d478a7 | ||
|
|
ed02f2a25c | ||
|
|
fa695a71c5 | ||
|
|
300bf6ebea | ||
|
|
35934ddd46 | ||
|
|
ab426339f1 | ||
|
|
92b8ebbeaf | ||
|
|
817fb5d549 | ||
|
|
6c767f02f2 | ||
|
|
88da01bd32 | ||
|
|
45dea7453f | ||
|
|
779803d48f | ||
|
|
6c728dfc40 | ||
|
|
47054c792f | ||
|
|
90d919c7a9 | ||
|
|
06950f2249 | ||
|
|
1f92f750ed | ||
|
|
620edaad46 | ||
|
|
cb84230765 | ||
|
|
664959bc2a | ||
|
|
e01483f8e4 | ||
|
|
7a665f97ac | ||
|
|
e8d880f923 | ||
|
|
d8df32549e | ||
|
|
3e34a1342c | ||
|
|
84e24629d8 | ||
|
|
30669fd6ee | ||
|
|
cea505df7a | ||
|
|
498ef892ac | ||
|
|
8ad9e29dd6 | ||
|
|
3aa3ae43f3 | ||
|
|
439436f44b |
@@ -14,6 +14,8 @@ Version 4.7.1 (development)
|
||||
- Added an MFEM example for the eikonal equation. This new solver is based on
|
||||
the proximal Galerkin method introduced by Keith and Surowiec.
|
||||
|
||||
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
|
||||
|
||||
|
||||
Version 4.7, released on May 7, 2024
|
||||
====================================
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
dimension
|
||||
4
|
||||
|
||||
elements
|
||||
24
|
||||
1 7 4 5 8 11 13
|
||||
1 7 1 4 5 7 8
|
||||
1 7 1 4 5 8 11
|
||||
1 7 1 5 8 11 13
|
||||
1 7 1 5 7 8 13
|
||||
1 7 4 5 7 8 13
|
||||
1 7 1 3 4 8 11
|
||||
1 7 1 3 4 5 11
|
||||
1 7 1 5 10 11 13
|
||||
1 7 1 8 10 11 13
|
||||
1 7 1 3 5 10 11
|
||||
1 7 1 2 3 5 10
|
||||
1 7 0 1 3 4 8
|
||||
1 7 0 1 4 7 8
|
||||
1 7 1 5 6 7 13
|
||||
1 7 1 6 7 8 13
|
||||
1 7 6 7 8 13 15
|
||||
1 7 4 7 8 13 15
|
||||
1 7 4 8 12 13 15
|
||||
1 7 4 8 11 12 13
|
||||
1 7 6 8 13 14 15
|
||||
1 7 1 6 8 13 14
|
||||
1 7 1 8 9 10 13
|
||||
1 7 1 8 9 13 14
|
||||
|
||||
boundary
|
||||
48
|
||||
1 4 0 1 3 4
|
||||
1 4 0 1 3 8
|
||||
1 4 0 3 4 8
|
||||
1 4 0 1 4 7
|
||||
1 4 0 1 7 8
|
||||
1 4 0 4 7 8
|
||||
1 4 1 4 5 7
|
||||
1 4 1 3 8 11
|
||||
1 4 1 3 4 5
|
||||
1 4 1 5 10 13
|
||||
1 4 1 8 10 11
|
||||
1 4 1 3 10 11
|
||||
1 4 1 2 3 5
|
||||
1 4 1 2 3 10
|
||||
1 4 1 2 5 10
|
||||
1 4 1 5 6 7
|
||||
1 4 1 5 6 13
|
||||
1 4 1 6 7 8
|
||||
1 4 1 6 8 14
|
||||
1 4 1 6 13 14
|
||||
1 4 1 8 9 10
|
||||
1 4 1 9 10 13
|
||||
1 4 1 8 9 14
|
||||
1 4 1 9 13 14
|
||||
1 4 2 3 5 10
|
||||
1 4 3 4 8 11
|
||||
1 4 3 4 5 11
|
||||
1 4 3 5 10 11
|
||||
1 4 4 5 11 13
|
||||
1 4 4 5 7 13
|
||||
1 4 4 7 8 15
|
||||
1 4 4 7 13 15
|
||||
1 4 4 8 12 15
|
||||
1 4 4 12 13 15
|
||||
1 4 4 8 11 12
|
||||
1 4 4 11 12 13
|
||||
1 4 5 10 11 13
|
||||
1 4 5 6 7 13
|
||||
1 4 6 7 8 15
|
||||
1 4 6 7 13 15
|
||||
1 4 6 8 14 15
|
||||
1 4 6 13 14 15
|
||||
2 4 8 10 11 13
|
||||
2 4 8 12 13 15
|
||||
2 4 8 11 12 13
|
||||
2 4 8 13 14 15
|
||||
2 4 8 9 10 13
|
||||
2 4 8 9 13 14
|
||||
|
||||
vertices
|
||||
16
|
||||
4
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
@@ -0,0 +1,102 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
dimension
|
||||
4
|
||||
|
||||
elements
|
||||
24
|
||||
17 8 4 5 8 11 13
|
||||
11 8 1 4 5 7 8
|
||||
15 8 1 4 5 8 11
|
||||
16 8 1 5 8 11 13
|
||||
12 8 1 5 7 8 13
|
||||
13 8 4 5 7 8 13
|
||||
7 8 1 3 4 8 11
|
||||
2 8 1 3 4 5 11
|
||||
4 8 1 5 10 11 13
|
||||
10 8 1 8 10 11 13
|
||||
3 8 1 3 5 10 11
|
||||
1 8 1 2 3 5 10
|
||||
6 8 0 1 3 4 8
|
||||
8 8 0 1 4 7 8
|
||||
5 8 1 5 6 7 13
|
||||
20 8 1 6 7 8 13
|
||||
19 8 6 7 8 13 15
|
||||
14 8 4 7 8 13 15
|
||||
21 8 4 8 12 13 15
|
||||
22 8 4 8 11 12 13
|
||||
23 8 6 8 13 14 15
|
||||
24 8 1 6 8 13 14
|
||||
9 8 1 8 9 10 13
|
||||
18 8 1 8 9 13 14
|
||||
|
||||
boundary
|
||||
48
|
||||
1 4 0 1 3 4
|
||||
3 4 0 1 3 8
|
||||
3 4 0 3 4 8
|
||||
1 4 0 1 4 7
|
||||
3 4 0 1 7 8
|
||||
3 4 0 4 7 8
|
||||
1 4 1 4 5 7
|
||||
3 4 1 3 8 11
|
||||
1 4 1 3 4 5
|
||||
3 4 1 5 10 13
|
||||
3 4 1 8 10 11
|
||||
3 4 1 3 10 11
|
||||
1 4 1 2 3 5
|
||||
3 4 1 2 3 10
|
||||
3 4 1 2 5 10
|
||||
1 4 1 5 6 7
|
||||
3 4 1 5 6 13
|
||||
3 4 1 6 7 8
|
||||
3 4 1 6 8 14
|
||||
3 4 1 6 13 14
|
||||
3 4 1 8 9 10
|
||||
3 4 1 9 10 13
|
||||
3 4 1 8 9 14
|
||||
3 4 1 9 13 14
|
||||
3 4 2 3 5 10
|
||||
3 4 3 4 8 11
|
||||
3 4 3 4 5 11
|
||||
3 4 3 5 10 11
|
||||
3 4 4 5 11 13
|
||||
3 4 4 5 7 13
|
||||
3 4 4 7 8 15
|
||||
3 4 4 7 13 15
|
||||
3 4 4 8 12 15
|
||||
3 4 4 12 13 15
|
||||
3 4 4 8 11 12
|
||||
3 4 4 11 12 13
|
||||
3 4 5 10 11 13
|
||||
3 4 5 6 7 13
|
||||
3 4 6 7 8 15
|
||||
3 4 6 7 13 15
|
||||
3 4 6 8 14 15
|
||||
3 4 6 13 14 15
|
||||
5 4 8 10 11 13
|
||||
5 4 8 12 13 15
|
||||
5 4 8 11 12 13
|
||||
5 4 8 13 14 15
|
||||
5 4 8 9 10 13
|
||||
5 4 8 9 13 14
|
||||
|
||||
vertices
|
||||
16
|
||||
4
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
@@ -0,0 +1,231 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
dimension
|
||||
4
|
||||
|
||||
elements
|
||||
96
|
||||
1 8 0 1 7 8 9
|
||||
1 8 1 6 7 8 9
|
||||
1 8 4 5 6 8 9
|
||||
1 8 4 6 7 8 9
|
||||
1 8 0 1 3 8 9
|
||||
1 8 1 2 3 8 9
|
||||
1 8 0 4 7 8 9
|
||||
1 8 0 3 4 8 9
|
||||
1 8 1 2 6 8 9
|
||||
1 8 2 5 6 8 9
|
||||
1 8 3 4 5 8 9
|
||||
1 8 2 3 5 8 9
|
||||
1 8 9 10 11 17 18
|
||||
1 8 9 11 16 17 18
|
||||
1 8 9 14 15 16 18
|
||||
1 8 9 14 16 17 18
|
||||
1 8 9 10 11 13 18
|
||||
1 8 9 11 12 13 18
|
||||
1 8 9 10 14 17 18
|
||||
1 8 9 10 13 14 18
|
||||
1 8 9 11 12 16 18
|
||||
1 8 9 12 15 16 18
|
||||
1 8 9 13 14 15 18
|
||||
1 8 9 12 13 15 18
|
||||
1 8 9 12 15 16 19
|
||||
1 8 9 11 12 16 19
|
||||
1 8 1 6 9 11 19
|
||||
1 8 6 9 11 16 19
|
||||
1 8 1 2 6 9 19
|
||||
1 8 2 5 6 9 19
|
||||
1 8 2 5 9 15 19
|
||||
1 8 2 9 12 15 19
|
||||
1 8 5 6 9 16 19
|
||||
1 8 5 9 15 16 19
|
||||
1 8 1 9 11 12 19
|
||||
1 8 1 2 9 12 19
|
||||
1 8 9 10 13 14 20
|
||||
1 8 9 10 14 17 20
|
||||
1 8 0 9 10 17 20
|
||||
1 8 0 7 9 17 20
|
||||
1 8 0 3 4 9 20
|
||||
1 8 0 4 7 9 20
|
||||
1 8 3 4 9 13 20
|
||||
1 8 4 9 13 14 20
|
||||
1 8 4 7 9 14 20
|
||||
1 8 7 9 14 17 20
|
||||
1 8 0 3 9 10 20
|
||||
1 8 3 9 10 13 20
|
||||
1 8 2 5 9 15 21
|
||||
1 8 2 9 12 15 21
|
||||
1 8 2 3 5 9 21
|
||||
1 8 3 4 5 9 21
|
||||
1 8 9 13 14 15 21
|
||||
1 8 9 12 13 15 21
|
||||
1 8 4 5 9 14 21
|
||||
1 8 5 9 14 15 21
|
||||
1 8 2 3 9 12 21
|
||||
1 8 3 9 12 13 21
|
||||
1 8 3 4 9 13 21
|
||||
1 8 4 9 13 14 21
|
||||
1 8 1 6 9 11 22
|
||||
1 8 6 9 11 16 22
|
||||
1 8 6 7 9 16 22
|
||||
1 8 7 9 16 17 22
|
||||
1 8 0 7 9 17 22
|
||||
1 8 0 9 10 17 22
|
||||
1 8 0 1 9 10 22
|
||||
1 8 1 9 10 11 22
|
||||
1 8 0 1 7 9 22
|
||||
1 8 1 6 7 9 22
|
||||
1 8 9 10 11 17 22
|
||||
1 8 9 11 16 17 22
|
||||
1 8 5 9 15 16 23
|
||||
1 8 5 6 9 16 23
|
||||
1 8 6 7 9 16 23
|
||||
1 8 7 9 16 17 23
|
||||
1 8 7 9 14 17 23
|
||||
1 8 4 7 9 14 23
|
||||
1 8 4 5 9 14 23
|
||||
1 8 5 9 14 15 23
|
||||
1 8 4 6 7 9 23
|
||||
1 8 4 5 6 9 23
|
||||
1 8 9 14 15 16 23
|
||||
1 8 9 14 16 17 23
|
||||
1 8 1 2 9 12 24
|
||||
1 8 1 9 11 12 24
|
||||
1 8 0 1 9 10 24
|
||||
1 8 1 9 10 11 24
|
||||
1 8 0 3 9 10 24
|
||||
1 8 3 9 10 13 24
|
||||
1 8 2 3 9 12 24
|
||||
1 8 3 9 12 13 24
|
||||
1 8 1 2 3 9 24
|
||||
1 8 0 1 3 9 24
|
||||
1 8 9 10 11 13 24
|
||||
1 8 9 11 12 13 24
|
||||
|
||||
boundary
|
||||
96
|
||||
1 4 0 1 7 8
|
||||
1 4 0 1 3 8
|
||||
1 4 0 4 7 8
|
||||
1 4 0 3 4 8
|
||||
2 4 0 10 17 20
|
||||
2 4 0 7 17 20
|
||||
2 4 0 3 4 20
|
||||
2 4 0 4 7 20
|
||||
2 4 0 3 10 20
|
||||
2 4 0 7 17 22
|
||||
2 4 0 10 17 22
|
||||
2 4 0 1 10 22
|
||||
2 4 0 1 7 22
|
||||
2 4 0 1 10 24
|
||||
2 4 0 3 10 24
|
||||
2 4 0 1 3 24
|
||||
1 4 1 6 7 8
|
||||
1 4 1 2 3 8
|
||||
1 4 1 2 6 8
|
||||
2 4 1 6 11 19
|
||||
2 4 1 2 6 19
|
||||
2 4 1 11 12 19
|
||||
2 4 1 2 12 19
|
||||
2 4 1 6 11 22
|
||||
2 4 1 10 11 22
|
||||
2 4 1 6 7 22
|
||||
2 4 1 2 12 24
|
||||
2 4 1 11 12 24
|
||||
2 4 1 10 11 24
|
||||
2 4 1 2 3 24
|
||||
1 4 2 5 6 8
|
||||
1 4 2 3 5 8
|
||||
2 4 2 5 6 19
|
||||
2 4 2 5 15 19
|
||||
2 4 2 12 15 19
|
||||
2 4 2 5 15 21
|
||||
2 4 2 12 15 21
|
||||
2 4 2 3 5 21
|
||||
2 4 2 3 12 21
|
||||
2 4 2 3 12 24
|
||||
1 4 3 4 5 8
|
||||
2 4 3 4 13 20
|
||||
2 4 3 10 13 20
|
||||
2 4 3 4 5 21
|
||||
2 4 3 12 13 21
|
||||
2 4 3 4 13 21
|
||||
2 4 3 10 13 24
|
||||
2 4 3 12 13 24
|
||||
1 4 4 5 6 8
|
||||
1 4 4 6 7 8
|
||||
2 4 4 13 14 20
|
||||
2 4 4 7 14 20
|
||||
2 4 4 5 14 21
|
||||
2 4 4 13 14 21
|
||||
2 4 4 7 14 23
|
||||
2 4 4 5 14 23
|
||||
2 4 4 6 7 23
|
||||
2 4 4 5 6 23
|
||||
2 4 5 6 16 19
|
||||
2 4 5 15 16 19
|
||||
2 4 5 14 15 21
|
||||
2 4 5 15 16 23
|
||||
2 4 5 6 16 23
|
||||
2 4 5 14 15 23
|
||||
2 4 6 11 16 19
|
||||
2 4 6 11 16 22
|
||||
2 4 6 7 16 22
|
||||
2 4 6 7 16 23
|
||||
2 4 7 14 17 20
|
||||
2 4 7 16 17 22
|
||||
2 4 7 16 17 23
|
||||
2 4 7 14 17 23
|
||||
3 4 10 11 17 18
|
||||
3 4 10 11 13 18
|
||||
3 4 10 14 17 18
|
||||
3 4 10 13 14 18
|
||||
2 4 10 13 14 20
|
||||
2 4 10 14 17 20
|
||||
2 4 10 11 17 22
|
||||
2 4 10 11 13 24
|
||||
3 4 11 16 17 18
|
||||
3 4 11 12 13 18
|
||||
3 4 11 12 16 18
|
||||
2 4 11 12 16 19
|
||||
2 4 11 16 17 22
|
||||
2 4 11 12 13 24
|
||||
3 4 12 15 16 18
|
||||
3 4 12 13 15 18
|
||||
2 4 12 15 16 19
|
||||
2 4 12 13 15 21
|
||||
3 4 13 14 15 18
|
||||
2 4 13 14 15 21
|
||||
3 4 14 15 16 18
|
||||
3 4 14 16 17 18
|
||||
2 4 14 15 16 23
|
||||
2 4 14 16 17 23
|
||||
|
||||
vertices
|
||||
25
|
||||
4
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 0.0000000000000000
|
||||
0.5000000000000000 0.5000000000000000 0.5000000000000000 0.0000000000000000
|
||||
0.5000000000000000 0.5000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 0.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 1.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
0.0000000000000000 0.0000000000000000 1.0000000000000000 1.0000000000000000
|
||||
0.5000000000000000 0.5000000000000000 0.5000000000000000 1.0000000000000000
|
||||
1.0000000000000000 0.5000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.0000000000000000 0.5000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.5000000000000000 1.0000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.5000000000000000 0.0000000000000000 0.5000000000000000 0.5000000000000000
|
||||
0.5000000000000000 0.5000000000000000 1.0000000000000000 0.5000000000000000
|
||||
0.5000000000000000 0.5000000000000000 0.0000000000000000 0.5000000000000000
|
||||
@@ -0,0 +1,36 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
2
|
||||
|
||||
elements
|
||||
2
|
||||
1 2 2 0 1
|
||||
1 2 0 2 3
|
||||
|
||||
boundary
|
||||
4
|
||||
1 1 0 1
|
||||
1 1 1 2
|
||||
2 1 2 3
|
||||
1 1 3 0
|
||||
|
||||
vertices
|
||||
4
|
||||
2
|
||||
0 0
|
||||
1 0
|
||||
1 1
|
||||
0 1
|
||||
@@ -0,0 +1,52 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
6
|
||||
1 4 3 1 7 5
|
||||
1 4 1 6 7 4
|
||||
1 4 6 1 0 2
|
||||
1 4 1 6 4 2
|
||||
1 4 6 1 3 0
|
||||
1 4 1 6 3 7
|
||||
|
||||
boundary
|
||||
12
|
||||
1 2 6 0 3
|
||||
1 2 0 6 2
|
||||
1 2 1 3 0
|
||||
1 2 3 1 5
|
||||
1 2 3 7 6
|
||||
1 2 7 3 5
|
||||
1 2 4 6 7
|
||||
1 2 6 4 2
|
||||
2 2 1 7 5
|
||||
2 2 7 1 4
|
||||
1 2 1 2 4
|
||||
1 2 2 1 0
|
||||
|
||||
vertices
|
||||
8
|
||||
3
|
||||
0 0 0
|
||||
0 0 1
|
||||
1 0 0
|
||||
0 1 0
|
||||
1 0 1
|
||||
0 1 1
|
||||
1 1 0
|
||||
1 1 1
|
||||
@@ -1208,13 +1208,13 @@ STRIP_CODE_COMMENTS = NO
|
||||
# entity all documented functions referencing it will be listed.
|
||||
# The default value is: NO.
|
||||
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCED_BY_RELATION = YES
|
||||
|
||||
# If the REFERENCES_RELATION tag is set to YES then for each documented function
|
||||
# all documented entities called/used by that function will be listed.
|
||||
# The default value is: NO.
|
||||
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_RELATION = YES
|
||||
|
||||
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
|
||||
# to YES then the hyperlinks from functions in REFERENCES_RELATION and
|
||||
|
||||
@@ -73,6 +73,9 @@ if (MFEM_USE_MPI)
|
||||
ex20p.cpp
|
||||
ex21p.cpp
|
||||
ex22p.cpp
|
||||
ex1p_4d.cpp
|
||||
ex3p_4d.cpp
|
||||
ex4D_DivSkew.cpp
|
||||
ex24p.cpp
|
||||
ex25p.cpp
|
||||
ex26p.cpp
|
||||
|
||||
+27
-9
@@ -20,6 +20,7 @@
|
||||
// ex14 -m ../data/fichera-amr.mesh
|
||||
// ex14 -pa -r 1 -o 3
|
||||
// ex14 -pa -r 1 -o 3 -m ../data/fichera.mesh
|
||||
// ex14 -m ../data/inline-tet.mesh -o 0 -nt 4 -s 1
|
||||
//
|
||||
// Device sample runs:
|
||||
// ex14 -pa -r 2 -d cuda -o 3
|
||||
@@ -55,10 +56,16 @@ int main(int argc, char *argv[])
|
||||
bool pa = false;
|
||||
bool visualization = 1;
|
||||
const char *device_config = "cpu";
|
||||
int nt = 0;
|
||||
double st = 1.0;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&nt, "-nt", "--number-of-timeslices",
|
||||
"Number of slices through the hyper-prism in the 4th coordinate.");
|
||||
args.AddOption(&st, "-st", "--size-time",
|
||||
"Length of hyper-prims in 4th coordinate (e.g. time).");
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly, -1 for auto.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
@@ -97,8 +104,17 @@ int main(int argc, char *argv[])
|
||||
// 3. Read the mesh from the given mesh file. We can handle triangular,
|
||||
// quadrilateral, tetrahedral and hexahedral meshes with the same code.
|
||||
// NURBS meshes are projected to second order meshes.
|
||||
Mesh mesh(mesh_file);
|
||||
const int dim = mesh.Dimension();
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
if (dim == 3 && nt > 0)
|
||||
{
|
||||
Mesh* spat_mesh = mesh;
|
||||
mesh = new Mesh(spat_mesh, nt, Element::PENTATOPE, true, st);
|
||||
delete spat_mesh;
|
||||
|
||||
ref_levels = 0;
|
||||
dim = 4;
|
||||
}
|
||||
|
||||
// 4. Refine the mesh to increase the resolution. In this example we do
|
||||
// 'ref_levels' of uniform refinement. By default, or if ref_levels < 0,
|
||||
@@ -107,23 +123,23 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
if (ref_levels < 0)
|
||||
{
|
||||
ref_levels = (int)floor(log(50000./mesh.GetNE())/log(2.)/dim);
|
||||
ref_levels = (int)floor(log(50000./mesh->GetNE())/log(2.)/(dim < 4 ? dim : 1.));
|
||||
}
|
||||
for (int l = 0; l < ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
if (mesh.NURBSext)
|
||||
if (mesh->NURBSext)
|
||||
{
|
||||
mesh.SetCurvature(max(order, 1));
|
||||
mesh->SetCurvature(max(order, 1));
|
||||
}
|
||||
|
||||
// 5. Define a finite element space on the mesh. Here we use discontinuous
|
||||
// finite elements of the specified order >= 0.
|
||||
const auto bt = pa ? BasisType::GaussLobatto : BasisType::GaussLegendre;
|
||||
DG_FECollection fec(order, dim, bt);
|
||||
FiniteElementSpace fespace(&mesh, &fec);
|
||||
FiniteElementSpace fespace(mesh, &fec);
|
||||
cout << "Number of unknowns: " << fespace.GetVSize() << endl;
|
||||
|
||||
// 6. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
@@ -198,7 +214,7 @@ int main(int argc, char *argv[])
|
||||
// later using GLVis: "glvis -m refined.mesh -g sol.gf".
|
||||
ofstream mesh_ofs("refined.mesh");
|
||||
mesh_ofs.precision(8);
|
||||
mesh.Print(mesh_ofs);
|
||||
mesh->Print(mesh_ofs);
|
||||
ofstream sol_ofs("sol.gf");
|
||||
sol_ofs.precision(8);
|
||||
x.Save(sol_ofs);
|
||||
@@ -210,8 +226,10 @@ int main(int argc, char *argv[])
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << mesh << x << flush;
|
||||
sol_sock << "solution\n" << *mesh << x << flush;
|
||||
}
|
||||
|
||||
delete mesh;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+24
-8
@@ -19,6 +19,7 @@
|
||||
// mpirun -np 4 ex14p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex14p -pa -rs 1 -rp 0 -o 3
|
||||
// mpirun -np 4 ex14p -pa -rs 1 -rp 0 -m ../data/fichera.mesh -o 3
|
||||
// mpirun -np 4 ex14p -m ../data/inline-tet.mesh -o 0 -nt 4 -s 1
|
||||
//
|
||||
// Device sample runs:
|
||||
// mpirun -np 4 ex14p -pa -rs 2 -rp 0 -d cuda -o 3
|
||||
@@ -90,10 +91,16 @@ int main(int argc, char *argv[])
|
||||
bool pa = false;
|
||||
bool visualization = 1;
|
||||
const char *device_config = "cpu";
|
||||
int nt = 0;
|
||||
double st = 1.0;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&nt, "-nt", "--number-of-timeslices",
|
||||
"Number of slices through the hyper-prism in the 4th coordinate.");
|
||||
args.AddOption(&st, "-st", "--size-time",
|
||||
"Length of hyper-prims in 4th coordinate (e.g. time).");
|
||||
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
|
||||
"Number of times to refine the mesh uniformly in serial,"
|
||||
" -1 for auto.");
|
||||
@@ -139,8 +146,17 @@ int main(int argc, char *argv[])
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral and hexahedral meshes
|
||||
// with the same code. NURBS meshes are projected to second order meshes.
|
||||
Mesh mesh(mesh_file);
|
||||
int dim = mesh.Dimension();
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
if (dim == 3 && nt > 0)
|
||||
{
|
||||
Mesh* spat_mesh = mesh;
|
||||
mesh = new Mesh(spat_mesh, nt, Element::PENTATOPE, true, st);
|
||||
delete spat_mesh;
|
||||
dim = 4;
|
||||
}
|
||||
if (dim == 4)
|
||||
ser_ref_levels = 0;
|
||||
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ser_ref_levels' of uniform refinement. By default,
|
||||
@@ -149,23 +165,23 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
if (ser_ref_levels < 0)
|
||||
{
|
||||
ser_ref_levels = (int)floor(log(10000./mesh.GetNE())/log(2.)/dim);
|
||||
ser_ref_levels = (int)floor(log(10000./mesh->GetNE())/log(2.)/dim);
|
||||
}
|
||||
for (int l = 0; l < ser_ref_levels; l++)
|
||||
{
|
||||
mesh.UniformRefinement();
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
if (mesh.NURBSext)
|
||||
if (mesh->NURBSext)
|
||||
{
|
||||
mesh.SetCurvature(max(order, 1));
|
||||
mesh->SetCurvature(max(order, 1));
|
||||
}
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted.
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
ParMesh pmesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
// MFEM Example 1 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex1p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex1p -m ../data/square-disc.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/escher.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-p2.vtk -o 2
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-p3.mesh -o 3
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-nurbs.mesh -o -1
|
||||
// mpirun -np 4 ex1p -m ../data/disc-nurbs.mesh -o -1
|
||||
// mpirun -np 4 ex1p -m ../data/pipe-nurbs.mesh -o -1
|
||||
// mpirun -np 4 ex1p -m ../data/ball-nurbs.mesh -o 2
|
||||
// mpirun -np 4 ex1p -m ../data/star-surf.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/square-disc-surf.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/inline-segment.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/amr-quad.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh
|
||||
// mpirun -np 4 ex1p -m ../data/mobius-strip.mesh -o -1 -sc
|
||||
//
|
||||
// Description: This example code demonstrates the use of MFEM to define a
|
||||
// simple finite element discretization of the Laplace problem
|
||||
// -Delta u = 1 with homogeneous Dirichlet boundary conditions.
|
||||
// Specifically, we discretize using a FE space of the specified
|
||||
// order, or if order < 1 using an isoparametric/isogeometric
|
||||
// space (i.e. quadratic for quadratic curvilinear mesh, NURBS for
|
||||
// NURBS mesh, etc.)
|
||||
//
|
||||
// The example highlights the use of mesh refinement, finite
|
||||
// element grid functions, as well as linear and bilinear forms
|
||||
// corresponding to the left-hand side and right-hand side of the
|
||||
// discrete linear system. We also cover the explicit elimination
|
||||
// of essential boundary conditions, static condensation, and the
|
||||
// optional connection to the GLVis tool for visualization.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "./spe10_coeff.cpp"
|
||||
|
||||
|
||||
int* LoadIterations(int NRows, int NCol)
|
||||
{
|
||||
ifstream in("iter_grad.txt");
|
||||
|
||||
//initialize
|
||||
int *iters = new int[NCol*NRows];
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
iters[row*NCol+col] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
return iters;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
if (in.eof())
|
||||
{
|
||||
in.close();
|
||||
return iters;
|
||||
}
|
||||
in >> iters[row*NCol+col];
|
||||
}
|
||||
|
||||
|
||||
in.close();
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
void putIterationsInArray(int iter, int row, int col, int NCol, int* iters)
|
||||
{
|
||||
iters[row*NCol+col] = iter;
|
||||
}
|
||||
|
||||
void WriteIterations(int *iters, int NRows, int NCol)
|
||||
{
|
||||
ofstream out;
|
||||
out.open("iter_grad.txt",fstream::out);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
delete[] iters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
out << iters[row*NCol+col] << "\t";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
|
||||
delete[] iters;
|
||||
}
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
double kappa = 1.0;
|
||||
|
||||
double u_exact(const Vector &x)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
return cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
}
|
||||
else { return 0.0; }
|
||||
}
|
||||
|
||||
double f_exact(const Vector &x)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
return (kappa + 4.0 * M_PI*M_PI) * cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(
|
||||
2))*cos(M_PI*x(3));
|
||||
}
|
||||
else { return 0.0; }
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
bool verbose = (myid==0);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/cube4d_96.MFEM";
|
||||
int order = 1;
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
int sequ_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
double tol = 1e-6;
|
||||
bool set_bc = true;
|
||||
bool standardCG = true;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&sequ_ref_levels, "-sr", "--seqrefinement",
|
||||
"Number of sequential refinement steps.");
|
||||
args.AddOption(&par_ref_levels, "-pr", "--parrefinement",
|
||||
"Number of parallel refinement steps.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Polynomial order of the finite element space.");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"A parameter.");
|
||||
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
|
||||
"Impose or not essential boundary conditions.");
|
||||
args.AddOption(&standardCG, "-sCG", "--stdCG", "-rCG", "--resCG",
|
||||
"Switch between standard PCG or recompute residuals in every step and use the residuals itself for the stopping criteria.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (verbose) { args.PrintOptions(cout); }
|
||||
|
||||
Mesh *mesh;
|
||||
ifstream imesh(mesh_file);
|
||||
if (!imesh)
|
||||
{
|
||||
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
mesh = new Mesh(imesh, 1, 1);
|
||||
imesh.close();
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
// if(dim !=4 || sdim != 4)
|
||||
// {
|
||||
// MPI_Finalize();
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
for (int i=0; i<sequ_ref_levels; i++) { mesh->UniformRefinement(); }
|
||||
if (verbose) { mesh->PrintCharacteristics(); }
|
||||
|
||||
if (verbose) { cout << "now we partition the mesh..." << endl << endl; }
|
||||
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
|
||||
for (int i=0; i<par_ref_levels; i++) { pmesh->UniformRefinement(); }
|
||||
|
||||
pmesh->PrintInfo(std::cout);
|
||||
if (verbose) { cout << endl; }
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use continuous Lagrange finite elements of the specified order. If
|
||||
// order < 1, we instead use an isoparametric/isogeometric space.
|
||||
FiniteElementCollection *fec;
|
||||
if (order > 0)
|
||||
{
|
||||
if (dim==4)
|
||||
{
|
||||
if (order==1) { fec = new LinearFECollection; }
|
||||
else { fec = new QuadraticFECollection; }
|
||||
}
|
||||
else { fec = new H1_FECollection(order, dim); }
|
||||
}
|
||||
else if (pmesh->GetNodes())
|
||||
{
|
||||
fec = pmesh->GetNodes()->OwnFEC();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Using isoparametric FEs: " << fec->Name() << endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fec = new H1_FECollection(order = 1, dim);
|
||||
}
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = set_bc ? 1 : 0;
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
|
||||
FunctionCoefficient uExact(u_exact);
|
||||
ParGridFunction x(fespace);
|
||||
|
||||
int NExpo =8;
|
||||
for (int expo=-NExpo; expo<=NExpo; expo++)
|
||||
{
|
||||
double weight = pow(10.0,expo);
|
||||
kappa = weight;
|
||||
|
||||
x.ProjectCoefficient(uExact);
|
||||
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
FunctionCoefficient ffunc(f_exact);
|
||||
b->AddDomainIntegrator(new DomainLFIntegrator(ffunc));
|
||||
b->Assemble();
|
||||
|
||||
x = 0.0;
|
||||
|
||||
// 10. Set up the parallel bilinear form a(.,.) on the finite element space
|
||||
// corresponding to the Laplacian operator -Delta, by adding the Diffusion
|
||||
// domain integrator.
|
||||
|
||||
// std::string permFile = "spe_perm.dat";
|
||||
// InversePermeabilityFunction::ReadPermeabilityFile(permFile, MPI_COMM_WORLD);
|
||||
// FunctionCoefficient *cspe10 = new FunctionCoefficient(InversePermeabilityFunction::Norm2Permeability);
|
||||
Coefficient *beta = new ConstantCoefficient(weight);
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DiffusionIntegrator);
|
||||
a->AddDomainIntegrator(new MassIntegrator(*beta));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
|
||||
}
|
||||
|
||||
// 12. Define and apply a parallel PCG solver for AX=B with the BoomerAMG
|
||||
// preconditioner from hypre.
|
||||
HypreSolver *amg = new HypreBoomerAMG(A);
|
||||
|
||||
int iter = -1;
|
||||
if (standardCG)
|
||||
{
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(A);
|
||||
pcg->SetRelTol(tol);
|
||||
pcg->SetMaxIter(5000);
|
||||
pcg->SetPrintLevel(1);
|
||||
pcg->SetPreconditioner(*amg);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
iter = pcg->GetNumIterations();
|
||||
|
||||
delete pcg;
|
||||
}
|
||||
else
|
||||
{
|
||||
HyprePCG *pcg = new HyprePCG(A);
|
||||
pcg->SetTol(tol);
|
||||
pcg->SetMaxIter(5000);
|
||||
pcg->SetResidualConvergenceOptions(1,tol);
|
||||
pcg->SetPrintLevel(2);
|
||||
pcg->SetPreconditioner(*amg);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
pcg->GetNumIterations(iter);
|
||||
|
||||
delete pcg;
|
||||
}
|
||||
|
||||
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Weigth: " << weight << " " << iter << endl;
|
||||
|
||||
int *iters = LoadIterations(10, 2*NExpo+1);
|
||||
putIterationsInArray(iter, sequ_ref_levels+par_ref_levels, expo+NExpo,
|
||||
2*NExpo+1, iters);
|
||||
WriteIterations(iters, 10, 2*NExpo+1);
|
||||
}
|
||||
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
{
|
||||
double err = x.ComputeL2Error(uExact);
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "\n|| u - u_h ||_{L^2} = " << err << '\n' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 14. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
// {
|
||||
// ostringstream mesh_name, sol_name;
|
||||
// mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
// sol_name << "sol." << setfill('0') << setw(6) << myid;
|
||||
//
|
||||
// ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
// mesh_ofs.precision(8);
|
||||
// pmesh->Print(mesh_ofs);
|
||||
//
|
||||
// ofstream sol_ofs(sol_name.str().c_str());
|
||||
// sol_ofs.precision(8);
|
||||
// x.Save(sol_ofs);
|
||||
// }
|
||||
|
||||
// 15. Send the solution by socket to a GLVis server.
|
||||
// if (visualization)
|
||||
// {
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock(vishost, visport);
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock.precision(8);
|
||||
// sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
// }
|
||||
|
||||
delete amg;
|
||||
delete a;
|
||||
delete beta;
|
||||
delete b;
|
||||
}
|
||||
|
||||
// 16. Free the used memory.
|
||||
|
||||
delete fespace;
|
||||
if (order > 0) { delete fec; }
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
+222
-9
@@ -58,6 +58,180 @@ void f_exact(const Vector &, Vector &);
|
||||
real_t freq = 1.0, kappa;
|
||||
int dim;
|
||||
|
||||
class Curl4dPrec : public Solver
|
||||
{
|
||||
|
||||
private:
|
||||
HypreParMatrix *A;
|
||||
ParFiniteElementSpace *fespace;
|
||||
|
||||
HypreParMatrix *idMat;
|
||||
HypreParMatrix *H1VecLaplaceMat;
|
||||
HypreBoomerAMG *amgVecH1;
|
||||
|
||||
|
||||
HypreParMatrix *gradMat;
|
||||
HypreParMatrix *H1LaplaceMat;
|
||||
HypreBoomerAMG *amgH1;
|
||||
|
||||
HypreSmoother * smoother;
|
||||
CGSolver *pcgGrad;
|
||||
CGSolver *pcgH1Vec;
|
||||
|
||||
Vector *f;
|
||||
Vector *fGrad, *uGrad;
|
||||
Vector *fH1Vec, *uH1Vec;
|
||||
|
||||
bool exactSolves;
|
||||
|
||||
public:
|
||||
Curl4dPrec(HypreParMatrix *AUser, ParFiniteElementSpace *fespaceUser,
|
||||
const Array<int> &essBnd, int orderKernel=1, bool exactSolvesUser=false)
|
||||
{
|
||||
A = AUser;
|
||||
fespace = fespaceUser;
|
||||
ParMesh *pmesh = fespace->GetParMesh();
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
exactSolves = exactSolvesUser;
|
||||
|
||||
int orderIm=1; //vecH1 --> H(curl)
|
||||
int orderKer=orderKernel; //grad V --> H(curl)
|
||||
|
||||
smoother = new HypreSmoother(*A, 16, 3);
|
||||
|
||||
// //for the pure dirichlet case
|
||||
// Array<int> essBnd(pmesh->bdr_attributes.Max()); essBnd = 1;
|
||||
|
||||
Array<int> HCurl_essDof(fespace->GetVSize()); HCurl_essDof = 0;
|
||||
fespace->GetEssentialVDofs(essBnd, HCurl_essDof);
|
||||
|
||||
//setup the H1 FESpace
|
||||
FiniteElementCollection* fecH1;
|
||||
if (orderKer==1) { fecH1 = new LinearFECollection; }
|
||||
else { fecH1 = new QuadraticFECollection; }
|
||||
|
||||
ParFiniteElementSpace *H1FESpace = new ParFiniteElementSpace(pmesh, fecH1);
|
||||
Array<int> H1_essDof(H1FESpace->GetVSize()); H1_essDof = 0;
|
||||
H1FESpace->GetEssentialVDofs(essBnd, H1_essDof);
|
||||
|
||||
//setup the discrete gradient
|
||||
ParDiscreteLinearOperator *disGrad = new ParDiscreteLinearOperator(H1FESpace,
|
||||
fespace);
|
||||
disGrad->AddDomainInterpolator(new GradientInterpolator);
|
||||
disGrad->Assemble();
|
||||
disGrad->Finalize();
|
||||
SparseMatrix* smat = &(disGrad->SpMat());
|
||||
smat->EliminateCols(H1_essDof);
|
||||
for (int dof=0; dof<HCurl_essDof.Size(); dof++) if (HCurl_essDof[dof]<0) { smat->EliminateRow(dof); }
|
||||
gradMat = disGrad->ParallelAssemble();
|
||||
delete disGrad;
|
||||
|
||||
//setup the H1 preconditioner
|
||||
ParBilinearForm* H1Varf = new ParBilinearForm(H1FESpace);
|
||||
H1Varf->AddDomainIntegrator(new DiffusionIntegrator);
|
||||
H1Varf->AddDomainIntegrator(new MassIntegrator);
|
||||
H1Varf->Assemble();
|
||||
H1Varf->Finalize();
|
||||
|
||||
SparseMatrix &matH1(H1Varf->SpMat());
|
||||
for (int dof=0; dof<H1_essDof.Size(); dof++) if (H1_essDof[dof]<0) { matH1.EliminateRowCol(dof); }
|
||||
H1LaplaceMat = H1Varf->ParallelAssemble();
|
||||
delete H1Varf;
|
||||
amgH1 = new HypreBoomerAMG(*H1LaplaceMat);
|
||||
|
||||
|
||||
//setup the H1 injection
|
||||
FiniteElementCollection* fecH1Vec;
|
||||
if (orderIm==1) { fecH1Vec = new LinearFECollection; }
|
||||
else { fecH1Vec = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1VecFESpace = new ParFiniteElementSpace(pmesh, fecH1Vec,
|
||||
dim, Ordering::byVDIM);
|
||||
Array<int> H1Vec_essDof(H1VecFESpace->GetVSize()); H1Vec_essDof = 0;
|
||||
H1VecFESpace->GetEssentialVDofs(essBnd, H1Vec_essDof);
|
||||
|
||||
//setup the discrete gradient
|
||||
ParDiscreteLinearOperator *disInterpol = new ParDiscreteLinearOperator(
|
||||
H1VecFESpace, fespace);
|
||||
disInterpol->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpol->Assemble();
|
||||
disInterpol->Finalize();
|
||||
SparseMatrix* smatID = &(disInterpol->SpMat());
|
||||
smatID->EliminateCols(H1Vec_essDof);
|
||||
for (int dof=0; dof<HCurl_essDof.Size(); dof++) if (HCurl_essDof[dof]<0) { smatID->EliminateRow(dof); }
|
||||
idMat = disInterpol->ParallelAssemble();
|
||||
delete disInterpol;
|
||||
|
||||
//setup the H1-vec preconditioner
|
||||
ParBilinearForm* H1VecVarf = new ParBilinearForm(H1VecFESpace);
|
||||
H1VecVarf->AddDomainIntegrator(new VectorDiffusionIntegrator);
|
||||
H1VecVarf->AddDomainIntegrator(new VectorMassIntegrator);
|
||||
H1VecVarf->Assemble();
|
||||
H1VecVarf->Finalize();
|
||||
|
||||
SparseMatrix &matH1Vec(H1VecVarf->SpMat());
|
||||
for (int dof=0; dof<H1Vec_essDof.Size(); dof++) if (H1Vec_essDof[dof]<0) { matH1Vec.EliminateRowCol(dof); }
|
||||
H1VecLaplaceMat = H1VecVarf->ParallelAssemble();
|
||||
delete H1VecVarf;
|
||||
amgVecH1 = new HypreBoomerAMG(*H1VecLaplaceMat);
|
||||
amgVecH1->SetSystemsOptions(dim);
|
||||
|
||||
|
||||
f = new Vector(fespace->GetTrueVSize());
|
||||
|
||||
fGrad = new Vector(H1FESpace->GetTrueVSize());
|
||||
uGrad = new Vector(H1FESpace->GetTrueVSize());
|
||||
|
||||
fH1Vec = new Vector(H1VecFESpace->GetTrueVSize());
|
||||
uH1Vec = new Vector(H1VecFESpace->GetTrueVSize());;
|
||||
|
||||
|
||||
amgH1->Mult(*fGrad, *uGrad);
|
||||
amgVecH1->Mult(*fH1Vec, *uH1Vec);
|
||||
|
||||
pcgGrad = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgGrad->SetOperator(*H1LaplaceMat);
|
||||
pcgGrad->SetPreconditioner(*amgH1);
|
||||
pcgGrad->SetRelTol(1e-16);
|
||||
pcgGrad->SetMaxIter(100000000);
|
||||
pcgGrad->SetPrintLevel(-2);
|
||||
|
||||
pcgH1Vec = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgH1Vec->SetOperator(*H1VecLaplaceMat);
|
||||
pcgH1Vec->SetPreconditioner(*amgVecH1);
|
||||
pcgH1Vec->SetRelTol(1e-16);
|
||||
pcgH1Vec->SetMaxIter(100000000);
|
||||
pcgH1Vec->SetPrintLevel(-2);
|
||||
|
||||
}
|
||||
|
||||
void setExactSolve(bool exSol)
|
||||
{
|
||||
exactSolves = exSol;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
smoother->Mult(x,y);
|
||||
|
||||
idMat->MultTranspose(x,*fH1Vec);
|
||||
*uH1Vec = 0.0;
|
||||
if (exactSolves) { pcgH1Vec->Mult(*fH1Vec, *uH1Vec); }
|
||||
else { amgVecH1->Mult(*fH1Vec, *uH1Vec); }
|
||||
idMat->Mult(1.0, *uH1Vec, 1.0, y);
|
||||
|
||||
gradMat->MultTranspose(x,*fGrad);
|
||||
*uGrad = 0.0;
|
||||
if (exactSolves) { pcgGrad->Mult(*fGrad, *uGrad); }
|
||||
else { amgH1->Mult(*fGrad, *uGrad); }
|
||||
gradMat->Mult(1.0, *uGrad, 1.0, y);
|
||||
|
||||
}
|
||||
|
||||
virtual void SetOperator(const Operator &op) {};
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
@@ -162,7 +336,13 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 7. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
FiniteElementCollection *fec = new ND_FECollection(order, dim);
|
||||
FiniteElementCollection *fec;
|
||||
if (dim==4)
|
||||
{
|
||||
if (order==1) { fec = new ND1_4DFECollection; }
|
||||
else { fec = new ND2_4DFECollection; }
|
||||
}
|
||||
else { fec = new ND_FECollection(order, dim); }
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_BigInt size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
@@ -248,15 +428,29 @@ int main(int argc, char *argv[])
|
||||
|
||||
ParFiniteElementSpace *prec_fespace =
|
||||
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
|
||||
Solver *prec;
|
||||
HypreAMS ams(*A.As<HypreParMatrix>(), prec_fespace);
|
||||
HyprePCG pcg(*A.As<HypreParMatrix>());
|
||||
pcg.SetTol(1e-12);
|
||||
pcg.SetMaxIter(500);
|
||||
pcg.SetPrintLevel(2);
|
||||
pcg.SetPreconditioner(ams);
|
||||
pcg.Mult(B, X);
|
||||
if (dim <= 3)
|
||||
{
|
||||
prec = new HypreAMS(*A.As<HypreParMatrix>(), prec_fespace);
|
||||
}
|
||||
else if (dim == 4)
|
||||
{
|
||||
prec = new Curl4dPrec(A.As<HypreParMatrix>(), fespace, ess_bdr, order, false);
|
||||
}
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(*A.As<HypreParMatrix>());
|
||||
pcg->SetTol(1e-12);
|
||||
pcg->SetMaxIter(500);
|
||||
pcg->SetPrintLevel(2);
|
||||
pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
delete pcg;
|
||||
delete prec;
|
||||
}
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// 14. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
@@ -312,7 +506,14 @@ int main(int argc, char *argv[])
|
||||
|
||||
void E_exact(const Vector &x, Vector &E)
|
||||
{
|
||||
if (dim == 3)
|
||||
if (dim==4)
|
||||
{
|
||||
E(0) = sin(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(1) = -cos(M_PI*x(0))*sin(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(2) = cos(M_PI*x(0))*cos(M_PI*x(1))*sin(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(3) = -cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*sin(M_PI*x(3));
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(2));
|
||||
@@ -328,7 +529,19 @@ void E_exact(const Vector &x, Vector &E)
|
||||
|
||||
void f_exact(const Vector &x, Vector &f)
|
||||
{
|
||||
if (dim == 3)
|
||||
//f_exact = E + DivSkew P( curl E ), where P is the 4d permutation operator
|
||||
if (dim==4)
|
||||
{
|
||||
f(0) = (1.0+4.0*M_PI*M_PI)*sin(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(1) = -(1.0+4.0*M_PI*M_PI)*cos(M_PI*x(0))*sin(M_PI*x(1))*cos(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(2) = (1.0+4.0*M_PI*M_PI)*cos(M_PI*x(0))*cos(M_PI*x(1))*sin(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(3) = -(1.0+4.0*M_PI*M_PI)*cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*sin(
|
||||
M_PI*x(3));
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
|
||||
|
||||
@@ -0,0 +1,650 @@
|
||||
// MFEM Example 3 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex3p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/escher.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
|
||||
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
|
||||
//
|
||||
// Description: This example code solves a simple electromagnetic diffusion
|
||||
// problem corresponding to the second order definite Maxwell
|
||||
// equation curl curl E + E = f with boundary condition
|
||||
// E x n = <given tangential field>. Here, we use a given exact
|
||||
// solution E and compute the corresponding r.h.s. f.
|
||||
// We discretize with Nedelec finite elements in 2D or 3D.
|
||||
//
|
||||
// The example demonstrates the use of H(curl) finite element
|
||||
// spaces with the curl-curl and the (vector finite element) mass
|
||||
// bilinear form, as well as the computation of discretization
|
||||
// error when the exact solution is known. Static condensation is
|
||||
// also illustrated.
|
||||
//
|
||||
// We recommend viewing examples 1-2 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "./spe10_coeff.cpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
int* LoadIterations(int NRows, int NCol)
|
||||
{
|
||||
ifstream in("iter_curl.txt");
|
||||
|
||||
//initialize
|
||||
int *iters = new int[NCol*NRows];
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
iters[row*NCol+col] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
return iters;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
if (in.eof())
|
||||
{
|
||||
in.close();
|
||||
return iters;
|
||||
}
|
||||
in >> iters[row*NCol+col];
|
||||
}
|
||||
|
||||
|
||||
in.close();
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
void putIterationsInArray(int iter, int row, int col, int NCol, int* iters)
|
||||
{
|
||||
iters[row*NCol+col] = iter;
|
||||
}
|
||||
|
||||
void WriteIterations(int *iters, int NRows, int NCol)
|
||||
{
|
||||
ofstream out;
|
||||
out.open("iter_curl.txt",fstream::out);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
delete[] iters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
out << iters[row*NCol+col] << "\t";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
|
||||
delete[] iters;
|
||||
}
|
||||
|
||||
|
||||
// Exact solution, E, and r.h.s., f. See below for implementation.
|
||||
void E_exact(const Vector &, Vector &);
|
||||
void f_exact(const Vector &, Vector &);
|
||||
double freq = 1.0, kappa = 1.0;
|
||||
int dim;
|
||||
|
||||
double osziCoeff(const Vector &x)
|
||||
{
|
||||
return 1.0001 + sin(100*x(0))*sin(200*x(1))*sin(300*x(2))*sin(400*x(3));
|
||||
}
|
||||
|
||||
class Curl4dPrec : public Solver
|
||||
{
|
||||
|
||||
private:
|
||||
HypreParMatrix *A;
|
||||
ParFiniteElementSpace *fespace;
|
||||
Coefficient *alpha_, *beta_, *neg_beta_;
|
||||
|
||||
HypreParMatrix *idMat;
|
||||
HypreParMatrix *H1VecLaplaceMat;
|
||||
HypreBoomerAMG *amgVecH1;
|
||||
|
||||
|
||||
HypreParMatrix *gradMat;
|
||||
HypreParMatrix *H1LaplaceMat;
|
||||
HypreBoomerAMG *amgH1;
|
||||
|
||||
HypreSmoother * smoother;
|
||||
CGSolver *pcgGrad;
|
||||
CGSolver *pcgH1Vec;
|
||||
|
||||
Vector *f;
|
||||
Vector *fGrad, *uGrad;
|
||||
Vector *fH1Vec, *uH1Vec;
|
||||
|
||||
bool exactSolves;
|
||||
|
||||
public:
|
||||
~Curl4dPrec()
|
||||
{
|
||||
delete pcgH1Vec;
|
||||
delete pcgGrad;
|
||||
|
||||
delete f, fGrad, uGrad, fH1Vec, uH1Vec;
|
||||
|
||||
delete smoother;
|
||||
|
||||
delete amgVecH1, H1VecLaplaceMat;
|
||||
delete idMat;
|
||||
delete amgH1, H1LaplaceMat;
|
||||
delete gradMat;
|
||||
}
|
||||
|
||||
Curl4dPrec(HypreParMatrix *AUser, ParFiniteElementSpace *fespaceUser,
|
||||
Coefficient *alpha, Coefficient *beta, Coefficient *neg_beta,
|
||||
const Array<int> &essBnd, int orderKernel=1, bool exactSolvesUser=false)
|
||||
{
|
||||
A = AUser;
|
||||
fespace = fespaceUser;
|
||||
alpha_ = alpha;
|
||||
beta_ = beta;
|
||||
neg_beta_=neg_beta;
|
||||
|
||||
ParMesh *pmesh = fespace->GetParMesh();
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
exactSolves = exactSolvesUser;
|
||||
|
||||
int orderIm=1; //vecH1 --> H(curl)
|
||||
int orderKer=orderKernel; //grad V --> H(curl)
|
||||
|
||||
smoother = new HypreSmoother(*A, 16, 3);
|
||||
|
||||
// //for the pure dirichlet case
|
||||
// Array<int> essBnd(pmesh->bdr_attributes.Max()); essBnd = 1;
|
||||
|
||||
Array<int> HCurl_essDof(fespace->GetVSize()); HCurl_essDof = 0;
|
||||
fespace->GetEssentialVDofs(essBnd, HCurl_essDof);
|
||||
|
||||
//setup the H1 FESpace
|
||||
FiniteElementCollection* fecH1;
|
||||
if (orderKer==1) { fecH1 = new LinearFECollection; }
|
||||
else { fecH1 = new QuadraticFECollection; }
|
||||
|
||||
ParFiniteElementSpace *H1FESpace = new ParFiniteElementSpace(pmesh, fecH1);
|
||||
Array<int> H1_essDof(H1FESpace->GetVSize()); H1_essDof = 0;
|
||||
H1FESpace->GetEssentialVDofs(essBnd, H1_essDof);
|
||||
|
||||
//setup the discrete gradient
|
||||
ParDiscreteLinearOperator *disGrad = new ParDiscreteLinearOperator(H1FESpace,
|
||||
fespace);
|
||||
disGrad->AddDomainInterpolator(new GradientInterpolator);
|
||||
disGrad->Assemble();
|
||||
disGrad->Finalize();
|
||||
SparseMatrix* smat = &(disGrad->SpMat());
|
||||
smat->EliminateCols(H1_essDof);
|
||||
for (int dof=0; dof<HCurl_essDof.Size(); dof++) if (HCurl_essDof[dof]<0) { smat->EliminateRow(dof); }
|
||||
gradMat = disGrad->ParallelAssemble();
|
||||
delete disGrad;
|
||||
|
||||
//setup the H1 preconditioner
|
||||
ParBilinearForm* H1Varf = new ParBilinearForm(H1FESpace);
|
||||
H1Varf->AddDomainIntegrator(new DiffusionIntegrator(*beta_));
|
||||
// H1Varf->AddDomainIntegrator(new MassIntegrator);
|
||||
H1Varf->Assemble();
|
||||
H1Varf->Finalize();
|
||||
|
||||
SparseMatrix &matH1(H1Varf->SpMat());
|
||||
for (int dof=0; dof<H1_essDof.Size(); dof++) if (H1_essDof[dof]<0) { matH1.EliminateRowCol(dof); }
|
||||
H1LaplaceMat = H1Varf->ParallelAssemble();
|
||||
delete H1Varf;
|
||||
amgH1 = new HypreBoomerAMG(*H1LaplaceMat);
|
||||
|
||||
|
||||
//setup the H1 injection
|
||||
FiniteElementCollection* fecH1Vec;
|
||||
if (orderIm==1) { fecH1Vec = new LinearFECollection; }
|
||||
else { fecH1Vec = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1VecFESpace = new ParFiniteElementSpace(pmesh, fecH1Vec,
|
||||
dim, Ordering::byVDIM);
|
||||
Array<int> H1Vec_essDof(H1VecFESpace->GetVSize()); H1Vec_essDof = 0;
|
||||
H1VecFESpace->GetEssentialVDofs(essBnd, H1Vec_essDof);
|
||||
|
||||
//setup the discrete gradient
|
||||
ParDiscreteLinearOperator *disInterpol = new ParDiscreteLinearOperator(
|
||||
H1VecFESpace, fespace);
|
||||
disInterpol->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpol->Assemble();
|
||||
disInterpol->Finalize();
|
||||
SparseMatrix* smatID = &(disInterpol->SpMat());
|
||||
smatID->EliminateCols(H1Vec_essDof);
|
||||
for (int dof=0; dof<HCurl_essDof.Size(); dof++) if (HCurl_essDof[dof]<0) { smatID->EliminateRow(dof); }
|
||||
idMat = disInterpol->ParallelAssemble();
|
||||
delete disInterpol;
|
||||
|
||||
//setup the H1-vec preconditioner
|
||||
ParBilinearForm* H1VecVarf = new ParBilinearForm(H1VecFESpace);
|
||||
H1VecVarf->AddDomainIntegrator(new VectorDiffusionIntegrator(*alpha_));
|
||||
H1VecVarf->AddDomainIntegrator(new VectorMassIntegrator(*neg_beta_));
|
||||
H1VecVarf->Assemble();
|
||||
H1VecVarf->Finalize();
|
||||
|
||||
SparseMatrix &matH1Vec(H1VecVarf->SpMat());
|
||||
for (int dof=0; dof<H1Vec_essDof.Size(); dof++) if (H1Vec_essDof[dof]<0) { matH1Vec.EliminateRowCol(dof); }
|
||||
H1VecLaplaceMat = H1VecVarf->ParallelAssemble();
|
||||
delete H1VecVarf;
|
||||
amgVecH1 = new HypreBoomerAMG(*H1VecLaplaceMat);
|
||||
amgVecH1->SetSystemsOptions(dim);
|
||||
|
||||
|
||||
f = new Vector(fespace->GetTrueVSize());
|
||||
|
||||
fGrad = new Vector(H1FESpace->GetTrueVSize());
|
||||
uGrad = new Vector(H1FESpace->GetTrueVSize());
|
||||
|
||||
fH1Vec = new Vector(H1VecFESpace->GetTrueVSize());
|
||||
uH1Vec = new Vector(H1VecFESpace->GetTrueVSize());
|
||||
|
||||
|
||||
amgH1->Mult(*fGrad, *uGrad);
|
||||
amgVecH1->Mult(*fH1Vec, *uH1Vec);
|
||||
|
||||
pcgGrad = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgGrad->SetOperator(*H1LaplaceMat);
|
||||
pcgGrad->SetPreconditioner(*amgH1);
|
||||
pcgGrad->SetRelTol(1e-16);
|
||||
pcgGrad->SetMaxIter(100000000);
|
||||
pcgGrad->SetPrintLevel(-2);
|
||||
|
||||
pcgH1Vec = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgH1Vec->SetOperator(*H1VecLaplaceMat);
|
||||
pcgH1Vec->SetPreconditioner(*amgVecH1);
|
||||
pcgH1Vec->SetRelTol(1e-16);
|
||||
pcgH1Vec->SetMaxIter(100000000);
|
||||
pcgH1Vec->SetPrintLevel(-2);
|
||||
|
||||
delete H1FESpace; delete fecH1;
|
||||
delete H1VecFESpace; delete fecH1Vec;
|
||||
|
||||
}
|
||||
|
||||
void setExactSolve(bool exSol)
|
||||
{
|
||||
exactSolves = exSol;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
smoother->Mult(x,y);
|
||||
|
||||
idMat->MultTranspose(x,*fH1Vec);
|
||||
*uH1Vec = 0.0;
|
||||
if (exactSolves) { pcgH1Vec->Mult(*fH1Vec, *uH1Vec); }
|
||||
else { amgVecH1->Mult(*fH1Vec, *uH1Vec); }
|
||||
idMat->Mult(1.0, *uH1Vec, 1.0, y);
|
||||
|
||||
gradMat->MultTranspose(x,*fGrad);
|
||||
*uGrad = 0.0;
|
||||
if (exactSolves) { pcgGrad->Mult(*fGrad, *uGrad); }
|
||||
else { amgH1->Mult(*fGrad, *uGrad); }
|
||||
gradMat->Mult(1.0, *uGrad, 1.0, y);
|
||||
|
||||
}
|
||||
|
||||
virtual void SetOperator(const Operator &op) {};
|
||||
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
bool verbose = (myid==0);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/cube4d_96.MFEM";
|
||||
int order = 1;
|
||||
bool set_bc = true;
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
int sequ_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
double tol = 1e-6;
|
||||
double coeffWeight = 1.0;
|
||||
bool exactH1Solver = false;
|
||||
bool spe10Coeff = false;
|
||||
bool standardCG = true;
|
||||
|
||||
int NExpo = 8;
|
||||
int weightStart = -NExpo;
|
||||
int weightEnd = NExpo;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&sequ_ref_levels, "-sr", "--seqrefinement",
|
||||
"Number of sequential refinement steps.");
|
||||
args.AddOption(&par_ref_levels, "-pr", "--parrefinement",
|
||||
"Number of parallel refinement steps.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Polynomial order of the finite element space.");
|
||||
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
|
||||
"Impose or not essential boundary conditions.");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"A parameter.");
|
||||
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
|
||||
" solution.");
|
||||
args.AddOption(&coeffWeight, "-c", "--coeffMass",
|
||||
"the weight for the mass term.");
|
||||
args.AddOption(&exactH1Solver, "-exH1Sol", "--exactH1Solver", "-H1prec",
|
||||
"--H1preconditioner",
|
||||
"Use exact H1 solvers for the preconditioner.");
|
||||
args.AddOption(&spe10Coeff, "-spe10", "--useSPE10Coeff", "-constCoeff",
|
||||
"--constCoeff",
|
||||
"Switch between the coefficients for the mass bilinear form.");
|
||||
args.AddOption(&standardCG, "-sCG", "--stdCG", "-rCG", "--resCG",
|
||||
"Switch between standard PCG or recompute residuals in every step and use the residuals itself for the stopping criteria.");
|
||||
args.AddOption(&weightStart, "-ws", "--weightStart",
|
||||
"the exponent for the starting weight (for the mass term).");
|
||||
args.AddOption(&weightEnd, "-we", "--weightEnd",
|
||||
"the exponent for the weight at the end (for the mass term).");
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (verbose) { args.PrintOptions(cout); }
|
||||
|
||||
kappa = freq * M_PI;
|
||||
|
||||
Mesh *mesh;
|
||||
ifstream imesh(mesh_file);
|
||||
if (!imesh)
|
||||
{
|
||||
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
mesh = new Mesh(imesh, 1, 1);
|
||||
imesh.close();
|
||||
|
||||
dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
|
||||
if (dim !=4 || sdim != 4)
|
||||
{
|
||||
MPI_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<sequ_ref_levels; i++) { mesh->UniformRefinement(); }
|
||||
if (verbose) { mesh->PrintCharacteristics(); }
|
||||
|
||||
if (verbose) { cout << "now we partition the mesh..." << endl << endl; }
|
||||
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
|
||||
for (int i=0; i<par_ref_levels; i++) { pmesh->UniformRefinement(); }
|
||||
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
pmesh->PrintInfo(std::cout);
|
||||
if (verbose) { cout << endl; }
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
FiniteElementCollection *fec;
|
||||
if (dim==4)
|
||||
{
|
||||
if (order==1) { fec = new ND1_4DFECollection; }
|
||||
else { fec = new ND2_4DFECollection; }
|
||||
}
|
||||
else { fec = new ND_FECollection(order, dim); }
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = set_bc ? 1 : 0;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (f,phi_i) where f is given by the function f_exact and phi_i are the
|
||||
// basis functions in the finite element fespace.
|
||||
|
||||
|
||||
// 9. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x by projecting the exact
|
||||
// solution. Note that only values from the boundary edges will be used
|
||||
// when eliminating the non-homogeneous boundary condition to modify the
|
||||
// r.h.s. vector b.
|
||||
ParGridFunction x(fespace);
|
||||
VectorFunctionCoefficient E(sdim, E_exact);
|
||||
|
||||
for (int expo=weightStart; expo<=weightEnd; expo++)
|
||||
{
|
||||
double weight = pow(10.0,expo);
|
||||
kappa = weight;
|
||||
|
||||
VectorFunctionCoefficient f(sdim, f_exact);
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
|
||||
b->Assemble();
|
||||
|
||||
x.ProjectCoefficient(E);
|
||||
|
||||
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
|
||||
// operator curl muinv curl + sigma I, by adding the curl-curl and the
|
||||
// mass domain integrators.
|
||||
// std::string permFile = "spe_perm.dat";
|
||||
// InversePermeabilityFunction::ReadPermeabilityFile(permFile, MPI_COMM_WORLD);
|
||||
|
||||
Coefficient *alpha = new ConstantCoefficient(1.0);
|
||||
Coefficient *beta;
|
||||
// if(spe10Coeff) beta = new FunctionCoefficient(InversePermeabilityFunction::Norm2Permeability);
|
||||
// else
|
||||
beta = new ConstantCoefficient(weight);
|
||||
Coefficient *neg_beta = new ConstantCoefficient(-weight);
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new CurlCurlIntegrator(*alpha));
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
|
||||
}
|
||||
|
||||
// 12. Define and apply a parallel PCG solver for AX=B with the AMS
|
||||
// preconditioner from hypre.
|
||||
ParFiniteElementSpace *prec_fespace =
|
||||
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
|
||||
Solver *prec;
|
||||
if (dim<=3) { prec = new HypreAMS(A, prec_fespace); }
|
||||
else if (dim==4) { prec = new Curl4dPrec(&A, fespace, alpha, beta, neg_beta, ess_bdr, order, false); }
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(A);
|
||||
pcg->SetRelTol(tol);
|
||||
pcg->SetMaxIter(5000);
|
||||
pcg->SetPrintLevel(1);
|
||||
pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
int iter = pcg->GetNumIterations();
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Weigth: " << weight << " " << iter << endl;
|
||||
|
||||
int *iters = LoadIterations(10, 2*NExpo+1);
|
||||
putIterationsInArray(iter, sequ_ref_levels+par_ref_levels, expo+NExpo,
|
||||
2*NExpo+1, iters);
|
||||
WriteIterations(iters, 10, 2*NExpo+1);
|
||||
}
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 14. Compute and print the L^2 norm of the error.
|
||||
{
|
||||
double err = x.ComputeL2Error(E);
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "\n|| E_h - E ||_{L^2} = " << err << '\n' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
// {
|
||||
// ostringstream mesh_name, sol_name;
|
||||
// mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
// sol_name << "sol." << setfill('0') << setw(6) << myid;
|
||||
//
|
||||
// ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
// mesh_ofs.precision(8);
|
||||
// pmesh->Print(mesh_ofs);
|
||||
//
|
||||
// ofstream sol_ofs(sol_name.str().c_str());
|
||||
// sol_ofs.precision(8);
|
||||
// x.Save(sol_ofs);
|
||||
// }
|
||||
|
||||
// // 16. Send the solution by socket to a GLVis server.
|
||||
// if (visualization)
|
||||
// {
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock(vishost, visport);
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock.precision(8);
|
||||
// sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
// }
|
||||
|
||||
delete pcg;
|
||||
delete prec;
|
||||
delete a;
|
||||
delete alpha;
|
||||
delete beta;
|
||||
delete b;
|
||||
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void E_exact(const Vector &x, Vector &E)
|
||||
{
|
||||
if (dim==4)
|
||||
{
|
||||
E(0) = sin(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(1) = -cos(M_PI*x(0))*sin(M_PI*x(1))*cos(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(2) = cos(M_PI*x(0))*cos(M_PI*x(1))*sin(M_PI*x(2))*cos(M_PI*x(3));
|
||||
E(3) = -cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*sin(M_PI*x(3));
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(2));
|
||||
E(2) = sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
E(0) = sin(kappa * x(1));
|
||||
E(1) = sin(kappa * x(0));
|
||||
if (x.Size() == 3) { E(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
|
||||
void f_exact(const Vector &x, Vector &f)
|
||||
{
|
||||
//f_exact = E + DivSkew P( curl E ), where P is the 4d permutation operator
|
||||
if (dim==4)
|
||||
{
|
||||
f(0) = (kappa+4.0*M_PI*M_PI)*sin(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(1) = -(kappa+4.0*M_PI*M_PI)*cos(M_PI*x(0))*sin(M_PI*x(1))*cos(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(2) = (kappa+4.0*M_PI*M_PI)*cos(M_PI*x(0))*cos(M_PI*x(1))*sin(M_PI*x(2))*cos(
|
||||
M_PI*x(3));
|
||||
f(3) = -(kappa+4.0*M_PI*M_PI)*cos(M_PI*x(0))*cos(M_PI*x(1))*cos(M_PI*x(2))*sin(
|
||||
M_PI*x(3));
|
||||
}
|
||||
else if (dim == 3)
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(2));
|
||||
f(2) = (1. + kappa * kappa) * sin(kappa * x(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
f(0) = (1. + kappa * kappa) * sin(kappa * x(1));
|
||||
f(1) = (1. + kappa * kappa) * sin(kappa * x(0));
|
||||
if (x.Size() == 3) { f(2) = 0.0; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,782 @@
|
||||
// MFEM Example 3 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex3p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex3p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/escher.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q2.vtk
|
||||
// mpirun -np 4 ex3p -m ../data/fichera-q3.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/square-disc-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/beam-hex-nurbs.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/amr-quad.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/amr-hex.mesh
|
||||
// mpirun -np 4 ex3p -m ../data/star-surf.mesh -o 2
|
||||
// mpirun -np 4 ex3p -m ../data/mobius-strip.mesh -o 2 -f 0.1
|
||||
// mpirun -np 4 ex3p -m ../data/klein-bottle.mesh -o 2 -f 0.1
|
||||
//
|
||||
// Description: This example code solves a simple electromagnetic diffusion
|
||||
// problem corresponding to the second order definite Maxwell
|
||||
// equation curl curl E + E = f with boundary condition
|
||||
// E x n = <given tangential field>. Here, we use a given exact
|
||||
// solution E and compute the corresponding r.h.s. f.
|
||||
// We discretize with Nedelec finite elements in 2D or 3D.
|
||||
//
|
||||
// The example demonstrates the use of H(curl) finite element
|
||||
// spaces with the curl-curl and the (vector finite element) mass
|
||||
// bilinear form, as well as the computation of discretization
|
||||
// error when the exact solution is known. Static condensation is
|
||||
// also illustrated.
|
||||
//
|
||||
// We recommend viewing examples 1-2 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "./spe10_coeff.cpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
int* LoadIterations(int NRows, int NCol)
|
||||
{
|
||||
ifstream in("iter_DivSkew.txt");
|
||||
|
||||
//initialize
|
||||
int *iters = new int[NCol*NRows];
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
iters[row*NCol+col] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
return iters;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
if (in.eof())
|
||||
{
|
||||
in.close();
|
||||
return iters;
|
||||
}
|
||||
in >> iters[row*NCol+col];
|
||||
}
|
||||
|
||||
in.close();
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
void putIterationsInArray(int iter, int row, int col, int NCol, int* iters)
|
||||
{
|
||||
iters[row*NCol+col] = iter;
|
||||
}
|
||||
|
||||
void WriteIterations(int *iters, int NRows, int NCol)
|
||||
{
|
||||
ofstream out;
|
||||
out.open("iter_DivSkew.txt",fstream::out);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
delete[] iters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
out << iters[row*NCol+col] << "\t";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
|
||||
delete[] iters;
|
||||
}
|
||||
|
||||
|
||||
// Exact solution, E, and r.h.s., f. See below for implementation.
|
||||
void E_exact_vec(const Vector &x, Vector &E);
|
||||
void E_exact(const Vector &, DenseMatrix &);
|
||||
void f_exact(const Vector &, DenseMatrix &);
|
||||
|
||||
|
||||
class DivSkew4dPrec : public Solver
|
||||
{
|
||||
|
||||
private:
|
||||
HypreParMatrix *A;
|
||||
ParFiniteElementSpace *fespace;
|
||||
Coefficient *alpha_, *beta_;
|
||||
|
||||
//kernel operators
|
||||
HypreParMatrix *P_d_HCurl_HDivSkew;
|
||||
|
||||
|
||||
HypreParMatrix *P_H1_HCurl;
|
||||
HypreParMatrix *H1_KernelMat;
|
||||
HypreBoomerAMG *amgH1_Kernel;
|
||||
|
||||
//"image" operators
|
||||
HypreParMatrix *P_H1_HDivSkew;
|
||||
HypreParMatrix *H1_ImageMat;
|
||||
HypreBoomerAMG *amgH1_Image;
|
||||
|
||||
|
||||
HypreParMatrix *HCurlMat;
|
||||
HypreSmoother * smootherDivSkew;
|
||||
HypreSmoother * smootherCurl;
|
||||
|
||||
CGSolver *pcgKernel;
|
||||
CGSolver *pcgImage;
|
||||
|
||||
Vector *f;
|
||||
Vector *fKernel, *uKernel;
|
||||
Vector *fImage, *uImage;
|
||||
Vector *fCurl, *uCurl;
|
||||
|
||||
bool exactSolves;
|
||||
|
||||
FiniteElementCollection* fecHCurlKernel;
|
||||
ParFiniteElementSpace *HCurlKernelFESpace;
|
||||
|
||||
|
||||
public:
|
||||
~DivSkew4dPrec()
|
||||
{
|
||||
delete pcgImage, pcgKernel;
|
||||
|
||||
delete f, fKernel, uKernel, fImage, uImage, fCurl, uCurl;
|
||||
|
||||
delete smootherCurl, HCurlMat;
|
||||
|
||||
delete P_d_HCurl_HDivSkew, P_H1_HDivSkew, P_H1_HCurl;
|
||||
|
||||
delete amgH1_Image, H1_ImageMat;
|
||||
delete amgH1_Kernel, H1_KernelMat;
|
||||
|
||||
delete smootherDivSkew;
|
||||
|
||||
delete HCurlKernelFESpace, fecHCurlKernel;
|
||||
}
|
||||
DivSkew4dPrec(HypreParMatrix *AUser, ParFiniteElementSpace *fespaceUser,
|
||||
Coefficient *alpha, Coefficient *beta,
|
||||
const Array<int> &essBnd, int orderKernel=1, bool exactSolvesUser=false)
|
||||
{
|
||||
A = AUser;
|
||||
fespace = fespaceUser;
|
||||
alpha_ = alpha;
|
||||
beta_ = beta;
|
||||
|
||||
ParMesh *pmesh = fespace->GetParMesh();
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
exactSolves = exactSolvesUser;
|
||||
|
||||
int orderIm=1; //H1 --> H(divSkew)
|
||||
int orderKer=orderKernel; //curl V --> H(divSkew)
|
||||
|
||||
smootherDivSkew = new HypreSmoother(*A, 16, 3);
|
||||
|
||||
Array<int> HDivSkew_essDof(fespace->GetVSize()); HDivSkew_essDof = 0;
|
||||
fespace->GetEssentialVDofs(essBnd, HDivSkew_essDof);
|
||||
|
||||
//setup the H1 FESpace for the kernel
|
||||
FiniteElementCollection* fecH1Kernel = new H1_FECollection(orderKer, 4);
|
||||
|
||||
ParFiniteElementSpace *H1KernelFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecH1Kernel, dim, Ordering::byVDIM);
|
||||
Array<int> H1Kernel_essDof(H1KernelFESpace->GetVSize()); H1Kernel_essDof = 0;
|
||||
H1KernelFESpace->GetEssentialVDofs(essBnd, H1Kernel_essDof);
|
||||
|
||||
|
||||
//setup the H(curl) FESpace for the kernel
|
||||
if (orderKer==1) { fecHCurlKernel = new ND1_4DFECollection; }
|
||||
else { fecHCurlKernel = new ND2_4DFECollection; }
|
||||
|
||||
HCurlKernelFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecHCurlKernel);
|
||||
Array<int> HCurlKernel_essDof(HCurlKernelFESpace->GetVSize());
|
||||
HCurlKernel_essDof = 0;
|
||||
HCurlKernelFESpace->GetEssentialVDofs(essBnd, HCurlKernel_essDof);
|
||||
|
||||
|
||||
//setup the FESpace for the H1 injection
|
||||
FiniteElementCollection* fecH1Vec;
|
||||
if (orderIm==1) { fecH1Vec = new LinearFECollection; }
|
||||
else { fecH1Vec = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1_ImageFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecH1Vec, 6, Ordering::byVDIM);
|
||||
Array<int> H1Image_essDof(H1_ImageFESpace->GetVSize()); H1Image_essDof = 0;
|
||||
H1_ImageFESpace->GetEssentialVDofs(essBnd, H1Image_essDof);
|
||||
|
||||
|
||||
|
||||
//setup the H1 preconditioner for the kernel
|
||||
ParBilinearForm* H1Varf = new ParBilinearForm(H1KernelFESpace);
|
||||
H1Varf->AddDomainIntegrator(new VectorDiffusionIntegrator(*beta_));
|
||||
// H1Varf->AddDomainIntegrator(new VectorMassIntegrator);
|
||||
H1Varf->Assemble();
|
||||
H1Varf->Finalize();
|
||||
SparseMatrix &matH1(H1Varf->SpMat());
|
||||
for (int dof = 0; dof < H1Kernel_essDof.Size(); dof++)
|
||||
if (H1Kernel_essDof[dof] < 0)
|
||||
{
|
||||
matH1.EliminateRowCol(dof);
|
||||
}
|
||||
H1_KernelMat = H1Varf->ParallelAssemble();
|
||||
delete H1Varf;
|
||||
amgH1_Kernel = new HypreBoomerAMG(*H1_KernelMat);
|
||||
amgH1_Kernel->SetSystemsOptions(dim);
|
||||
amgH1_Kernel->SetPrintLevel(0);
|
||||
|
||||
//setup the H1 preconditioner for the image
|
||||
ParBilinearForm* H1VecVarf = new ParBilinearForm(H1_ImageFESpace);
|
||||
VectorDiffusionIntegrator *alpha_integ = new VectorDiffusionIntegrator(*alpha_);
|
||||
alpha_integ->SetVDim(6);
|
||||
H1VecVarf->AddDomainIntegrator(alpha_integ);
|
||||
VectorMassIntegrator *beta_integ = new VectorMassIntegrator(*beta);
|
||||
beta_integ->SetVDim(6);
|
||||
H1VecVarf->AddDomainIntegrator(beta_integ);
|
||||
H1VecVarf->Assemble();
|
||||
H1VecVarf->Finalize();
|
||||
SparseMatrix &matH1Vec(H1VecVarf->SpMat());
|
||||
for (int dof=0; dof<H1Image_essDof.Size(); dof++) if (H1Image_essDof[dof]<0) { matH1Vec.EliminateRowCol(dof); }
|
||||
H1_ImageMat = H1VecVarf->ParallelAssemble();
|
||||
delete H1VecVarf;
|
||||
amgH1_Image = new HypreBoomerAMG(*H1_ImageMat);
|
||||
amgH1_Image->SetSystemsOptions(6);
|
||||
amgH1_Image->SetPrintLevel(0);
|
||||
|
||||
|
||||
//setup the injection of H1 into H(curl)
|
||||
ParDiscreteLinearOperator *disInterpol = new ParDiscreteLinearOperator(
|
||||
H1KernelFESpace, HCurlKernelFESpace);
|
||||
disInterpol->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpol->Assemble();
|
||||
disInterpol->Finalize();
|
||||
SparseMatrix* smatID = &(disInterpol->SpMat());
|
||||
smatID->EliminateCols(H1Kernel_essDof);
|
||||
for (int dof=0; dof<HCurlKernel_essDof.Size();
|
||||
dof++) if (HCurlKernel_essDof[dof]<0) { smatID->EliminateRow(dof); }
|
||||
P_H1_HCurl = disInterpol->ParallelAssemble();
|
||||
delete disInterpol;
|
||||
|
||||
//setup the injection of H1 into H(DivSkew)
|
||||
ParDiscreteLinearOperator *disInterpolIm = new ParDiscreteLinearOperator(
|
||||
H1_ImageFESpace, fespace);
|
||||
disInterpolIm->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpolIm->Assemble();
|
||||
disInterpolIm->Finalize();
|
||||
SparseMatrix* smatIDIm = &(disInterpolIm->SpMat());
|
||||
smatIDIm->EliminateCols(H1Image_essDof);
|
||||
for (int dof=0; dof<HDivSkew_essDof.Size(); dof++) if (HDivSkew_essDof[dof]<0) { smatIDIm->EliminateRow(dof); }
|
||||
P_H1_HDivSkew = disInterpolIm->ParallelAssemble();
|
||||
delete disInterpolIm;
|
||||
|
||||
|
||||
//setup the injection of the curl(H(curl)) into H(DivSkew)
|
||||
ParDiscreteLinearOperator *disCurl = new ParDiscreteLinearOperator(
|
||||
HCurlKernelFESpace, fespace);
|
||||
disCurl->AddDomainInterpolator(new CurlInterpolator);
|
||||
disCurl->Assemble();
|
||||
disCurl->Finalize();
|
||||
SparseMatrix* smatCurl = &(disCurl->SpMat());
|
||||
smatCurl->EliminateCols(HCurlKernel_essDof);
|
||||
for (int dof=0; dof<HDivSkew_essDof.Size(); dof++) if (HDivSkew_essDof[dof]<0) { smatCurl->EliminateRow(dof); }
|
||||
P_d_HCurl_HDivSkew = disCurl->ParallelAssemble();
|
||||
delete disCurl;
|
||||
|
||||
//setup the smoother for H(curl)
|
||||
// Coefficient *massC = new ConstantCoefficient(1.0);
|
||||
// Coefficient *CurlCurlC = new ConstantCoefficient(1.0);
|
||||
ParBilinearForm *a_HCurl = new ParBilinearForm(HCurlKernelFESpace);
|
||||
a_HCurl->AddDomainIntegrator(new CurlCurlIntegrator(*beta_));
|
||||
// a_HCurl->AddDomainIntegrator(new CurlCurlIntegrator(*CurlCurlC));
|
||||
// a_HCurl->AddDomainIntegrator(new VectorFEMassIntegrator(*massC));
|
||||
a_HCurl->Assemble();
|
||||
a_HCurl->Finalize();
|
||||
SparseMatrix &matHCurl(a_HCurl->SpMat());
|
||||
for (int dof=0; dof<HCurlKernel_essDof.Size();
|
||||
dof++) if (HCurlKernel_essDof[dof]<0) { matHCurl.EliminateRowCol(dof); }
|
||||
HCurlMat = a_HCurl->ParallelAssemble();
|
||||
delete a_HCurl;
|
||||
smootherCurl = new HypreSmoother(*HCurlMat, 16, 3);
|
||||
|
||||
f = new Vector(fespace->GetTrueVSize());
|
||||
|
||||
fKernel = new Vector(H1KernelFESpace->GetTrueVSize());
|
||||
uKernel = new Vector(H1KernelFESpace->GetTrueVSize());
|
||||
|
||||
fImage = new Vector(H1_ImageFESpace->GetTrueVSize());
|
||||
uImage = new Vector(H1_ImageFESpace->GetTrueVSize());
|
||||
|
||||
fCurl = new Vector(HCurlKernelFESpace->GetTrueVSize());
|
||||
uCurl = new Vector(HCurlKernelFESpace->GetTrueVSize());
|
||||
|
||||
|
||||
amgH1_Kernel->Mult(*fKernel, *uKernel);
|
||||
amgH1_Image->Mult(*fImage, *uImage);
|
||||
|
||||
pcgKernel = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgKernel->SetOperator(*H1_KernelMat);
|
||||
pcgKernel->SetPreconditioner(*amgH1_Kernel);
|
||||
pcgKernel->SetRelTol(1e-16);
|
||||
pcgKernel->SetMaxIter(100000000);
|
||||
pcgKernel->SetPrintLevel(-2);
|
||||
|
||||
pcgImage = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgImage->SetOperator(*H1_ImageMat);
|
||||
pcgImage->SetPreconditioner(*amgH1_Image);
|
||||
pcgImage->SetRelTol(1e-16);
|
||||
pcgImage->SetMaxIter(100000000);
|
||||
pcgImage->SetPrintLevel(-2);
|
||||
|
||||
delete H1KernelFESpace, fecH1Kernel;
|
||||
delete H1_ImageFESpace, fecH1Vec;
|
||||
}
|
||||
|
||||
void setExactSolve(bool exSol)
|
||||
{
|
||||
exactSolves = exSol;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
smootherDivSkew->Mult(x,y);
|
||||
|
||||
P_H1_HDivSkew->MultTranspose(x,*fImage);
|
||||
*uImage = 0.0;
|
||||
if (exactSolves) { pcgImage->Mult(*fImage, *uImage); }
|
||||
else { amgH1_Image->Mult(*fImage, *uImage); }
|
||||
P_H1_HDivSkew->Mult(1.0, *uImage, 1.0, y);
|
||||
|
||||
*uCurl = 0.0;
|
||||
P_d_HCurl_HDivSkew->MultTranspose(x,*fCurl);
|
||||
|
||||
smootherCurl->Mult(*fCurl, *uCurl);
|
||||
|
||||
P_H1_HCurl->MultTranspose(*fCurl,*fKernel);
|
||||
*uKernel = 0.0;
|
||||
if (exactSolves) { pcgKernel->Mult(*fKernel, *uKernel); }
|
||||
else { amgH1_Kernel->Mult(*fKernel, *uKernel); }
|
||||
P_H1_HCurl->Mult(1.0, *uKernel, 1.0, *uCurl);
|
||||
|
||||
P_d_HCurl_HDivSkew->Mult(1.0, *uCurl, 1.0, y);
|
||||
}
|
||||
|
||||
virtual void SetOperator(const Operator &op) {};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
bool verbose = (myid==0);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/cube4d_96.MFEM";
|
||||
int order = 1;
|
||||
bool set_bc = true;
|
||||
bool static_cond = false;
|
||||
bool visualization = 1;
|
||||
int sequ_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
double tol = 1e-6;
|
||||
double coeffWeight = 1.0;
|
||||
bool exactH1Solver = false;
|
||||
bool spe10Coeff = false;
|
||||
bool standardCG = true;
|
||||
|
||||
int NExpo = 8;
|
||||
int weightStart = -NExpo;
|
||||
int weightEnd = NExpo;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&sequ_ref_levels, "-sr", "--seqrefinement",
|
||||
"Number of sequential refinement steps.");
|
||||
args.AddOption(&par_ref_levels, "-pr", "--parrefinement",
|
||||
"Number of parallel refinement steps.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Polynomial order of the finite element space.");
|
||||
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
|
||||
"Impose or not essential boundary conditions.");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"A parameter.");
|
||||
args.AddOption(&coeffWeight, "-c", "--coeffMass",
|
||||
"the weight for the mass term.");
|
||||
args.AddOption(&exactH1Solver, "-exH1Sol", "--exactH1Solver", "-H1prec",
|
||||
"--H1preconditioner",
|
||||
"Use exact H1 solvers for the preconditioner.");
|
||||
args.AddOption(&spe10Coeff, "-spe10", "--useSPE10Coeff", "-constCoeff",
|
||||
"--constCoeff",
|
||||
"Switch between the coefficients for the mass bilinear form.");
|
||||
args.AddOption(&standardCG, "-sCG", "--stdCG", "-rCG", "--resCG",
|
||||
"Switch between standard PCG or recompute residuals in every step and use the residuals itself for the stopping criteria.");
|
||||
args.AddOption(&weightStart, "-ws", "--weightStart",
|
||||
"the exponent for the starting weight (for the mass term).");
|
||||
args.AddOption(&weightEnd, "-we", "--weightEnd",
|
||||
"the exponent for the weight at the end (for the mass term).");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
return 1;
|
||||
}
|
||||
if (verbose) { args.PrintOptions(cout); }
|
||||
|
||||
Mesh *mesh;
|
||||
ifstream imesh(mesh_file);
|
||||
if (!imesh)
|
||||
{
|
||||
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
mesh = new Mesh(imesh, 1, 1);
|
||||
imesh.close();
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
if (dim !=4 || sdim != 4)
|
||||
{
|
||||
MPI_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<sequ_ref_levels; i++) { mesh->UniformRefinement(); }
|
||||
if (verbose) { mesh->PrintCharacteristics(); }
|
||||
|
||||
if (verbose) { cout << "now we partition the mesh..." << endl << endl; }
|
||||
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
|
||||
for (int i=0; i<par_ref_levels; i++) { pmesh->UniformRefinement(); }
|
||||
|
||||
pmesh->PrintInfo(std::cout);
|
||||
if (verbose) { cout << endl; }
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Nedelec finite elements of the specified order.
|
||||
FiniteElementCollection *fec;
|
||||
if (order==1) { fec = new DivSkew1_4DFECollection; }
|
||||
// else fec = new F2K1_4DFECollection;
|
||||
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
fespace->SetUpdateOperatorType(Operator::Hypre_ParCSR);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = set_bc ? 1 : 0;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
|
||||
}
|
||||
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (f,phi_i) where f is given by the function f_exact and phi_i are the
|
||||
// basis functions in the finite element fespace.
|
||||
MatrixFunctionCoefficient f(sdim, f_exact);
|
||||
MatrixFunctionCoefficient solMat(sdim, E_exact);
|
||||
VectorFunctionCoefficient solVec(6, E_exact_vec);
|
||||
|
||||
|
||||
|
||||
|
||||
// 9. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x by projecting the exact
|
||||
// solution. Note that only values from the boundary edges will be used
|
||||
// when eliminating the non-homogeneous boundary condition to modify the
|
||||
// r.h.s. vector b.
|
||||
ParGridFunction x(fespace);
|
||||
|
||||
for (int expo=weightStart; expo<=weightEnd; expo++)
|
||||
{
|
||||
double weight = pow(10.0,expo);
|
||||
|
||||
x.ProjectCoefficient(solVec);
|
||||
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
b->AddDomainIntegrator(new MatFEDomainLFIntegrator(f));
|
||||
b->Assemble();
|
||||
|
||||
// cout << x << endl;
|
||||
// x = 0.0;
|
||||
|
||||
// 10. Set up the parallel bilinear form corresponding to the EM diffusion
|
||||
// operator curl muinv curl + sigma I, by adding the curl-curl and the
|
||||
// mass domain integrators.
|
||||
// std::string permFile = "spe_perm.dat";
|
||||
// InversePermeabilityFunction::ReadPermeabilityFile(permFile, MPI_COMM_WORLD);
|
||||
|
||||
Coefficient *alpha = new ConstantCoefficient(1.0);
|
||||
Coefficient *beta;
|
||||
// if(spe10Coeff) beta = new FunctionCoefficient(InversePermeabilityFunction::Norm2Permeability);
|
||||
// else
|
||||
beta = new ConstantCoefficient(weight);
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DivSkewDivSkewIntegrator(*alpha));
|
||||
a->AddDomainIntegrator(new VectorFE_DivSkewMassIntegrator(*beta));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation, etc.
|
||||
if (static_cond) { a->EnableStaticCondensation(); }
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << A.GetGlobalNumRows() << endl;
|
||||
}
|
||||
|
||||
//Define the preconditioner
|
||||
|
||||
if (myid == 0) { cout << "Set up the preconditioner" << endl; }
|
||||
Solver *prec;
|
||||
if (dim==4) { prec = new DivSkew4dPrec(&A, fespace, alpha, beta, ess_bdr, order, exactH1Solver); }
|
||||
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(A);
|
||||
pcg->SetRelTol(tol);
|
||||
pcg->SetMaxIter(500);
|
||||
pcg->SetPrintLevel(1);
|
||||
pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
delete prec;
|
||||
|
||||
int iter = pcg->GetNumIterations();
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Weigth: " << weight << " " << iter << endl;
|
||||
|
||||
int *iters = LoadIterations(10, 2*NExpo+1);
|
||||
putIterationsInArray(iter, sequ_ref_levels+par_ref_levels, expo+NExpo,
|
||||
2*NExpo+1, iters);
|
||||
WriteIterations(iters, 10, 2*NExpo+1);
|
||||
}
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 14. Compute and print the L^2 norm of the error.
|
||||
{
|
||||
double error = 0.0;
|
||||
for (int i = 0; i < fespace->GetNE(); i++)
|
||||
{
|
||||
const FiniteElement* fe = fespace->GetFE(i);
|
||||
int fdof = fe->GetDof();
|
||||
ElementTransformation* transf = fespace->GetElementTransformation(i);
|
||||
DenseMatrix shape(fdof,dim*dim);
|
||||
|
||||
int intorder = 2*fe->GetOrder() + 1; // <----------
|
||||
const IntegrationRule *ir;
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
|
||||
Vector elSol(dim*dim);
|
||||
DenseMatrix elSolMat(dim,dim);
|
||||
DenseMatrix exactSol(dim,dim);
|
||||
Vector exactSolVec(dim*dim);
|
||||
|
||||
|
||||
|
||||
Array<int> vdofs;
|
||||
fespace->GetElementVDofs(i, vdofs);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
|
||||
fe->CalcVShape(*transf, shape);
|
||||
|
||||
elSol = 0.0;
|
||||
for (int k = 0; k < fdof; k++)
|
||||
{
|
||||
if (vdofs[k] >= 0)
|
||||
{
|
||||
for (int l=0; l<dim*dim; l++) { elSol(l) += shape(k,l)*x(vdofs[k]); }
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int l=0; l<dim*dim; l++) { elSol(l) -= shape(k,l)*x(-1-vdofs[k]); }
|
||||
}
|
||||
}
|
||||
for (int k=0; k<dim; k++)
|
||||
for (int l=0; l<dim; l++)
|
||||
{
|
||||
elSolMat(k,l) = elSol(dim*k+l);
|
||||
}
|
||||
|
||||
|
||||
solMat.Eval(exactSol,*transf, ip);
|
||||
for (int k=0; k<dim; k++)
|
||||
for (int l=0; l<dim; l++)
|
||||
{
|
||||
exactSolVec(dim*k+l) = exactSol(k,l);
|
||||
}
|
||||
elSol.Add(-1.0, exactSolVec);
|
||||
|
||||
error += ip.weight * fabs(transf->Weight()) * (elSol * elSol);
|
||||
}
|
||||
}
|
||||
double globalError = 0.0;
|
||||
MPI_Allreduce(&error, &globalError, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
|
||||
if (myid==0) { std::cout << "L2 error: " << sqrt(globalError) << std::endl; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
delete pcg;
|
||||
delete a;
|
||||
delete alpha;
|
||||
delete beta;
|
||||
|
||||
delete b;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
|
||||
|
||||
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void E_exact_vec(const Vector &x, Vector &E)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
E.SetSize(6);
|
||||
|
||||
double s0 = sin(M_PI*x(0)), s1 = sin(M_PI*x(1)), s2 = sin(M_PI*x(2)),
|
||||
s3 = sin(M_PI*x(3));
|
||||
double c0 = cos(M_PI*x(0)), c1 = cos(M_PI*x(1)), c2 = cos(M_PI*x(2)),
|
||||
c3 = cos(M_PI*x(3));
|
||||
|
||||
E(0) = c0*c1*s2*s3;
|
||||
E(1) = -c0*s1*c2*s3;
|
||||
E(2) = c0*s1*s2*c3;
|
||||
E(3) = s0*c1*c2*s3;
|
||||
E(4) = -s0*c1*s2*c3;
|
||||
E(5) = s0*s1*c2*c3;
|
||||
}
|
||||
}
|
||||
|
||||
void E_exact(const Vector &x, DenseMatrix &E)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
E.SetSize(dim*dim);
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
Vector vecE; E_exact_vec(x, vecE);
|
||||
|
||||
E = 0.0;
|
||||
|
||||
E(0,1) = vecE(0);
|
||||
E(0,2) = vecE(1);
|
||||
E(0,3) = vecE(2);
|
||||
E(1,2) = vecE(3);
|
||||
E(1,3) = vecE(4);
|
||||
E(2,3) = vecE(5);
|
||||
|
||||
E(1,0) = -E(0,1);
|
||||
E(2,0) = -E(0,2);
|
||||
E(3,0) = -E(0,3);
|
||||
E(2,1) = -E(1,2);
|
||||
E(3,1) = -E(1,3);
|
||||
E(3,2) = -E(2,3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//f_exact = E + 0.5 * P( curl DivSkew E ), where P is the 4d permutation operator
|
||||
void f_exact(const Vector &x, DenseMatrix &f)
|
||||
{
|
||||
int dim = x.Size();
|
||||
|
||||
f.SetSize(dim,dim);
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
f = 0.0;
|
||||
|
||||
double s0 = sin(M_PI*x(0)), s1 = sin(M_PI*x(1)), s2 = sin(M_PI*x(2)),
|
||||
s3 = sin(M_PI*x(3));
|
||||
double c0 = cos(M_PI*x(0)), c1 = cos(M_PI*x(1)), c2 = cos(M_PI*x(2)),
|
||||
c3 = cos(M_PI*x(3));
|
||||
|
||||
f(0,1) = (1.0 + 1.0 * M_PI*M_PI)*c0*c1*s2*s3;
|
||||
f(0,2) = -(1.0 + 0.0 * M_PI*M_PI)*c0*s1*c2*s3;
|
||||
f(0,3) = (1.0 + 1.0 * M_PI*M_PI)*c0*s1*s2*c3;
|
||||
f(1,2) = (1.0 - 1.0 * M_PI*M_PI)*s0*c1*c2*s3;
|
||||
f(1,3) = -(1.0 + 0.0 * M_PI*M_PI)*s0*c1*s2*c3;
|
||||
f(2,3) = (1.0 + 1.0 * M_PI*M_PI)*s0*s1*c2*c3;
|
||||
|
||||
f(1,0) = -f(0,1);
|
||||
f(2,0) = -f(0,2);
|
||||
f(3,0) = -f(0,3);
|
||||
f(2,1) = -f(1,2);
|
||||
f(3,1) = -f(1,3);
|
||||
f(3,2) = -f(2,3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,800 @@
|
||||
// MFEM Example 4 - Parallel Version
|
||||
//
|
||||
// Compile with: make ex4p
|
||||
//
|
||||
// Sample runs: mpirun -np 4 ex4p -m ../data/square-disc.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/star.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/beam-tet.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/beam-hex.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/escher.mesh -o 2 -sc
|
||||
// mpirun -np 4 ex4p -m ../data/fichera.mesh -o 2 -hb
|
||||
// mpirun -np 4 ex4p -m ../data/fichera-q2.vtk
|
||||
// mpirun -np 4 ex4p -m ../data/fichera-q3.mesh -o 2 -sc
|
||||
// mpirun -np 4 ex4p -m ../data/square-disc-nurbs.mesh -o 3
|
||||
// mpirun -np 4 ex4p -m ../data/beam-hex-nurbs.mesh -o 3
|
||||
// mpirun -np 4 ex4p -m ../data/periodic-square.mesh -no-bc
|
||||
// mpirun -np 4 ex4p -m ../data/periodic-cube.mesh -no-bc
|
||||
// mpirun -np 4 ex4p -m ../data/amr-quad.mesh
|
||||
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -sc
|
||||
// mpirun -np 4 ex4p -m ../data/amr-hex.mesh -o 2 -hb
|
||||
// mpirun -np 4 ex4p -m ../data/star-surf.mesh -o 3 -hb
|
||||
//
|
||||
// Description: This example code solves a simple 2D/3D H(div) diffusion
|
||||
// problem corresponding to the second order definite equation
|
||||
// -grad(alpha div F) + beta F = f with boundary condition F dot n
|
||||
// = <given normal field>. Here, we use a given exact solution F
|
||||
// and compute the corresponding r.h.s. f. We discretize with
|
||||
// Raviart-Thomas finite elements.
|
||||
//
|
||||
// The example demonstrates the use of H(div) finite element
|
||||
// spaces with the grad-div and H(div) vector finite element mass
|
||||
// bilinear form, as well as the computation of discretization
|
||||
// error when the exact solution is known. Bilinear form
|
||||
// hybridization and static condensation are also illustrated.
|
||||
//
|
||||
// We recommend viewing examples 1-3 before viewing this example.
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "./spe10_coeff.cpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
int* LoadIterations(int NRows, int NCol)
|
||||
{
|
||||
ifstream in("iter_div.txt");
|
||||
|
||||
//initialize
|
||||
int *iters = new int[NCol*NRows];
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
iters[row*NCol+col] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!in)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
return iters;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
if (in.eof())
|
||||
{
|
||||
in.close();
|
||||
return iters;
|
||||
}
|
||||
in >> iters[row*NCol+col];
|
||||
}
|
||||
|
||||
|
||||
in.close();
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
void putIterationsInArray(int iter, int row, int col, int NCol, int* iters)
|
||||
{
|
||||
iters[row*NCol+col] = iter;
|
||||
}
|
||||
|
||||
void WriteIterations(int *iters, int NRows, int NCol)
|
||||
{
|
||||
ofstream out;
|
||||
out.open("iter_div.txt",fstream::out);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
cout << "Cannot open file.\n";
|
||||
delete[] iters;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int row = 0; row < NRows; row++)
|
||||
{
|
||||
for (int col = 0; col < NCol; col++)
|
||||
{
|
||||
out << iters[row*NCol+col] << "\t";
|
||||
}
|
||||
out << endl;
|
||||
}
|
||||
out.close();
|
||||
|
||||
delete[] iters;
|
||||
}
|
||||
|
||||
|
||||
// Exact solution, F, and r.h.s., f. See below for implementation.
|
||||
void F_exact(const Vector &, Vector &);
|
||||
void f_exact(const Vector &, Vector &);
|
||||
double freq = 1.0, kappa;
|
||||
|
||||
|
||||
|
||||
class div4dPrec : public Solver
|
||||
{
|
||||
|
||||
private:
|
||||
HypreParMatrix *A;
|
||||
ParFiniteElementSpace *fespace;
|
||||
|
||||
Coefficient *alpha_, *beta_;
|
||||
|
||||
//kernel operators
|
||||
HypreParMatrix *P_d_HSkewDiv_Hdiv;
|
||||
|
||||
HypreParMatrix *P_H1_HDivSkew;
|
||||
HypreParMatrix *H1_KernelMat;
|
||||
HypreBoomerAMG *amgH1_Kernel;
|
||||
|
||||
//"image" operators
|
||||
HypreParMatrix *P_H1_Hdiv;
|
||||
HypreParMatrix *H1_ImageMat;
|
||||
HypreBoomerAMG *amgH1_Image;
|
||||
|
||||
HypreParMatrix *HDivSkewMat;
|
||||
HypreSmoother * smootherdiv;
|
||||
HypreSmoother * smootherDivSkew;
|
||||
|
||||
CGSolver *pcgKernel;
|
||||
CGSolver *pcgImage;
|
||||
|
||||
Vector *f;
|
||||
Vector *fKernel, *uKernel;
|
||||
Vector *fImage, *uImage;
|
||||
Vector *fDivSkew, *uDivSkew;
|
||||
|
||||
FiniteElementCollection* fecHDivSkewKernel;
|
||||
ParFiniteElementSpace *HDivSkewKernelFESpace;
|
||||
|
||||
bool exactSolves;
|
||||
|
||||
public:
|
||||
~div4dPrec()
|
||||
{
|
||||
delete pcgImage;
|
||||
delete pcgKernel;
|
||||
|
||||
delete uDivSkew, fDivSkew, uImage, fImage, uKernel, fKernel, f;
|
||||
|
||||
delete smootherDivSkew;
|
||||
delete HDivSkewMat;
|
||||
|
||||
delete P_d_HSkewDiv_Hdiv;
|
||||
delete P_H1_Hdiv;
|
||||
delete P_H1_HDivSkew;
|
||||
|
||||
delete amgH1_Image, H1_ImageMat;
|
||||
delete amgH1_Kernel, H1_KernelMat;
|
||||
|
||||
delete smootherdiv;
|
||||
|
||||
delete HDivSkewKernelFESpace;
|
||||
delete fecHDivSkewKernel;
|
||||
}
|
||||
div4dPrec(HypreParMatrix *AUser, ParFiniteElementSpace *fespaceUser,
|
||||
Coefficient *alpha, Coefficient *beta, const Array<int> &essBnd,
|
||||
int orderKernel=1, bool exactSolvesUser=false)
|
||||
{
|
||||
A = AUser;
|
||||
fespace = fespaceUser;
|
||||
alpha_ = alpha;
|
||||
beta_ = beta;
|
||||
|
||||
|
||||
ParMesh *pmesh = fespace->GetParMesh();
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
exactSolves = exactSolvesUser;
|
||||
|
||||
|
||||
|
||||
|
||||
int orderIm=1; //H1 --> H(div)
|
||||
int orderKer=orderKernel; //DivSkew V --> H(div)
|
||||
|
||||
|
||||
|
||||
smootherdiv = new HypreSmoother(*A, 16, 3);
|
||||
|
||||
Array<int> Hdiv_essDof(fespace->GetVSize()); Hdiv_essDof = 0;
|
||||
fespace->GetEssentialVDofs(essBnd, Hdiv_essDof);
|
||||
|
||||
|
||||
|
||||
|
||||
//setup the H1 FESpace for the kernel
|
||||
FiniteElementCollection* fecH1Kernel;
|
||||
if (orderKer==1) { fecH1Kernel = new LinearFECollection; }
|
||||
else { fecH1Kernel = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1KernelFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecH1Kernel, 6, Ordering::byVDIM);
|
||||
Array<int> H1Kernel_essDof(H1KernelFESpace->GetVSize()); H1Kernel_essDof = 0;
|
||||
H1KernelFESpace->GetEssentialVDofs(essBnd, H1Kernel_essDof);
|
||||
|
||||
|
||||
//setup the H(DivSkew) FESpace for the kernel
|
||||
if (orderKer==1) { fecHDivSkewKernel = new DivSkew1_4DFECollection; }
|
||||
// else fecHDivSkewKernel = new DivSkewFull1_4DFECollection;
|
||||
HDivSkewKernelFESpace = new ParFiniteElementSpace(pmesh, fecHDivSkewKernel);
|
||||
Array<int> HDivSkewKernel_essDof(HDivSkewKernelFESpace->GetVSize());
|
||||
HDivSkewKernel_essDof = 0;
|
||||
HDivSkewKernelFESpace->GetEssentialVDofs(essBnd, HDivSkewKernel_essDof);
|
||||
|
||||
|
||||
//setup the FESpace for the H1 injection
|
||||
FiniteElementCollection* fecH1Vec;
|
||||
if (orderIm==1) { fecH1Vec = new LinearFECollection; }
|
||||
else { fecH1Vec = new QuadraticFECollection; }
|
||||
ParFiniteElementSpace *H1_ImageFESpace = new ParFiniteElementSpace(pmesh,
|
||||
fecH1Vec, dim, Ordering::byVDIM);
|
||||
Array<int> H1Image_essDof(H1_ImageFESpace->GetVSize()); H1Image_essDof = 0;
|
||||
H1_ImageFESpace->GetEssentialVDofs(essBnd, H1Image_essDof);
|
||||
|
||||
|
||||
|
||||
//setup the H1 preconditioner for the kernel
|
||||
ParBilinearForm* H1Varf = new ParBilinearForm(H1KernelFESpace);
|
||||
// H1Varf->AddDomainIntegrator(new VectorDiffusionIntegrator(*alpha_, 6));
|
||||
// H1Varf->AddDomainIntegrator(new VectorMassIntegrator(6, beta_));
|
||||
|
||||
H1Varf->AddDomainIntegrator(new VectorDiffusionIntegrator(*beta_, 6));
|
||||
H1Varf->Assemble();
|
||||
H1Varf->Finalize();
|
||||
SparseMatrix &matH1(H1Varf->SpMat());
|
||||
for (int dof=0; dof<H1Kernel_essDof.Size(); dof++) if (H1Kernel_essDof[dof]<0) { matH1.EliminateRowCol(dof); }
|
||||
H1_KernelMat = H1Varf->ParallelAssemble();
|
||||
delete H1Varf;
|
||||
amgH1_Kernel = new HypreBoomerAMG(*H1_KernelMat);
|
||||
amgH1_Kernel->SetSystemsOptions(6);
|
||||
|
||||
//setup the H1 preconditioner for the image
|
||||
ParBilinearForm* H1VecVarf = new ParBilinearForm(H1_ImageFESpace);
|
||||
H1VecVarf->AddDomainIntegrator(new VectorDiffusionIntegrator(*alpha_));
|
||||
H1VecVarf->AddDomainIntegrator(new VectorMassIntegrator(-1, beta_));
|
||||
H1VecVarf->Assemble();
|
||||
H1VecVarf->Finalize();
|
||||
SparseMatrix &matH1Vec(H1VecVarf->SpMat());
|
||||
for (int dof=0; dof<H1Image_essDof.Size(); dof++) if (H1Image_essDof[dof]<0) { matH1Vec.EliminateRowCol(dof); }
|
||||
H1_ImageMat = H1VecVarf->ParallelAssemble();
|
||||
delete H1VecVarf;
|
||||
amgH1_Image = new HypreBoomerAMG(*H1_ImageMat);
|
||||
amgH1_Image->SetSystemsOptions(dim);
|
||||
|
||||
|
||||
//setup the injection of H1 into H(DivSkew)
|
||||
ParDiscreteLinearOperator *disInterpolIm = new ParDiscreteLinearOperator(
|
||||
H1KernelFESpace, HDivSkewKernelFESpace);
|
||||
disInterpolIm->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpolIm->Assemble();
|
||||
disInterpolIm->Finalize();
|
||||
SparseMatrix* smatIDIm = &(disInterpolIm->SpMat());
|
||||
smatIDIm->EliminateCols(H1Kernel_essDof);
|
||||
for (int dof=0; dof<HDivSkewKernel_essDof.Size();
|
||||
dof++) if (HDivSkewKernel_essDof[dof]<0) { smatIDIm->EliminateRow(dof); }
|
||||
P_H1_HDivSkew = disInterpolIm->ParallelAssemble();
|
||||
delete disInterpolIm;
|
||||
|
||||
//setup the injection of H1 into H(div)
|
||||
ParDiscreteLinearOperator *disInterpol = new ParDiscreteLinearOperator(
|
||||
H1_ImageFESpace, fespace);
|
||||
disInterpol->AddDomainInterpolator(new IdentityInterpolator);
|
||||
disInterpol->Assemble();
|
||||
disInterpol->Finalize();
|
||||
SparseMatrix* smatID = &(disInterpol->SpMat());
|
||||
smatID->EliminateCols(H1Image_essDof);
|
||||
for (int dof=0; dof<Hdiv_essDof.Size(); dof++) if (Hdiv_essDof[dof]<0) { smatID->EliminateRow(dof); }
|
||||
P_H1_Hdiv = disInterpol->ParallelAssemble();
|
||||
delete disInterpol;
|
||||
|
||||
|
||||
|
||||
|
||||
//setup the injection of the DivSkew(H(DivSkew)) into H(div)
|
||||
ParDiscreteLinearOperator *disDivSkew = new ParDiscreteLinearOperator(
|
||||
HDivSkewKernelFESpace, fespace);
|
||||
disDivSkew->AddDomainInterpolator(new DivSkewInterpolator);
|
||||
disDivSkew->Assemble();
|
||||
disDivSkew->Finalize();
|
||||
SparseMatrix* smatDivSkew= &(disDivSkew->SpMat());
|
||||
smatDivSkew->EliminateCols(HDivSkewKernel_essDof);
|
||||
for (int dof=0; dof<Hdiv_essDof.Size(); dof++) if (Hdiv_essDof[dof]<0) { smatDivSkew->EliminateRow(dof); }
|
||||
P_d_HSkewDiv_Hdiv = disDivSkew->ParallelAssemble();
|
||||
delete disDivSkew;
|
||||
|
||||
|
||||
//setup the smoother for H(DivSkew)
|
||||
ParBilinearForm *a_HDivSkew = new ParBilinearForm(HDivSkewKernelFESpace);
|
||||
// a_HDivSkew->AddDomainIntegrator(new DivSkewDivSkewIntegrator(*alpha_));
|
||||
// a_HDivSkew->AddDomainIntegrator(new VectorFE_DivSkewMassIntegrator(*beta_));
|
||||
|
||||
a_HDivSkew->AddDomainIntegrator(new DivSkewDivSkewIntegrator(*beta_));
|
||||
|
||||
a_HDivSkew->Assemble();
|
||||
a_HDivSkew->Finalize();
|
||||
SparseMatrix &matHDivSkew(a_HDivSkew->SpMat());
|
||||
for (int dof=0; dof<HDivSkewKernel_essDof.Size();
|
||||
dof++) if (HDivSkewKernel_essDof[dof]<0) { matHDivSkew.EliminateRowCol(dof); }
|
||||
HDivSkewMat = a_HDivSkew->ParallelAssemble();
|
||||
delete a_HDivSkew;
|
||||
smootherDivSkew = new HypreSmoother(*HDivSkewMat, 16, 3);
|
||||
|
||||
|
||||
|
||||
f = new Vector(fespace->GetTrueVSize());
|
||||
|
||||
fKernel = new Vector(H1KernelFESpace->GetTrueVSize());
|
||||
uKernel = new Vector(H1KernelFESpace->GetTrueVSize());
|
||||
|
||||
fImage = new Vector(H1_ImageFESpace->GetTrueVSize());
|
||||
uImage = new Vector(H1_ImageFESpace->GetTrueVSize());
|
||||
|
||||
fDivSkew = new Vector(HDivSkewKernelFESpace->GetTrueVSize());
|
||||
uDivSkew = new Vector(HDivSkewKernelFESpace->GetTrueVSize());
|
||||
|
||||
amgH1_Kernel->Mult(*fKernel, *uKernel);
|
||||
amgH1_Image->Mult(*fImage, *uImage);
|
||||
|
||||
pcgKernel = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgKernel->SetOperator(*H1_KernelMat);
|
||||
pcgKernel->SetPreconditioner(*amgH1_Kernel);
|
||||
pcgKernel->SetRelTol(1e-16);
|
||||
pcgKernel->SetMaxIter(100000000);
|
||||
pcgKernel->SetPrintLevel(-2);
|
||||
|
||||
pcgImage = new CGSolver(MPI_COMM_WORLD);
|
||||
pcgImage->SetOperator(*H1_ImageMat);
|
||||
pcgImage->SetPreconditioner(*amgH1_Image);
|
||||
pcgImage->SetRelTol(1e-16);
|
||||
pcgImage->SetMaxIter(100000000);
|
||||
pcgImage->SetPrintLevel(-2);
|
||||
|
||||
delete H1_ImageFESpace;
|
||||
delete H1KernelFESpace;
|
||||
delete fecH1Kernel;
|
||||
delete fecH1Vec;
|
||||
}
|
||||
|
||||
void setExactSolve(bool exSol)
|
||||
{
|
||||
exactSolves = exSol;
|
||||
}
|
||||
|
||||
virtual void Mult(const Vector &x, Vector &y) const
|
||||
{
|
||||
smootherdiv->Mult(x,y);
|
||||
|
||||
P_H1_Hdiv->MultTranspose(x,*fImage);
|
||||
*uImage = 0.0;
|
||||
if (exactSolves) { pcgImage->Mult(*fImage, *uImage); }
|
||||
else { amgH1_Image->Mult(*fImage, *uImage); }
|
||||
P_H1_Hdiv->Mult(1.0, *uImage, 1.0, y);
|
||||
|
||||
|
||||
*uDivSkew = 0.0;
|
||||
P_d_HSkewDiv_Hdiv->MultTranspose(x,*fDivSkew);
|
||||
|
||||
smootherDivSkew->Mult(*fDivSkew, *uDivSkew);
|
||||
|
||||
P_H1_HDivSkew->MultTranspose(*fDivSkew,*fKernel);
|
||||
*uKernel = 0.0;
|
||||
if (exactSolves) { pcgKernel->Mult(*fKernel, *uKernel); }
|
||||
else { amgH1_Kernel->Mult(*fKernel, *uKernel); }
|
||||
P_H1_HDivSkew->Mult(1.0, *uKernel, 1.0, *uDivSkew);
|
||||
|
||||
P_d_HSkewDiv_Hdiv->Mult(1.0, *uDivSkew, 1.0, y);
|
||||
}
|
||||
|
||||
virtual void SetOperator(const Operator &op) {};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI.
|
||||
int num_procs, myid;
|
||||
MPI_Init(&argc, &argv);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
|
||||
|
||||
bool verbose = (myid==0);
|
||||
|
||||
// 2. Parse command-line options.
|
||||
const char *mesh_file = "../data/star.mesh";
|
||||
int order = 1;
|
||||
bool set_bc = true;
|
||||
bool static_cond = false;
|
||||
bool hybridization = false;
|
||||
bool visualization = 1;
|
||||
int sequ_ref_levels = 0;
|
||||
int par_ref_levels = 0;
|
||||
double tol = 1e-6;
|
||||
double coeffWeight = 1.0;
|
||||
bool spe10Coeff = false;
|
||||
bool exactH1Solver = false;
|
||||
bool standardCG = true;
|
||||
|
||||
int NExpo = 8;
|
||||
int weightStart = -NExpo;
|
||||
int weightEnd = NExpo;
|
||||
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&mesh_file, "-m", "--mesh",
|
||||
"Mesh file to use.");
|
||||
args.AddOption(&order, "-o", "--order",
|
||||
"Finite element order (polynomial degree).");
|
||||
args.AddOption(&sequ_ref_levels, "-sr", "--seqrefinement",
|
||||
"Number of sequential refinement steps.");
|
||||
args.AddOption(&par_ref_levels, "-pr", "--parrefinement",
|
||||
"Number of parallel refinement steps.");
|
||||
args.AddOption(&set_bc, "-bc", "--impose-bc", "-no-bc", "--dont-impose-bc",
|
||||
"Impose or not essential boundary conditions.");
|
||||
args.AddOption(&freq, "-f", "--frequency", "Set the frequency for the exact"
|
||||
" solution.");
|
||||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||||
"--no-static-condensation", "Enable static condensation.");
|
||||
args.AddOption(&hybridization, "-hb", "--hybridization", "-no-hb",
|
||||
"--no-hybridization", "Enable hybridization.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(&tol, "-tol", "--tol",
|
||||
"A parameter.");
|
||||
args.AddOption(&coeffWeight, "-c", "--coeffMass",
|
||||
"the weight for the mass term.");
|
||||
args.AddOption(&exactH1Solver, "-exH1Sol", "--exactH1Solver", "-H1prec",
|
||||
"--H1preconditioner",
|
||||
"Use exact H1 solvers for the preconditioner.");
|
||||
args.AddOption(&spe10Coeff, "-spe10", "--useSPE10Coeff", "-constCoeff",
|
||||
"--constCoeff",
|
||||
"Switch between the coefficients for the mass bilinear form.");
|
||||
args.AddOption(&standardCG, "-sCG", "--stdCG", "-rCG", "--resCG",
|
||||
"Switch between standard PCG or recompute residuals in every step and use the residuals itself for the stopping criteria.");
|
||||
args.AddOption(&weightStart, "-ws", "--weightStart",
|
||||
"the exponent for the starting weight (for the mass term).");
|
||||
args.AddOption(&weightEnd, "-we", "--weightEnd",
|
||||
"the exponent for the weight at the end (for the mass term).");
|
||||
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
MPI_Finalize();
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
kappa = freq * M_PI;
|
||||
|
||||
// 3. Read the (serial) mesh from the given mesh file on all processors. We
|
||||
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
|
||||
// and volume, as well as periodic meshes with the same code.
|
||||
Mesh *mesh = new Mesh(mesh_file, 1, 1);
|
||||
int dim = mesh->Dimension();
|
||||
int sdim = mesh->SpaceDimension();
|
||||
|
||||
// 4. Refine the serial mesh on all processors to increase the resolution. In
|
||||
// this example we do 'ref_levels' of uniform refinement. We choose
|
||||
// 'ref_levels' to be the largest number that gives a final mesh with no
|
||||
// more than 1,000 elements.
|
||||
{
|
||||
for (int l = 0; l < sequ_ref_levels; l++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
|
||||
// this mesh further in parallel to increase the resolution. Once the
|
||||
// parallel mesh is defined, the serial mesh can be deleted. Tetrahedral
|
||||
// meshes need to be reoriented before we can define high-order Nedelec
|
||||
// spaces on them (this is needed in the ADS solver below).
|
||||
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
||||
delete mesh;
|
||||
{
|
||||
for (int l = 0; l < par_ref_levels; l++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
}
|
||||
pmesh->ReorientTetMesh();
|
||||
|
||||
// 6. Define a parallel finite element space on the parallel mesh. Here we
|
||||
// use the Raviart-Thomas finite elements of the specified order.
|
||||
FiniteElementCollection *fec;
|
||||
if (dim==4) { fec = new RT0_4DFECollection; }
|
||||
else { fec = new RT_FECollection(order-1, dim); }
|
||||
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
||||
HYPRE_Int size = fespace->GlobalTrueVSize();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Number of finite element unknowns: " << size << endl;
|
||||
}
|
||||
|
||||
// 7. Determine the list of true (i.e. parallel conforming) essential
|
||||
// boundary dofs. In this example, the boundary conditions are defined
|
||||
// by marking all the boundary attributes from the mesh as essential
|
||||
// (Dirichlet) and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = set_bc ? 1 : 0;
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
|
||||
// 8. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system, which in this case is
|
||||
// (f,phi_i) where f is given by the function f_exact and phi_i are the
|
||||
// basis functions in the finite element fespace.
|
||||
|
||||
|
||||
// 9. Define the solution vector x as a parallel finite element grid function
|
||||
// corresponding to fespace. Initialize x by projecting the exact
|
||||
// solution. Note that only values from the boundary faces will be used
|
||||
// when eliminating the non-homogeneous boundary condition to modify the
|
||||
// r.h.s. vector b.
|
||||
ParGridFunction x(fespace);
|
||||
VectorFunctionCoefficient F(sdim, F_exact);
|
||||
|
||||
for (int expo=weightStart; expo<=weightEnd; expo++)
|
||||
{
|
||||
double weight = pow(10.0,expo);
|
||||
kappa = weight;
|
||||
|
||||
x.ProjectCoefficient(F);
|
||||
|
||||
VectorFunctionCoefficient f(sdim, f_exact);
|
||||
ParLinearForm *b = new ParLinearForm(fespace);
|
||||
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
|
||||
b->Assemble();
|
||||
|
||||
// 10. Set up the parallel bilinear form corresponding to the H(div)
|
||||
// diffusion operator grad alpha div + beta I, by adding the div-div and
|
||||
// the mass domain integrators.
|
||||
|
||||
// std::string permFile = "spe_perm.dat";
|
||||
// InversePermeabilityFunction::ReadPermeabilityFile(permFile, MPI_COMM_WORLD);
|
||||
|
||||
Coefficient *alpha = new ConstantCoefficient(1.0);
|
||||
Coefficient *beta;
|
||||
// if(spe10Coeff) beta = new FunctionCoefficient(InversePermeabilityFunction::Norm2Permeability);
|
||||
// else
|
||||
beta = new ConstantCoefficient(weight);
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
a->AddDomainIntegrator(new DivDivIntegrator(*alpha));
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator(*beta));
|
||||
|
||||
// 11. Assemble the parallel bilinear form and the corresponding linear
|
||||
// system, applying any necessary transformations such as: parallel
|
||||
// assembly, eliminating boundary conditions, applying conforming
|
||||
// constraints for non-conforming AMR, static condensation,
|
||||
// hybridization, etc.
|
||||
FiniteElementCollection *hfec = NULL;
|
||||
ParFiniteElementSpace *hfes = NULL;
|
||||
if (static_cond)
|
||||
{
|
||||
a->EnableStaticCondensation();
|
||||
}
|
||||
else if (hybridization)
|
||||
{
|
||||
hfec = new DG_Interface_FECollection(order-1, dim);
|
||||
hfes = new ParFiniteElementSpace(pmesh, hfec);
|
||||
a->EnableHybridization(hfes, new NormalTraceJumpIntegrator(),
|
||||
ess_tdof_list);
|
||||
}
|
||||
a->Assemble();
|
||||
|
||||
HypreParMatrix A;
|
||||
Vector B, X;
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
|
||||
HYPRE_Int glob_size = A.GetGlobalNumRows();
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "Size of linear system: " << glob_size << endl;
|
||||
}
|
||||
|
||||
// 12. Define and apply a parallel PCG solver for A X = B with the 2D AMS or
|
||||
// the 3D ADS preconditioners from hypre. If using hybridization, the
|
||||
// system is preconditioned with hypre's BoomerAMG.
|
||||
Solver *prec = NULL;
|
||||
if (hybridization) { prec = new HypreBoomerAMG(A); }
|
||||
else
|
||||
{
|
||||
ParFiniteElementSpace *prec_fespace =
|
||||
(a->StaticCondensationIsEnabled() ? a->SCParFESpace() : fespace);
|
||||
if (dim == 2) { prec = new HypreAMS(A, prec_fespace); }
|
||||
else if (dim==3) { prec = new HypreADS(A, prec_fespace); }
|
||||
else if (dim==4) { prec = new div4dPrec(&A, fespace, alpha, beta, ess_bdr, order, exactH1Solver); }
|
||||
else { prec = NULL; }
|
||||
}
|
||||
|
||||
int iter = -1;
|
||||
if (standardCG)
|
||||
{
|
||||
IterativeSolver *pcg = new CGSolver(MPI_COMM_WORLD);
|
||||
pcg->SetOperator(A);
|
||||
pcg->SetRelTol(tol);
|
||||
pcg->SetMaxIter(500);
|
||||
pcg->SetPrintLevel(1);
|
||||
pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
iter = pcg->GetNumIterations();
|
||||
|
||||
delete pcg;
|
||||
}
|
||||
else
|
||||
{
|
||||
HyprePCG *pcg = new HyprePCG(A);
|
||||
pcg->SetTol(tol);
|
||||
pcg->SetMaxIter(5000);
|
||||
pcg->SetResidualConvergenceOptions(1,tol);
|
||||
pcg->SetPrintLevel(2);
|
||||
// pcg->SetPreconditioner(*prec);
|
||||
pcg->Mult(B, X);
|
||||
|
||||
pcg->GetNumIterations(iter);
|
||||
|
||||
delete pcg;
|
||||
}
|
||||
|
||||
if (myid==0)
|
||||
{
|
||||
cout << "Weigth: " << weight << " " << iter << endl;
|
||||
|
||||
int *iters = LoadIterations(10, 2*NExpo+1);
|
||||
putIterationsInArray(iter, sequ_ref_levels+par_ref_levels, expo+NExpo,
|
||||
2*NExpo+1, iters);
|
||||
WriteIterations(iters, 10, 2*NExpo+1);
|
||||
}
|
||||
|
||||
|
||||
// 13. Recover the parallel grid function corresponding to X. This is the
|
||||
// local finite element solution on each processor.
|
||||
a->RecoverFEMSolution(X, *b, x);
|
||||
|
||||
// 14. Compute and print the L^2 norm of the error.
|
||||
{
|
||||
double err = x.ComputeL2Error(F);
|
||||
if (myid == 0)
|
||||
{
|
||||
cout << "\n|| F_h - F ||_{L^2} = " << err << '\n' << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// 15. Save the refined mesh and the solution in parallel. This output can
|
||||
// be viewed later using GLVis: "glvis -np <np> -m mesh -g sol".
|
||||
// {
|
||||
// ostringstream mesh_name, sol_name;
|
||||
// mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
// sol_name << "sol." << setfill('0') << setw(6) << myid;
|
||||
//
|
||||
// ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
// mesh_ofs.precision(8);
|
||||
// pmesh->Print(mesh_ofs);
|
||||
//
|
||||
// ofstream sol_ofs(sol_name.str().c_str());
|
||||
// sol_ofs.precision(8);
|
||||
// x.Save(sol_ofs);
|
||||
// }
|
||||
|
||||
// 16. Send the solution by socket to a GLVis server.
|
||||
// if (visualization)
|
||||
// {
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock(vishost, visport);
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock.precision(8);
|
||||
// sol_sock << "solution\n" << *pmesh << x << flush;
|
||||
// }
|
||||
|
||||
if (prec!=NULL) { delete prec; }
|
||||
delete hfes;
|
||||
delete hfec;
|
||||
delete a;
|
||||
delete alpha;
|
||||
delete beta;
|
||||
|
||||
delete b;
|
||||
}
|
||||
|
||||
// 17. Free the used memory.
|
||||
|
||||
|
||||
delete fespace;
|
||||
delete fec;
|
||||
delete pmesh;
|
||||
|
||||
MPI_Finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// The exact solution (for non-surface meshes)
|
||||
void F_exact(const Vector &p, Vector &F)
|
||||
{
|
||||
int dim = p.Size();
|
||||
|
||||
if (dim==4)
|
||||
{
|
||||
double s0 = sin(M_PI*p(0)), s1 = sin(M_PI*p(1)), s2 = sin(M_PI*p(2)),
|
||||
s3 = sin(M_PI*p(3));
|
||||
double c0 = cos(M_PI*p(0)), c1 = cos(M_PI*p(1)), c2 = cos(M_PI*p(2)),
|
||||
c3 = cos(M_PI*p(3));
|
||||
|
||||
F(0) = c0 * s1 * s2 * s3;
|
||||
F(1) = s0 * c1 * s2 * s3;
|
||||
F(2) = s0 * s1 * c2 * s3;
|
||||
F(3) = s0 * s1 * s2 * c3;
|
||||
}
|
||||
else
|
||||
{
|
||||
double x = p(0);
|
||||
double y = p(1);
|
||||
// double z = (dim == 3) ? p(2) : 0.0;
|
||||
|
||||
F(0) = cos(kappa*x)*sin(kappa*y);
|
||||
F(1) = cos(kappa*y)*sin(kappa*x);
|
||||
if (dim == 3)
|
||||
{
|
||||
F(2) = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The right hand side
|
||||
void f_exact(const Vector &p, Vector &f)
|
||||
{
|
||||
int dim = p.Size();
|
||||
if (dim==4)
|
||||
{
|
||||
double s0 = sin(M_PI*p(0)), s1 = sin(M_PI*p(1)), s2 = sin(M_PI*p(2)),
|
||||
s3 = sin(M_PI*p(3));
|
||||
double c0 = cos(M_PI*p(0)), c1 = cos(M_PI*p(1)), c2 = cos(M_PI*p(2)),
|
||||
c3 = cos(M_PI*p(3));
|
||||
|
||||
f(0) = c0 * s1 * s2 * s3;
|
||||
f(1) = s0 * c1 * s2 * s3;
|
||||
f(2) = s0 * s1 * c2 * s3;
|
||||
f(3) = s0 * s1 * s2 * c3;
|
||||
|
||||
f *= (kappa + 4.0 * M_PI*M_PI);
|
||||
}
|
||||
else
|
||||
{
|
||||
double x = p(0);
|
||||
double y = p(1);
|
||||
// double z = (dim == 3) ? p(2) : 0.0;
|
||||
|
||||
double temp = 1 + 2*kappa*kappa;
|
||||
|
||||
f(0) = temp*cos(kappa*x)*sin(kappa*y);
|
||||
f(1) = temp*cos(kappa*y)*sin(kappa*x);
|
||||
if (dim == 3)
|
||||
{
|
||||
f(2) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -27,7 +27,8 @@ SEQ_EXAMPLES = ex0 ex1 ex2 ex3 ex4 ex5 ex6 ex7 ex8 ex9 ex10 ex14 ex15 ex16 \
|
||||
PAR_EXAMPLES = ex0p ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex8p ex9p ex10p ex11p \
|
||||
ex12p ex13p ex14p ex15p ex16p ex17p ex18p ex19p ex20p ex21p ex22p ex24p \
|
||||
ex25p ex26p ex27p ex28p ex29p ex30p ex31p ex32p ex33p ex34p ex35p ex36p \
|
||||
ex37p ex39p ex40p
|
||||
ex37p ex39p ex40p \
|
||||
ex1p_4d ex3p_4d ex4D_DivSkew
|
||||
SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
|
||||
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p \
|
||||
ex22p ex24p ex25p ex26p ex34p ex35p
|
||||
|
||||
@@ -66,7 +66,6 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI (required by PUMI) and HYPRE.
|
||||
Mpi::Init(argc, argv);
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
|
||||
@@ -80,8 +80,6 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI (required by PUMI) and HYPRE.
|
||||
Mpi::Init(argc, argv);
|
||||
int num_proc = Mpi::WorldSize();
|
||||
int myId = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
// 2. Parse command-line options.
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* spe10_coeff.cpp
|
||||
*
|
||||
* Created on: Aug 23, 2017
|
||||
* Author: neumueller
|
||||
*/
|
||||
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
class InversePermeabilityFunction
|
||||
{
|
||||
public:
|
||||
|
||||
enum SliceOrientation {NONE, XY, XZ, YZ};
|
||||
|
||||
static void SetNumberCells(int Nx_, int Ny_, int Nz_);
|
||||
static void SetMeshSizes(double hx, double hy, double hz);
|
||||
static void Set2DSlice(SliceOrientation o, int npos );
|
||||
|
||||
static void ReadPermeabilityFile(const std::string fileName);
|
||||
#ifdef MFEM_USE_MPI
|
||||
static void ReadPermeabilityFile(const std::string fileName, MPI_Comm comm);
|
||||
#endif
|
||||
static void SetConstantInversePermeability(double ipx, double ipy, double ipz);
|
||||
|
||||
template<class F>
|
||||
static void Transform(const F & f)
|
||||
{
|
||||
for (int i = 0; i < 3*Nx*Ny*Nz; ++i)
|
||||
{
|
||||
inversePermeability[i] = f(inversePermeability[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void InversePermeability(const Vector & x, Vector & val);
|
||||
static double PermeabilityXY(Vector &x);
|
||||
static void NegativeInversePermeability(const Vector & x, Vector & val);
|
||||
static void Permeability(const Vector & x, Vector & val);
|
||||
|
||||
static double Norm2Permeability(const Vector & x);
|
||||
|
||||
static double Norm2InversePermeability(const Vector & x);
|
||||
static double Norm1InversePermeability(const Vector & x);
|
||||
static double NormInfInversePermeability(const Vector & x);
|
||||
|
||||
static double InvNorm2(const Vector & x);
|
||||
static double InvNorm1(const Vector & x);
|
||||
static double InvNormInf(const Vector & x);
|
||||
|
||||
|
||||
static void ClearMemory();
|
||||
|
||||
private:
|
||||
static int Nx;
|
||||
static int Ny;
|
||||
static int Nz;
|
||||
static double hx;
|
||||
static double hy;
|
||||
static double hz;
|
||||
static double * inversePermeability;
|
||||
|
||||
static SliceOrientation orientation;
|
||||
static int npos;
|
||||
};
|
||||
|
||||
|
||||
void InversePermeabilityFunction::SetNumberCells(int Nx_, int Ny_, int Nz_)
|
||||
{
|
||||
Nx = Nx_;
|
||||
Ny = Ny_;
|
||||
Nz = Nz_;
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::SetMeshSizes(double hx_, double hy_,
|
||||
double hz_)
|
||||
{
|
||||
hx = hx_;
|
||||
hy = hy_;
|
||||
hz = hz_;
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::Set2DSlice(SliceOrientation o, int npos_ )
|
||||
{
|
||||
orientation = o;
|
||||
npos = npos_;
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::SetConstantInversePermeability(double ipx,
|
||||
double ipy, double ipz)
|
||||
{
|
||||
int compSize = Nx*Ny*Nz;
|
||||
int size = 3*compSize;
|
||||
inversePermeability = new double [size];
|
||||
double *ip = inversePermeability;
|
||||
|
||||
for (int i(0); i < compSize; ++i)
|
||||
{
|
||||
ip[i] = ipx;
|
||||
ip[i+compSize] = ipy;
|
||||
ip[i+2*compSize] = ipz;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MPI
|
||||
void InversePermeabilityFunction::ReadPermeabilityFile(const std::string
|
||||
fileName, MPI_Comm comm)
|
||||
{
|
||||
int num_procs, myid;
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
|
||||
StopWatch chrono;
|
||||
|
||||
chrono.Start();
|
||||
if (myid == 0)
|
||||
{
|
||||
ReadPermeabilityFile(fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
inversePermeability = new double [3*Nx*Ny*Nz];
|
||||
}
|
||||
chrono.Stop();
|
||||
|
||||
if (myid==0)
|
||||
{
|
||||
std::cout<<"Permeability file read in " << chrono.RealTime() << ".s \n";
|
||||
}
|
||||
|
||||
chrono.Clear();
|
||||
|
||||
chrono.Start();
|
||||
MPI_Bcast(inversePermeability, 3*Nx*Ny*Nz, MPI_DOUBLE, 0, comm);
|
||||
chrono.Stop();
|
||||
|
||||
if (myid==0)
|
||||
{
|
||||
std::cout<<"Permeability field distributed in " << chrono.RealTime() <<
|
||||
".s \n";
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
void InversePermeabilityFunction::ReadPermeabilityFile(const std::string
|
||||
fileName)
|
||||
{
|
||||
std::ifstream permfile(fileName.c_str());
|
||||
|
||||
if (!permfile.is_open())
|
||||
{
|
||||
std::cout << "Error in opening file " << fileName << "\n";
|
||||
mfem_error("File do not exists");
|
||||
}
|
||||
|
||||
inversePermeability = new double [3*Nx*Ny*Nz];
|
||||
double *ip = inversePermeability;
|
||||
double tmp;
|
||||
for (int l = 0; l < 3; l++)
|
||||
{
|
||||
for (int k = 0; k < Nz; k++)
|
||||
{
|
||||
for (int j = 0; j < Ny; j++)
|
||||
{
|
||||
for (int i = 0; i < Nx; i++)
|
||||
{
|
||||
permfile >> *ip;
|
||||
*ip = 1./(*ip);
|
||||
ip++;
|
||||
}
|
||||
for (int i = 0; i < 60-Nx; i++)
|
||||
{
|
||||
permfile >> tmp; // skip unneeded part
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < 220-Ny; j++)
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
permfile >> tmp; // skip unneeded part
|
||||
}
|
||||
}
|
||||
|
||||
if (l < 2) // if not processing Kz, skip unneeded part
|
||||
for (int k = 0; k < 85-Nz; k++)
|
||||
for (int j = 0; j < 220; j++)
|
||||
for (int i = 0; i < 60; i++)
|
||||
{
|
||||
permfile >> tmp;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::InversePermeability(const Vector & x,
|
||||
Vector & val)
|
||||
{
|
||||
val.SetSize(3);
|
||||
|
||||
unsigned int i,j,k;
|
||||
|
||||
switch (orientation)
|
||||
{
|
||||
case NONE:
|
||||
i = Nx-1-(int)floor(x[0]/hx/(1.+3e-16));
|
||||
j = (int)floor(x[1]/hy/(1.+3e-16));
|
||||
k = Nz-1-(int)floor(x[2]/hz/(1.+3e-16));
|
||||
break;
|
||||
case XY:
|
||||
i = Nx-1-(int)floor(x[0]/hx/(1.+3e-16));
|
||||
j = (int)floor(x[1]/hy/(1.+3e-16));
|
||||
k = npos;
|
||||
break;
|
||||
case XZ:
|
||||
i = Nx-1-(int)floor(x[0]/hx/(1.+3e-16));
|
||||
j = npos;
|
||||
k = Nz-1-(int)floor(x[2]/hz/(1.+3e-16));
|
||||
break;
|
||||
case YZ:
|
||||
i = npos;
|
||||
j = (int)floor(x[1]/hy/(1.+3e-16));
|
||||
k = Nz-1-(int)floor(x[2]/hz/(1.+3e-16));
|
||||
break;
|
||||
default:
|
||||
{
|
||||
mfem_error("InversePermeabilityFunction::InversePermeability");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int NMax = 3*Nx*Ny*Nz-1;
|
||||
if (Ny*Nx*k + Nx*j + i>NMax || Ny*Nx*k + Nx*j + i + Nx*Ny*Nz>NMax ||
|
||||
Ny*Nx*k + Nx*j + i + 2*Nx*Ny*Nz>NMax)
|
||||
{
|
||||
cout << " the indicies are wrong!" << endl;
|
||||
cout << i << " " << j << " " << k << endl;
|
||||
}
|
||||
|
||||
val[0] = inversePermeability[Ny*Nx*k + Nx*j + i];
|
||||
val[1] = inversePermeability[Ny*Nx*k + Nx*j + i + Nx*Ny*Nz];
|
||||
|
||||
if (orientation == NONE)
|
||||
{
|
||||
val[2] = inversePermeability[Ny*Nx*k + Nx*j + i + 2*Nx*Ny*Nz];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::PermeabilityXY(Vector &x)
|
||||
{
|
||||
unsigned int i,j,k;
|
||||
|
||||
i = Nx-1-(int)floor(x[0]/hx/(1.+3e-16));
|
||||
j = (int)floor(x[1]/hy/(1.+3e-16));
|
||||
k = npos;
|
||||
|
||||
return 1./inversePermeability[Ny*Nx*k + Nx*j + i];
|
||||
}
|
||||
|
||||
void InversePermeabilityFunction::NegativeInversePermeability(const Vector & x,
|
||||
Vector & val)
|
||||
{
|
||||
InversePermeability(x,val);
|
||||
val *= -1.;
|
||||
}
|
||||
|
||||
|
||||
void InversePermeabilityFunction::Permeability(const Vector & x, Vector & val)
|
||||
{
|
||||
InversePermeability(x,val);
|
||||
|
||||
for (double * it = val.GetData(), *end = val.GetData()+val.Size(); it != end;
|
||||
++it )
|
||||
{
|
||||
(*it) = 1./ (*it);
|
||||
}
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::Norm2Permeability(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
Permeability(x,val);
|
||||
return val.Norml2();
|
||||
}
|
||||
|
||||
|
||||
double InversePermeabilityFunction::Norm2InversePermeability(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return val.Norml2();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::Norm1InversePermeability(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return val.Norml1();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::NormInfInversePermeability(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return val.Normlinf();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::InvNorm2(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return 1./val.Norml2();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::InvNorm1(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return 1./val.Norml1();
|
||||
}
|
||||
|
||||
double InversePermeabilityFunction::InvNormInf(const Vector & x)
|
||||
{
|
||||
Vector val(3);
|
||||
InversePermeability(x,val);
|
||||
return 1./val.Normlinf();
|
||||
}
|
||||
|
||||
|
||||
void InversePermeabilityFunction::ClearMemory()
|
||||
{
|
||||
delete[] inversePermeability;
|
||||
}
|
||||
|
||||
int InversePermeabilityFunction::Nx(60);
|
||||
int InversePermeabilityFunction::Ny(220);
|
||||
int InversePermeabilityFunction::Nz(85);
|
||||
double InversePermeabilityFunction::hx(20);
|
||||
double InversePermeabilityFunction::hy(10);
|
||||
double InversePermeabilityFunction::hz(2);
|
||||
double * InversePermeabilityFunction::inversePermeability(NULL);
|
||||
InversePermeabilityFunction::SliceOrientation
|
||||
InversePermeabilityFunction::orientation( InversePermeabilityFunction::NONE );
|
||||
int InversePermeabilityFunction::npos(-1);
|
||||
|
||||
|
||||
|
||||
@@ -1833,7 +1833,6 @@ void MixedBilinearForm::FormRectangularSystemMatrix(
|
||||
const Array<int> &trial_tdof_list,
|
||||
const Array<int> &test_tdof_list,
|
||||
OperatorHandle &A)
|
||||
|
||||
{
|
||||
if (ext)
|
||||
{
|
||||
@@ -1912,8 +1911,14 @@ void MixedBilinearForm::FormRectangularLinearSystem(
|
||||
B.SetSubVector(test_tdof_list, 0.0);
|
||||
}
|
||||
|
||||
void MixedBilinearForm::Update()
|
||||
void MixedBilinearForm::Update(FiniteElementSpace *ntr_fes,
|
||||
FiniteElementSpace *nte_fes)
|
||||
{
|
||||
if ((ntr_fes && nte_fes) && (ntr_fes != trial_fes || nte_fes != test_fes))
|
||||
{
|
||||
trial_fes = ntr_fes;
|
||||
test_fes = nte_fes;
|
||||
}
|
||||
delete mat;
|
||||
mat = NULL;
|
||||
delete mat_e;
|
||||
|
||||
+11
-2
@@ -706,6 +706,10 @@ public:
|
||||
*/
|
||||
void SetDiagonalPolicy(DiagonalPolicy policy);
|
||||
|
||||
void SetIntegratorOwnership(int _extern_bfs)
|
||||
{
|
||||
extern_bfs = _extern_bfs;
|
||||
}
|
||||
/// Indicate that integrators are not owned by the BilinearForm
|
||||
void UseExternalIntegrators() { extern_bfs = 1; }
|
||||
|
||||
@@ -1068,8 +1072,13 @@ public:
|
||||
A.MakeRef(*A_ptr);
|
||||
}
|
||||
|
||||
/// Must be called after making changes to #trial_fes or #test_fes.
|
||||
void Update();
|
||||
virtual void Update(FiniteElementSpace *ntr_fes = NULL,
|
||||
FiniteElementSpace *nte_fes = NULL);
|
||||
|
||||
void SetIntegratorOwnership(int _extern_bfs)
|
||||
{
|
||||
extern_bfs = _extern_bfs;
|
||||
}
|
||||
|
||||
/// Return the trial FE space associated with the BilinearForm.
|
||||
FiniteElementSpace *TrialFESpace() { return trial_fes; }
|
||||
|
||||
+123
-2
@@ -1999,7 +1999,11 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
dim = el.GetDim();
|
||||
int dimc = el.GetCurlDim();
|
||||
// in main
|
||||
// int dimc = el.GetCurlDim();
|
||||
// Taken from 4d_dev:
|
||||
int dimc = (dim == 3) ? 3 : 1;
|
||||
if (dim==4) { dimc = 6; }
|
||||
real_t w;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
@@ -2036,8 +2040,43 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
if (dim ==4)
|
||||
{
|
||||
DenseMatrix tSh(4,4);
|
||||
DenseMatrix trShTemp(4,4);
|
||||
|
||||
DenseMatrix J = Trans.Jacobian();
|
||||
DenseMatrix invJ(4,4); CalcInverse(J, invJ);
|
||||
DenseMatrix invJtr(invJ); invJtr.Transpose();
|
||||
|
||||
el.CalcCurlShape(ip, curlshape);
|
||||
for (int dof=0; dof<nd; dof++)
|
||||
{
|
||||
tSh = 0.; trShTemp = 0.;
|
||||
tSh(0,1) = curlshape(dof,0); tSh(0,2) = curlshape(dof,1);
|
||||
tSh(0,3) = curlshape(dof,2);
|
||||
tSh(1,0) = -curlshape(dof,0);
|
||||
tSh(1,2) = curlshape(dof,3); tSh(1,3) = curlshape(dof,4);
|
||||
tSh(2,0) = -curlshape(dof,1); tSh(2,1) = -curlshape(dof,3);
|
||||
tSh(2,3) = curlshape(dof,5);
|
||||
tSh(3,0) = -curlshape(dof,2); tSh(3,1) = -curlshape(dof,4);
|
||||
tSh(3,2) = -curlshape(dof,5);
|
||||
|
||||
Mult(tSh, invJ, trShTemp);
|
||||
Mult(invJtr, trShTemp, tSh);
|
||||
|
||||
curlshape_dFt(dof,0) = tSh(0,1);
|
||||
curlshape_dFt(dof,1) = tSh(0,2);
|
||||
curlshape_dFt(dof,2) = tSh(0,3);
|
||||
curlshape_dFt(dof,3) = tSh(1,2);
|
||||
curlshape_dFt(dof,4) = tSh(1,3);
|
||||
curlshape_dFt(dof,5) = tSh(2,3);
|
||||
}
|
||||
}
|
||||
else
|
||||
el.CalcPhysCurlShape(Trans, curlshape_dFt);
|
||||
|
||||
w = ip.weight * Trans.Weight();
|
||||
el.CalcPhysCurlShape(Trans, curlshape_dFt);
|
||||
|
||||
if (MQ)
|
||||
{
|
||||
@@ -3415,6 +3454,7 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &el1,
|
||||
}
|
||||
}
|
||||
}
|
||||
// elmat.PrintMatlab(std::cout);
|
||||
}
|
||||
|
||||
|
||||
@@ -4555,4 +4595,85 @@ VectorInnerProductInterpolator::AssembleElementMatrix2(
|
||||
ran_fe.Project(dom_shape_coeff, Trans, elmat_as_vec);
|
||||
}
|
||||
|
||||
void HeatEquationIntegrator::AssembleElementMatrix
|
||||
( const FiniteElement &el, ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
int spaceDim = Trans.GetSpaceDim();
|
||||
double w;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix dshape(nd,dim), dshapedxt(nd,spaceDim), invdfdx(dim,spaceDim);
|
||||
Vector shape(nd), vec(nd);
|
||||
#else
|
||||
dshape.SetSize(nd,dim);
|
||||
dshapedxt.SetSize(nd,spaceDim);
|
||||
invdfdx.SetSize(dim,spaceDim);
|
||||
shape.SetSize(nd);
|
||||
dtshape.SetSize(nd);
|
||||
#endif
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
if (el.Space() == FunctionSpace::Pk)
|
||||
{
|
||||
order = 2*el.GetOrder() - 2;
|
||||
}
|
||||
else
|
||||
// order = 2*el.GetOrder() - 2; // <-- this seems to work fine too
|
||||
{
|
||||
order = 2*el.GetOrder() + dim - 1;
|
||||
}
|
||||
|
||||
if (el.Space() == FunctionSpace::rQk)
|
||||
{
|
||||
ir = &RefinedIntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
else
|
||||
{
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
el.CalcShape(ip,shape);
|
||||
el.CalcDShape(ip, dshape);
|
||||
|
||||
Trans.SetIntPoint(&ip);
|
||||
w = Trans.Weight();
|
||||
w *= ip.weight;
|
||||
CalcInverse(Trans.Jacobian(), invdfdx);
|
||||
Mult(dshape, invdfdx, dshapedxt);
|
||||
|
||||
dshapedxt.GetColumn(spaceDim - 1, dtshape); // d_t u
|
||||
dshapedxt.SetCol(spaceDim - 1, 0.);
|
||||
|
||||
AddMult_a_VWt(w,shape,dtshape,elmat); // d_t u * v
|
||||
if (!MQ)
|
||||
{
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
}
|
||||
AddMult_a_AAt(w, dshapedxt, elmat);
|
||||
}
|
||||
else
|
||||
{
|
||||
MQ->Eval(invdfdx, Trans, ip);
|
||||
invdfdx *= w;
|
||||
Mult(dshapedxt, invdfdx, dshape);
|
||||
AddMultABt(dshape, dshapedxt, elmat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+187
-1
@@ -266,6 +266,9 @@ public:
|
||||
Vector &flux, Vector *d_energy = NULL)
|
||||
{ return 0.0; }
|
||||
|
||||
// I think this got deleted
|
||||
// void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
|
||||
|
||||
/** @brief For bilinear forms on element faces, specifies if the normal
|
||||
derivatives are needed on the faces or just the face restriction.
|
||||
|
||||
@@ -298,7 +301,6 @@ public:
|
||||
*/
|
||||
virtual void AddMultPAFaceNormalDerivatives(const Vector &x, const Vector &dxdn,
|
||||
Vector &y, Vector &dydn) const;
|
||||
|
||||
virtual ~BilinearFormIntegrator() { }
|
||||
};
|
||||
|
||||
@@ -3680,6 +3682,16 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class DivSkewInterpolator : public DiscreteInterpolator
|
||||
{
|
||||
public:
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &dom_fe,
|
||||
const FiniteElement &ran_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{ ran_fe.ProjectDivSkew(dom_fe, Trans, elmat); }
|
||||
};
|
||||
|
||||
/** Class for constructing the (local) discrete divergence matrix which can
|
||||
be used as an integrator in a DiscreteLinearOperator object to assemble
|
||||
the global discrete divergence matrix.
|
||||
@@ -3811,5 +3823,179 @@ protected:
|
||||
VectorCoefficient *VQ;
|
||||
};
|
||||
|
||||
class DivSkewDivSkewIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
DenseMatrix DivSkewshape, DivSkew_dFt;
|
||||
|
||||
Coefficient *Q;
|
||||
|
||||
public:
|
||||
DivSkewDivSkewIntegrator() { Q = NULL; }
|
||||
/// Construct a bilinear form integrator for Nedelec elements
|
||||
DivSkewDivSkewIntegrator(Coefficient &q) : Q(&q) { }
|
||||
|
||||
/* Given a particular Finite Element, compute the
|
||||
element DivSkew-DivSkew matrix elmat */
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
real_t w;
|
||||
|
||||
DivSkewshape.SetSize(nd,dim);
|
||||
DivSkew_dFt.SetSize(nd,dim);
|
||||
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = 2*el.GetOrder()+2;
|
||||
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
el.CalcDivSkewShape(ip, DivSkewshape);
|
||||
|
||||
MultABt(DivSkewshape, Trans.Jacobian(), DivSkew_dFt);
|
||||
|
||||
DivSkew_dFt *= (1.0 / Trans.Weight());
|
||||
|
||||
w = ip.weight * fabs(Trans.Weight());
|
||||
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
}
|
||||
|
||||
AddMult_a_AAt(w, DivSkew_dFt, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class VectorFE_DivSkewMassIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
DenseMatrix shape;
|
||||
|
||||
Coefficient *Q;
|
||||
|
||||
public:
|
||||
VectorFE_DivSkewMassIntegrator() { Q = NULL; }
|
||||
/// Construct a bilinear form integrator for Nedelec elements
|
||||
VectorFE_DivSkewMassIntegrator(Coefficient &q) : Q(&q) { }
|
||||
|
||||
/* Given a particular Finite Element, compute the
|
||||
element curl-curl matrix elmat */
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{
|
||||
int nd = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
real_t w;
|
||||
|
||||
shape.SetSize(nd,dim*dim);
|
||||
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = Trans.OrderW() + 2 * el.GetOrder();
|
||||
|
||||
ir = &IntRules.Get(el.GetGeomType(), order);
|
||||
}
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Trans.SetIntPoint (&ip);
|
||||
|
||||
w = ip.weight * fabs(Trans.Weight());
|
||||
|
||||
|
||||
el.CalcVShape(Trans, shape);
|
||||
|
||||
|
||||
if (Q)
|
||||
{
|
||||
w *= Q->Eval(Trans, ip);
|
||||
}
|
||||
|
||||
AddMult_a_AAt(w, shape, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form a(u,v) := (d_t u, v) + (Q grad_x u, grad_x v) where Q
|
||||
can be a scalar or a matrix coefficient and grad_x is the gradient wrt to the spatial variables.
|
||||
Here we use the space-time f.e. scheme by [Steinbach2015]. */
|
||||
class HeatEquationIntegrator: public BilinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
Vector vec, pointflux, shape, dtshape;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
DenseMatrix dshape, dshapedxt, invdfdx, mq;
|
||||
DenseMatrix te_dshape, te_dshapedxt;
|
||||
#endif
|
||||
Coefficient *Q;
|
||||
MatrixCoefficient *MQ;
|
||||
|
||||
public:
|
||||
/// Construct a diffusion integrator with coefficient Q = 1
|
||||
HeatEquationIntegrator() { Q = NULL; MQ = NULL; }
|
||||
|
||||
/// Construct a diffusion integrator with a scalar coefficient q
|
||||
HeatEquationIntegrator (Coefficient &q) : Q(&q) { MQ = NULL; }
|
||||
|
||||
/// Construct a diffusion integrator with a matrix coefficient q
|
||||
HeatEquationIntegrator (MatrixCoefficient &q) : MQ(&q) { Q = NULL; }
|
||||
|
||||
/** Given a particular Finite Element
|
||||
computes the element stiffness matrix elmat. */
|
||||
virtual void AssembleElementMatrix(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat);
|
||||
/** Given a trial and test Finite Element computes the element stiffness
|
||||
matrix elmat. */
|
||||
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &elmat)
|
||||
{ mfem_error("HeatEquationIntegrator::AssembleElementMatrix2: not implemented!"); }
|
||||
|
||||
/// Perform the local action of the BilinearFormIntegrator
|
||||
virtual void AssembleElementVector(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
const Vector &elfun, Vector &elvect)
|
||||
{ mfem_error("HeatEquationIntegrator::AssembleElementVector: not implemented!"); }
|
||||
|
||||
virtual void ComputeElementFlux(const FiniteElement &el,
|
||||
ElementTransformation &Trans,
|
||||
Vector &u, const FiniteElement &fluxelem,
|
||||
Vector &flux, int with_coef = 1)
|
||||
{ mfem_error("HeatEquationIntegrator::ComputeElementFlux: not implemented!"); }
|
||||
|
||||
virtual double ComputeFluxEnergy(const FiniteElement &fluxelem,
|
||||
ElementTransformation &Trans,
|
||||
Vector &flux, Vector *d_energy = NULL)
|
||||
{ mfem_error("HeatEquationIntegrator::ComputeFluxEnergy: not implemented!"); return -1;}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
+8
-4
@@ -129,8 +129,10 @@ real_t PWCoefficient::Eval(ElementTransformation &T,
|
||||
real_t FunctionCoefficient::Eval(ElementTransformation & T,
|
||||
const IntegrationPoint & ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
// real_t x[Geometry::MaxDim];
|
||||
// Vector transip(x, Geometry::MaxDim);
|
||||
real_t x[4];
|
||||
Vector transip(x, 4);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
@@ -366,8 +368,10 @@ void PositionVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
|
||||
const IntegrationPoint &ip)
|
||||
{
|
||||
real_t x[3];
|
||||
Vector transip(x, 3);
|
||||
// real_t x[Geometry::MaxDim];
|
||||
// Vector transip(x, Geometry::MaxDim);
|
||||
real_t x[4];
|
||||
Vector transip(x, 4);
|
||||
|
||||
T.Transform(ip, transip);
|
||||
|
||||
|
||||
+6
-2
@@ -180,7 +180,7 @@ int InverseElementTransformation::NewtonSolve(const Vector &pt,
|
||||
const int dim = T->GetDimension();
|
||||
const int sdim = T->GetSpaceDim();
|
||||
IntegrationPoint xip, prev_xip;
|
||||
real_t xd[3], yd[3], dxd[3], dx_norm = -1.0, err_phys, real_dx_norm = -1.0;
|
||||
double xd[4], yd[4], dxd[4], dx_norm = -1.0, err_phys, real_dx_norm = -1.0;
|
||||
Vector x(xd, dim), y(yd, sdim), dx(dxd, dim);
|
||||
bool hit_bdr = false, prev_hit_bdr = false;
|
||||
|
||||
@@ -389,6 +389,8 @@ void IsoparametricTransformation::SetIdentityTransformation(
|
||||
case Geometry::CUBE : FElem = &HexahedronFE; break;
|
||||
case Geometry::PRISM : FElem = &WedgeFE; break;
|
||||
case Geometry::PYRAMID : FElem = &PyramidFE; break;
|
||||
case Geometry::PENTATOPE: FElem = &PentatopeFE; break;
|
||||
case Geometry::TESSERACT: FElem = &TesseractFE; break;
|
||||
default:
|
||||
MFEM_ABORT("unknown Geometry::Type!");
|
||||
}
|
||||
@@ -543,7 +545,9 @@ void IsoparametricTransformation::Transform (const DenseMatrix &matrix,
|
||||
void IntegrationPointTransformation::Transform (const IntegrationPoint &ip1,
|
||||
IntegrationPoint &ip2)
|
||||
{
|
||||
real_t vec[3];
|
||||
// real_t vec[Geometry::MaxDim];
|
||||
real_t vec[4];
|
||||
|
||||
Vector v (vec, Transf.GetPointMat().Height());
|
||||
|
||||
Transf.Transform (ip1, v);
|
||||
|
||||
@@ -43,6 +43,10 @@ LinearWedgeFiniteElement WedgeFE;
|
||||
// Defined here to ensure it is constructed before 'Geometries'.
|
||||
LinearPyramidFiniteElement PyramidFE;
|
||||
|
||||
// Object declared in mesh/pentatope.hpp.
|
||||
// Defined here to ensure it is constructed before 'Geometries'.
|
||||
Linear4DFiniteElement PentatopeFE;
|
||||
|
||||
// Object declared in geom.hpp.
|
||||
// Construct 'Geometries' after 'TriangleFE', 'TetrahedronFE', 'WedgeFE', and
|
||||
// PyramidFE.
|
||||
|
||||
@@ -93,6 +93,13 @@ void FiniteElement::CalcPhysCurlShape(ElementTransformation &Trans,
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElement::CalcDivSkewShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const
|
||||
{
|
||||
mfem_error ("FiniteElement::CalcDivSkewShape (ip, ...)\n"
|
||||
" is not implemented for this class!");
|
||||
}
|
||||
|
||||
void FiniteElement::GetFaceDofs(int face, int **dofs, int *ndofs) const
|
||||
{
|
||||
MFEM_ABORT("method is not overloaded");
|
||||
@@ -179,6 +186,14 @@ void FiniteElement::ProjectDiv(
|
||||
MFEM_ABORT("method is not implemented for this element");
|
||||
}
|
||||
|
||||
void FiniteElement::ProjectDivSkew(
|
||||
const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &DivSkew) const
|
||||
{
|
||||
mfem_error("FiniteElement::ProjectDivSkew(...) is not implemented for "
|
||||
"this element!");
|
||||
}
|
||||
|
||||
void FiniteElement::CalcPhysShape(ElementTransformation &Trans,
|
||||
Vector &shape) const
|
||||
{
|
||||
@@ -1012,9 +1027,19 @@ void VectorFiniteElement::SetDerivMembers()
|
||||
deriv_range_type = SCALAR;
|
||||
deriv_map_type = INTEGRAL;
|
||||
break;
|
||||
case H_DIV_SKEW:
|
||||
deriv_type = DIV_SKEW;
|
||||
deriv_range_type = VECTOR;
|
||||
deriv_map_type = H_DIV;
|
||||
break;
|
||||
case H_CURL:
|
||||
switch (dim)
|
||||
{
|
||||
case 4: // curl: 4D H_CURL -> 4D H_DIV(skew)
|
||||
deriv_type = CURL;
|
||||
deriv_range_type = MAT_SKEW;
|
||||
deriv_map_type = H_DIV_SKEW;
|
||||
break;
|
||||
case 3: // curl: 3D H_CURL -> 3D H_DIV
|
||||
deriv_type = CURL;
|
||||
deriv_range_type = VECTOR;
|
||||
@@ -1063,6 +1088,74 @@ void VectorFiniteElement::CalcVShape_ND(
|
||||
Mult(vshape, Trans.InverseJacobian(), shape);
|
||||
}
|
||||
|
||||
void VectorFiniteElement::CalcVShape_DivSkew (
|
||||
ElementTransformation &Trans, DenseMatrix &shape) const
|
||||
{
|
||||
if (dim!=4) { return; }
|
||||
|
||||
MFEM_ASSERT(map_type == H_DIV_SKEW, "");
|
||||
const DenseMatrix &J = Trans.Jacobian();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix vshape(dof, dim*dim);
|
||||
DenseMatrix Jinv(J.Width(), J.Height());
|
||||
#else
|
||||
Jinv.SetSize(J.Width(), J.Height());
|
||||
#endif
|
||||
|
||||
if (vshape.Width()!=dim*dim) { vshape.SetSize(dof,dim*dim); }
|
||||
|
||||
CalcVShape(Trans.GetIntPoint(), vshape);
|
||||
|
||||
CalcInverse(J, Jinv);
|
||||
DenseMatrix invJtr(Jinv); invJtr.Transpose();
|
||||
|
||||
CalcVShape(Trans.GetIntPoint(), vshape);
|
||||
|
||||
DenseMatrix mat(dim,dim); mat = 0.0;
|
||||
DenseMatrix tempMat(dim,dim);
|
||||
|
||||
for (int o=0; o<dof; o++)
|
||||
{
|
||||
// for(int ik=0; ik<dim; ik++)
|
||||
// for(int jk=0; jk<dim; jk++)
|
||||
// {
|
||||
// mat(ik,jk) = vshape(o,dim*ik+jk);
|
||||
// }
|
||||
//
|
||||
// Mult(mat, Jinv, tempMat);
|
||||
// Mult(invJtr, tempMat, mat);
|
||||
//
|
||||
// for(int ik=0; ik<dim; ik++)
|
||||
// for(int jk=0; jk<dim; jk++)
|
||||
// {
|
||||
// shape(o,dim*ik+jk) = mat(ik,jk);
|
||||
// }
|
||||
|
||||
|
||||
mat(0,0) = 0.0; mat(0,1) = vshape(o,11);
|
||||
mat(0,2) = vshape(o,13); mat(0,3) = vshape(o,6);
|
||||
mat(1,0) = vshape(o,14); mat(1,1) = 0.0;
|
||||
mat(1,2) = vshape(o,3); mat(1,3) = vshape(o,8);
|
||||
mat(2,0) = vshape(o,7); mat(2,1) = vshape(o,12); mat(2,2) = 0.0;
|
||||
mat(2,3) = vshape(o,1);
|
||||
mat(3,0) = vshape(o,9); mat(3,1) = vshape(o,2);
|
||||
mat(3,2) = vshape(o,4); mat(3,3) = 0.0;
|
||||
|
||||
Mult(mat, Jinv, tempMat);
|
||||
Mult(invJtr, tempMat, mat);
|
||||
|
||||
shape(o,0) = 0.0; shape(o,1) = mat(2,3); shape(o,2) = mat(3,1);
|
||||
shape(o,3) = mat(1,2);
|
||||
shape(o,4) = mat(3,2); shape(o,5) = 0.0; shape(o,6) = mat(0,3);
|
||||
shape(o,7) = mat(2,0);
|
||||
shape(o,8) = mat(1,3); shape(o,9) = mat(3,0); shape(o,10) = 0.0;
|
||||
shape(o,11) = mat(0,1);
|
||||
shape(o,12) = mat(2,1); shape(o,13) = mat(0,2); shape(o,14) = mat(1,0);
|
||||
shape(o,15) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void VectorFiniteElement::Project_RT(
|
||||
const real_t *nk, const Array<int> &d2n,
|
||||
VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
|
||||
|
||||
+18
-4
@@ -259,7 +259,7 @@ protected:
|
||||
|
||||
public:
|
||||
/// Enumeration for range_type and deriv_range_type
|
||||
enum RangeType { UNKNOWN_RANGE_TYPE = -1, SCALAR, VECTOR };
|
||||
enum RangeType { UNKNOWN_RANGE_TYPE = -1, SCALAR, VECTOR, MAT_SKEW };
|
||||
|
||||
/** @brief Enumeration for MapType: defines how reference functions are
|
||||
mapped to physical space.
|
||||
@@ -281,10 +281,11 @@ public:
|
||||
$ u(x) = (1/w) \hat u(\hat x) $ */
|
||||
H_DIV, /**< For vector fields; preserves surface integrals of the
|
||||
normal component $ u(x) = (J/w) \hat u(\hat x) $ */
|
||||
H_CURL /**< For vector fields; preserves line integrals of the
|
||||
H_CURL, /**< For vector fields; preserves line integrals of the
|
||||
tangential component
|
||||
$ u(x) = J^{-t} \hat u(\hat x) $ (square J),
|
||||
$ u(x) = J(J^t J)^{-1} \hat u(\hat x) $ (general J) */
|
||||
H_DIV_SKEW
|
||||
};
|
||||
|
||||
/** @brief Enumeration for DerivType: defines which derivative method
|
||||
@@ -299,7 +300,8 @@ public:
|
||||
NONE, ///< No derivatives implemented
|
||||
GRAD, ///< Implements CalcDShape methods
|
||||
DIV, ///< Implements CalcDivShape methods
|
||||
CURL ///< Implements CalcCurlShape methods
|
||||
CURL, ///< Implements CalcCurlShape methods
|
||||
DIV_SKEW
|
||||
};
|
||||
|
||||
/** @brief Construct FiniteElement with given
|
||||
@@ -448,6 +450,10 @@ public:
|
||||
virtual void CalcPhysCurlShape(ElementTransformation &Trans,
|
||||
DenseMatrix &curl_shape) const;
|
||||
|
||||
virtual void CalcDivSkewShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
|
||||
|
||||
/** @brief Get the dofs associated with the given @a face.
|
||||
@a *dofs is set to an internal array of the local dofc on the
|
||||
face, while *ndofs is set to the number of dofs on that face.
|
||||
@@ -577,6 +583,10 @@ public:
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &div) const;
|
||||
|
||||
virtual void ProjectDivSkew(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &DivSkew) const;
|
||||
|
||||
/** @brief Return a DofToQuad structure corresponding to the given
|
||||
IntegrationRule using the given DofToQuad::Mode. */
|
||||
/** See the documentation for DofToQuad for more details. */
|
||||
@@ -812,7 +822,7 @@ private:
|
||||
protected:
|
||||
bool is_nodal;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable DenseMatrix JtJ;
|
||||
mutable DenseMatrix JtJ, J, Jinv;
|
||||
mutable DenseMatrix curlshape, curlshape_J;
|
||||
#endif
|
||||
void SetDerivMembers();
|
||||
@@ -823,6 +833,10 @@ protected:
|
||||
void CalcVShape_ND(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
void CalcVShape_DivSkew(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
|
||||
/** @brief Project a vector coefficient onto the RT basis functions
|
||||
@param nk Face normal vectors for this element type
|
||||
@param d2n Offset into nk for each degree of freedom
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -450,6 +450,74 @@ public:
|
||||
{ dofs = 0.0; dofs(vertex) = 1.0; }
|
||||
};
|
||||
|
||||
/// Class for quad-linear FE on tesseract (4d element)
|
||||
class QuadLinear4DFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct a quad-linear FE on tesseract
|
||||
QuadLinear4DFiniteElement();
|
||||
|
||||
/** virtual function which evaluates the values of all
|
||||
shape functions at a given point ip and stores
|
||||
them in the vector shape of dimension Dof (16) */
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
|
||||
/** virtual function which evaluates the values of all
|
||||
partial derivatives of all shape functions at a given
|
||||
point ip and stores them in the matrix dshape (Dof x Dim) (16 x 4)
|
||||
so that each row contains the derivatives of one shape function */
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
virtual void CalcHessian (const IntegrationPoint &ip,
|
||||
DenseMatrix &h) const;
|
||||
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const
|
||||
{ dofs = 0.0; dofs(vertex) = 1.0; }
|
||||
};
|
||||
|
||||
/// Class for linear FE on a pentatope
|
||||
class Linear4DFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct a linear FE on tetrahedron
|
||||
Linear4DFiniteElement();
|
||||
|
||||
/** virtual function which evaluates the values of all
|
||||
shape functions at a given point ip and stores
|
||||
them in the vector shape of dimension Dof (4) */
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
|
||||
/** virtual function which evaluates the values of all
|
||||
partial derivatives of all shape functions at a given
|
||||
point ip and stores them in the matrix dshape (Dof x Dim) (4 x 3)
|
||||
so that each row contains the derivatives of one shape function */
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const
|
||||
{ dofs = 0.0; dofs(vertex) = 1.0; }
|
||||
|
||||
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const;
|
||||
|
||||
virtual void CalcHessian(const IntegrationPoint &ip, DenseMatrix &h) const;
|
||||
};
|
||||
|
||||
/// Class for quadratic FE on pentatope
|
||||
class Quadratic4DFiniteElement : public NodalFiniteElement
|
||||
{
|
||||
public:
|
||||
/// Construct a quadratic FE on pentatope
|
||||
Quadratic4DFiniteElement();
|
||||
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &h) const;
|
||||
};
|
||||
|
||||
/// A 2D Crouzeix-Raviart element on triangle
|
||||
class CrouzeixRaviartFiniteElement : public NodalFiniteElement
|
||||
@@ -1189,7 +1257,126 @@ public:
|
||||
DenseMatrix &dshape) const;
|
||||
};
|
||||
|
||||
//lowest order first kind nedelec element for a pentatope
|
||||
class Nedelec1PentFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double tk[10][4];
|
||||
|
||||
public:
|
||||
Nedelec1PentFiniteElement();
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_ND(Trans, shape); }
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
};
|
||||
|
||||
//lowest order second kind nedelec element for a pentatope
|
||||
class Nedelec1FullPentFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double tk[10][4];
|
||||
|
||||
public:
|
||||
Nedelec1FullPentFiniteElement();
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_ND(Trans, shape); }
|
||||
virtual void CalcCurlShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &curl_shape) const;
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const {};
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
virtual void ProjectGrad(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &grad) const;
|
||||
};
|
||||
|
||||
class DivSkew1PentFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double tk1[10][4];
|
||||
static const double tk2[10][4];
|
||||
|
||||
public:
|
||||
DivSkew1PentFiniteElement();
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_DivSkew(Trans, shape); }
|
||||
virtual void CalcDivSkewShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &divSkew_shape) const;
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
using FiniteElement::Project;
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
virtual void ProjectCurl(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &curl) const;
|
||||
};
|
||||
|
||||
class RT0PentFiniteElement : public VectorFiniteElement
|
||||
{
|
||||
private:
|
||||
static const double nk[5][4];
|
||||
|
||||
public:
|
||||
RT0PentFiniteElement();
|
||||
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_RT(Trans, shape); };
|
||||
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
|
||||
virtual void GetLocalInterpolation (ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
using FiniteElement::Project;
|
||||
|
||||
virtual void Project (VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const;
|
||||
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const;
|
||||
|
||||
virtual void ProjectDivSkew(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &DivSkew) const;
|
||||
};
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1040,4 +1040,345 @@ void H1_WedgeElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
H1_PentatopeElement::H1_PentatopeElement(const int p, const int type)
|
||||
: NodalFiniteElement(4, Geometry::PENTATOPE,
|
||||
((p + 1)*(p + 2)*(p + 3)*(p + 4))/24,
|
||||
p, FunctionSpace::Pk)
|
||||
{
|
||||
const double *cp = poly1d.ClosedPoints(p, VerifyClosed(type));
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p + 1);
|
||||
shape_y.SetSize(p + 1);
|
||||
shape_z.SetSize(p + 1);
|
||||
shape_t.SetSize(p + 1);
|
||||
shape_l.SetSize(p + 1);
|
||||
dshape_x.SetSize(p + 1);
|
||||
dshape_y.SetSize(p + 1);
|
||||
dshape_z.SetSize(p + 1);
|
||||
dshape_t.SetSize(p + 1);
|
||||
dshape_l.SetSize(p + 1);
|
||||
ddshape_x.SetSize(p + 1);
|
||||
ddshape_y.SetSize(p + 1);
|
||||
ddshape_z.SetSize(p + 1);
|
||||
ddshape_t.SetSize(p + 1);
|
||||
ddshape_l.SetSize(p + 1);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof, dim);
|
||||
ddu.SetSize(dof,dim*(dim+1)/2 );
|
||||
#else
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p+1),
|
||||
shape_l(p + 1);
|
||||
#endif
|
||||
|
||||
// vertices
|
||||
Nodes.IntPoint(0).Set4(cp[0], cp[0], cp[0], cp[0]);
|
||||
Nodes.IntPoint(1).Set4(cp[p], cp[0], cp[0], cp[0]);
|
||||
Nodes.IntPoint(2).Set4(cp[0], cp[p], cp[0], cp[0]);
|
||||
Nodes.IntPoint(3).Set4(cp[0], cp[0], cp[p], cp[0]);
|
||||
Nodes.IntPoint(4).Set4(cp[0], cp[0], cp[0], cp[p]);
|
||||
|
||||
// edges (see Tetrahedron::edges in mesh/tetrahedron.cpp)
|
||||
int o = 5;
|
||||
for (int i = 1; i < p; i++) // (0,1)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[i], cp[0], cp[0], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (0,2)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[i], cp[0], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (0,3)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[0], cp[i], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (0,4)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[0], cp[0], cp[i]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (1,2)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i], cp[i], cp[0], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (1,3)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i], cp[0], cp[i], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (1,4)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i], cp[0], cp[0], cp[i]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (2,3)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[p-i], cp[i], cp[0]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (2,4)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[p-i], cp[0], cp[i]);
|
||||
}
|
||||
for (int i = 1; i < p; i++) // (3,4)
|
||||
{
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[0], cp[p-i], cp[i]);
|
||||
}
|
||||
|
||||
// planars (see Mesh::GeneratePlanars in mesh/mesh.cpp)
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,1,2)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[j]/w, cp[0], cp[0]);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,1,3)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[0], cp[j]/w, cp[0]);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,1,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[0], cp[0], cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,2,3)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[i]/w, cp[j]/w, cp[0]);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,2,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[i]/w, cp[0], cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (0,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[0], cp[i]/w, cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (1,2,3)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i-j]/w, cp[i]/w, cp[j]/w, cp[0]);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (1,2,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i-j]/w, cp[i]/w, cp[0], cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (1,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i-j]/w, cp[0], cp[i]/w, cp[j]/w);
|
||||
}
|
||||
for (int j = 1; j < p; j++)
|
||||
for (int i=1; i + j < p; i++) // (2,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[p-i-j];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[p-i-j]/w, cp[i]/w, cp[j]/w);
|
||||
}
|
||||
|
||||
// face(volumes)s (see Mesh::GenerateFaces in mesh/mesh.cpp)
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (0,1,2,3)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[j]/w, cp[k]/w, cp[0]);
|
||||
}
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (0,2,1,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[j]/w, cp[i]/w, cp[0], cp[k]/w);
|
||||
}
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (0,1,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[0], cp[j]/w, cp[k]/w);
|
||||
}
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (0,3,2,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[0], cp[j]/w, cp[i]/w, cp[k]/w);
|
||||
}
|
||||
for (int k = 1; k < p; k++)
|
||||
for (int j = 1; j + k < p; j++)
|
||||
for (int i = 1; i + j + k < p; i++) // (1,2,3,4)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k];
|
||||
Nodes.IntPoint(o++).Set4(cp[p-i-j-k]/w, cp[i]/w, cp[j]/w, cp[k]/w);
|
||||
}
|
||||
|
||||
// interior
|
||||
for (int l = 1; l < p; l++)
|
||||
for (int k = 1; k + l < p; k++)
|
||||
for (int j = 1; j + k + l < p; j++)
|
||||
for (int i = 1; i + j + k + l < p; i++)
|
||||
{
|
||||
double w = cp[i] + cp[j] + cp[k] + cp[l] + cp[p-i-j-k-l];
|
||||
Nodes.IntPoint(o++).Set4(cp[i]/w, cp[j]/w, cp[k]/w, cp[l]/w);
|
||||
}
|
||||
|
||||
DenseMatrix T(dof);
|
||||
for (int m = 0; m < dof; m++)
|
||||
{
|
||||
IntegrationPoint &ip = Nodes.IntPoint(m);
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
o = 0;
|
||||
for (int l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k +l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
T(o++, m) = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
}
|
||||
}
|
||||
|
||||
Ti.Factor(T);
|
||||
// cout << "H1_PentatopeElement(" << p << ") : "; Ti.TestInversion();
|
||||
}
|
||||
|
||||
void H1_PentatopeElement::CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p+1),
|
||||
shape_l(p + 1);
|
||||
Vector u(Dof);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
u(o++) = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
}
|
||||
|
||||
Ti.Mult(u, shape);
|
||||
}
|
||||
|
||||
void H1_PentatopeElement::CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p+1),
|
||||
shape_l(p + 1);
|
||||
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_t(p+1),
|
||||
dshape_l(p + 1);
|
||||
DenseMatrix du(Dof, Dim);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t, dshape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l, dshape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
int m = p - i - j - k - l;
|
||||
du(o,0) = ((dshape_x(i)* shape_l(m)) -
|
||||
( shape_x(i)*dshape_l(m)))*shape_y(j)*shape_z(k)*shape_t(l);
|
||||
du(o,1) = ((dshape_y(j)* shape_l(m)) -
|
||||
( shape_y(j)*dshape_l(m)))*shape_x(i)*shape_z(k)*shape_t(l);
|
||||
du(o,2) = ((dshape_z(k)* shape_l(m)) -
|
||||
( shape_z(k)*dshape_l(m)))*shape_x(i)*shape_y(j)*shape_t(l);
|
||||
du(o,3) = ((dshape_t(l)* shape_l(m)) -
|
||||
( shape_t(l)*dshape_l(m)))*shape_x(i)*shape_y(j)*shape_z(k);
|
||||
o++;
|
||||
}
|
||||
|
||||
Ti.Mult(du, dshape);
|
||||
}
|
||||
|
||||
void H1_PentatopeElement::CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &ddshape) const
|
||||
{
|
||||
const int p = order;
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p+1),
|
||||
shape_l(p + 1);
|
||||
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_t(p+1),
|
||||
dshape_l(p + 1);
|
||||
Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_z(p + 1), ddshape_t(p+1),
|
||||
ddshape_l(p + 1);
|
||||
DenseMatrix ddu(Dof, ((Dim+1)*Dim)/2);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y, ddshape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z, ddshape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t, dshape_t, ddshape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l, dshape_l,
|
||||
ddshape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
// u_xx, u_xy, u_xz, u_xt, u_yy, u_yz, u_yt, u_zz, u_zt, u_tt
|
||||
int m = p - i - j - k - l;
|
||||
ddu(o,0) = ((ddshape_x(i)*shape_l(m)) - 2.* (dshape_x(i)*dshape_l(m)) +
|
||||
(shape_x(i)*ddshape_l(m))) * shape_y(j) * shape_z(k) * shape_t(l);
|
||||
ddu(o,1) = ((dshape_y(j)* ( (dshape_x(i)*shape_l(m)) - (shape_x(i)*dshape_l(
|
||||
m))) ) + (shape_y(j)* ((ddshape_l(m)*shape_x(i)) - (dshape_x(i) * dshape_l(
|
||||
m)) ) ) )* shape_z(k) * shape_t(l);
|
||||
ddu(o,2) = ((dshape_z(k)* ( (dshape_x(i)*shape_l(m)) - (shape_x(i)*dshape_l(
|
||||
m))) ) + (shape_z(k)* ((ddshape_l(m)*shape_x(i)) - (dshape_x(i) * dshape_l(
|
||||
m)) ) ) )* shape_y(j) * shape_t(l);
|
||||
ddu(o,3) = ((dshape_t(l)* ( (dshape_x(i)*shape_l(m)) - (shape_x(i)*dshape_l(
|
||||
m))) ) + (shape_t(l)* ((ddshape_l(m)*shape_x(i)) - (dshape_x(i) * dshape_l(
|
||||
m)) ) ) )* shape_y(j) * shape_z(k);
|
||||
ddu(o,4) = ((ddshape_y(j)*shape_l(m)) - 2.* (dshape_y(j)*dshape_l(m)) +
|
||||
(shape_y(j)*ddshape_l(m))) * shape_x(i) * shape_z(k) * shape_t(l);
|
||||
ddu(o,5) = ((dshape_z(k)* ( (dshape_y(j)*shape_l(m)) - (shape_y(j)*dshape_l(
|
||||
m))) ) + (shape_z(k)* ((ddshape_l(m)*shape_y(j)) - (dshape_y(j) * dshape_l(
|
||||
m)) ) ) )* shape_x(i) * shape_t(l);
|
||||
ddu(o,6) = ((dshape_t(l)* ( (dshape_y(j)*shape_l(m)) - (shape_y(j)*dshape_l(
|
||||
m))) ) + (shape_t(l)* ((ddshape_l(m)*shape_y(j)) - (dshape_y(j) * dshape_l(
|
||||
m)) ) ) )* shape_x(i) * shape_z(k);
|
||||
ddu(o,7) = ((ddshape_z(k)*shape_l(m)) - 2.* (dshape_z(k)*dshape_l(m)) +
|
||||
(shape_z(k)*ddshape_l(m))) * shape_y(j) * shape_x(i) * shape_t(l);
|
||||
ddu(o,8) = ((dshape_t(l)* ( (dshape_z(k)*shape_l(m)) - (shape_z(k)*dshape_l(
|
||||
m))) ) + (shape_t(l)* ((ddshape_l(m)*shape_z(k)) - (dshape_z(k) * dshape_l(
|
||||
m)) ) ) )* shape_x(i) * shape_y(j);
|
||||
ddu(o,9) = ((ddshape_t(l)*shape_l(m)) - 2.* (dshape_t(l)*dshape_l(m)) +
|
||||
(shape_t(l)*ddshape_l(m))) * shape_y(j) * shape_x(i) * shape_z(k);
|
||||
o++;
|
||||
}
|
||||
Ti.Mult(ddu, ddshape);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -148,6 +148,28 @@ public:
|
||||
DenseMatrix &dshape) const;
|
||||
};
|
||||
|
||||
class H1_PentatopeElement : public NodalFiniteElement
|
||||
{
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_z, shape_t, shape_l;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z, dshape_t, dshape_l, u;
|
||||
mutable Vector ddshape_x, ddshape_y, ddshape_z, ddshape_t, ddshape_l;
|
||||
mutable DenseMatrix du, ddu;
|
||||
#endif
|
||||
DenseMatrixInverse Ti;
|
||||
|
||||
public:
|
||||
H1_PentatopeElement(const int p,
|
||||
const int btype = BasisType::GaussLobatto);
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void CalcHessian(const IntegrationPoint &ip,
|
||||
DenseMatrix &ddshape) const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -923,4 +923,175 @@ void L2_WedgeElement::CalcDShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
L2_PentatopeElement::L2_PentatopeElement(const int p, const int _type)
|
||||
: NodalFiniteElement(4, Geometry::PENTATOPE,
|
||||
((p + 1)*(p + 2)*(p + 3)*(p + 4))/24,
|
||||
p, FunctionSpace::Pk), T(dof)
|
||||
{
|
||||
const double *op;
|
||||
|
||||
type = _type;
|
||||
switch (type)
|
||||
{
|
||||
case 0: op = poly1d.OpenPoints(p); break;
|
||||
case 1:
|
||||
default: op = poly1d.ClosedPoints(p);
|
||||
}
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p + 1);
|
||||
shape_y.SetSize(p + 1);
|
||||
shape_z.SetSize(p + 1);
|
||||
shape_t.SetSize(p + 1);
|
||||
shape_l.SetSize(p + 1);
|
||||
dshape_x.SetSize(p + 1);
|
||||
dshape_y.SetSize(p + 1);
|
||||
dshape_z.SetSize(p + 1);
|
||||
dshape_t.SetSize(p + 1);
|
||||
dshape_l.SetSize(p + 1);
|
||||
u.SetSize(dof);
|
||||
du.SetSize(dof, dim);
|
||||
#else
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p + 1),
|
||||
shape_l(p + 1);
|
||||
#endif
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; l + k <= p; k++)
|
||||
for (int j = 0; j + l + k <= p; j++)
|
||||
for (int i = 0; i + j + l + k <= p; i++)
|
||||
{
|
||||
double w = op[i] + op[j] + op[k] + op[l] + op[p-i-j-k-l];
|
||||
Nodes.IntPoint(o++).Set4(op[i]/w, op[j]/w, op[k]/w, op[l]/w);
|
||||
}
|
||||
|
||||
for (int m = 0; m < dof; m++)
|
||||
{
|
||||
IntegrationPoint &ip = Nodes.IntPoint(m);
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; l + k <= p; k++)
|
||||
for (int j = 0; j + l + k <= p; j++)
|
||||
for (int i = 0; i + j + l + k <= p; i++)
|
||||
{
|
||||
T(o++, m) = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
}
|
||||
}
|
||||
|
||||
T.Invert();
|
||||
}
|
||||
|
||||
void L2_PentatopeElement::CalcShape(const IntegrationPoint &ip,
|
||||
Vector &shape) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
|
||||
Vector u(Dof);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
for (int o = 0, l = 0; l <= p; l++)
|
||||
for (int k = 0; l + k <= p; k++)
|
||||
for (int j = 0; j + l + k <= p; j++)
|
||||
for (int i = 0; i + j + l + k <= p; i++)
|
||||
{
|
||||
u(o++) = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
}
|
||||
|
||||
T.Mult(u, shape);
|
||||
}
|
||||
|
||||
void L2_PentatopeElement::CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const
|
||||
{
|
||||
const int p = order;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p + 1),
|
||||
shape_l(p + 1);
|
||||
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_t(p + 1),
|
||||
dshape_l(p + 1);
|
||||
DenseMatrix du(Dof, Dim);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t, dshape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l, dshape_l);
|
||||
|
||||
for (int o = 0, m = 0; m <= p; m++)
|
||||
for (int k = 0; k + m <= p; k++)
|
||||
for (int j = 0; j + k + m <= p; j++)
|
||||
for (int i = 0; i + j + k + m <= p; i++)
|
||||
{
|
||||
int l = p - i - j - k - m;
|
||||
du(o,0) = ((dshape_x(i)* shape_l(l)) -
|
||||
( shape_x(i)*dshape_l(l)))*shape_y(j)*shape_z(k)*shape_t(m);
|
||||
du(o,1) = ((dshape_y(j)* shape_l(l)) -
|
||||
( shape_y(j)*dshape_l(l)))*shape_x(i)*shape_z(k)*shape_t(m);
|
||||
du(o,2) = ((dshape_z(k)* shape_l(l)) -
|
||||
( shape_z(k)*dshape_l(l)))*shape_x(i)*shape_y(j)*shape_t(m);
|
||||
du(o,3) = ((dshape_t(m)* shape_l(l)) -
|
||||
( shape_t(m)*dshape_l(l)))*shape_x(i)*shape_y(j)*shape_z(k);
|
||||
o++;
|
||||
}
|
||||
|
||||
Mult(T, du, dshape);
|
||||
}
|
||||
|
||||
void L2_PentatopeElement::ProjectDelta(int vertex, Vector &dofs) const
|
||||
{
|
||||
switch (vertex)
|
||||
{
|
||||
case 0:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(1.0 - ip.x - ip.y - ip.z - ip.t, order);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.x, order);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.y, order);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.z, order);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (int i = 0; i < dof; i++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(i);
|
||||
dofs[i] = pow(ip.t, order);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -183,6 +183,25 @@ public:
|
||||
DenseMatrix &dshape) const;
|
||||
};
|
||||
|
||||
class L2_PentatopeElement : public NodalFiniteElement
|
||||
{
|
||||
private:
|
||||
int type;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_z, shape_t, shape_l;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z, dshape_t, dshape_l, u;
|
||||
mutable DenseMatrix du;
|
||||
#endif
|
||||
DenseMatrix T;
|
||||
|
||||
public:
|
||||
L2_PentatopeElement(const int p, const int _type = 0);
|
||||
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const;
|
||||
virtual void CalcDShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &dshape) const;
|
||||
virtual void ProjectDelta(int vertex, Vector &dofs) const;
|
||||
};
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2266,4 +2266,268 @@ void RT_R2D_QuadrilateralElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
}
|
||||
}
|
||||
|
||||
const double RT_PentatopeElement::nk[20] =
|
||||
{ 0,0,0,-1, 0,0,-1,0, 0,-1,0,0, -1,0,0,0, 1,1,1,1};
|
||||
// { .5,.5,.5, -.5,0,0, 0,-.5,0, 0,0,-.5}; // n_F |F|
|
||||
|
||||
const double RT_PentatopeElement::c = 1./5.;
|
||||
|
||||
RT_PentatopeElement::RT_PentatopeElement(const int p)
|
||||
: VectorFiniteElement(4, Geometry::PENTATOPE, (p + 1)*(p + 2)*(p + 3)*(p + 5)/6,
|
||||
p + 1, H_DIV, FunctionSpace::Pk),
|
||||
dof2nk(dof)
|
||||
{
|
||||
const double *iop = (p > 0) ? poly1d.OpenPoints(p - 1) : NULL;
|
||||
const double *bop = poly1d.OpenPoints(p);
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
shape_x.SetSize(p + 1);
|
||||
shape_y.SetSize(p + 1);
|
||||
shape_z.SetSize(p + 1);
|
||||
shape_t.SetSize(p + 1);
|
||||
shape_l.SetSize(p + 1);
|
||||
dshape_x.SetSize(p + 1);
|
||||
dshape_y.SetSize(p + 1);
|
||||
dshape_z.SetSize(p + 1);
|
||||
dshape_t.SetSize(p + 1);
|
||||
dshape_l.SetSize(p + 1);
|
||||
u.SetSize(dof, dim);
|
||||
divu.SetSize(dof);
|
||||
#else
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p + 1),
|
||||
shape_l(p + 1);
|
||||
#endif
|
||||
|
||||
int o = 0;
|
||||
// faces (see Mesh::GenerateFaces in mesh/mesh.cpp,
|
||||
// the constructor of H1_PentatopeElement)
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (0,1,2,3)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(bop[i]/w, bop[j]/w, bop[k]/w, 0.);
|
||||
dof2nk[o++] = 0;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (0,2,1,4)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(bop[j]/w, bop[i]/w, 0., bop[k]/w);
|
||||
dof2nk[o++] = 1;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (0,1,3,4)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(bop[i]/w, 0., bop[j]/w, bop[k]/w);
|
||||
dof2nk[o++] = 2;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (0,3,2,4)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(0., bop[j]/w, bop[i]/w, bop[k]/w);
|
||||
dof2nk[o++] = 3;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++) // (1,2,3,4)
|
||||
{
|
||||
double w = bop[i] + bop[j] + bop[k] + bop[p-i-j-k];
|
||||
Nodes.IntPoint(o).Set4(bop[p-i-j-k]/w, bop[i]/w, bop[j]/w, bop[k]/w);
|
||||
dof2nk[o++] = 4;
|
||||
}
|
||||
|
||||
// interior
|
||||
for (int l = 0; l < p; l++)
|
||||
for (int k = 0; k + l < p; k++)
|
||||
for (int j = 0; j + k + l < p; j++)
|
||||
for (int i = 0; i + j + k + l < p; i++)
|
||||
{
|
||||
double w = iop[i] + iop[j] + iop[k] + iop[l] + iop[p-1-i-j-k-l];
|
||||
Nodes.IntPoint(o).Set4(iop[i]/w, iop[j]/w, iop[k]/w, iop[l]/w);
|
||||
dof2nk[o++] = 1;
|
||||
Nodes.IntPoint(o).Set4(iop[i]/w, iop[j]/w, iop[k]/w, iop[l]/w);
|
||||
dof2nk[o++] = 2;
|
||||
Nodes.IntPoint(o).Set4(iop[i]/w, iop[j]/w, iop[k]/w, iop[l]/w);
|
||||
dof2nk[o++] = 3;
|
||||
Nodes.IntPoint(o).Set4(iop[i]/w, iop[j]/w, iop[k]/w, iop[l]/w);
|
||||
dof2nk[o++] = 4;
|
||||
}
|
||||
|
||||
DenseMatrix T(dof);
|
||||
for (int m = 0; m < dof; m++)
|
||||
{
|
||||
const IntegrationPoint &ip = Nodes.IntPoint(m);
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
const double *nm = nk + 4*dof2nk[m];
|
||||
|
||||
o = 0;
|
||||
for (int l = 0; l<= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
T(o++, m) = s * nm[0];
|
||||
T(o++, m) = s * nm[1];
|
||||
T(o++, m) = s * nm[2];
|
||||
T(o++, m) = s * nm[3];
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++)
|
||||
{
|
||||
double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(p-i-j-k);
|
||||
T(o++, m) = s*((ip.x - c)*nm[0] + (ip.y - c)*nm[1] +
|
||||
(ip.z - c)*nm[2] + (ip.t - c)*nm[3]);
|
||||
}
|
||||
}
|
||||
|
||||
Ti.Factor(T);
|
||||
// mfem::out << "RT_TetrahedronElement(" << p << ") : "; Ti.TestInversion();
|
||||
}
|
||||
|
||||
void RT_PentatopeElement::CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const
|
||||
{
|
||||
const int p = order - 1;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_t(p + 1),
|
||||
shape_l(p + 1);
|
||||
DenseMatrix u(Dof, Dim);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l);
|
||||
|
||||
int o = 0;
|
||||
for (int l = 0; l <= p; l++)
|
||||
for (int k = 0; k + l <= p; k++)
|
||||
for (int j = 0; j + k + l <= p; j++)
|
||||
for (int i = 0; i + j + k + l <= p; i++)
|
||||
{
|
||||
double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(l)*shape_l(p-i-j-k-l);
|
||||
u(o,0) = s; u(o,1) = 0; u(o,2) = 0; u(o,3) = 0; o++;
|
||||
u(o,0) = 0; u(o,1) = s; u(o,2) = 0; u(o,3) = 0; o++;
|
||||
u(o,0) = 0; u(o,1) = 0; u(o,2) = s; u(o,3) = 0; o++;
|
||||
u(o,0) = 0; u(o,1) = 0; u(o,2) = 0; u(o,3) = s; o++;
|
||||
}
|
||||
for (int k = 0; k <= p; k++)
|
||||
for (int j = 0; j + k <= p; j++)
|
||||
for (int i = 0; i + j + k <= p; i++)
|
||||
{
|
||||
double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_t(p-i-j-k);
|
||||
u(o,0) = (ip.x - c)*s; u(o,1) = (ip.y - c)*s; u(o,2) = (ip.z - c)*s;
|
||||
u(o,3) = (ip.t - c)*s;
|
||||
o++;
|
||||
}
|
||||
|
||||
Ti.Mult(u, shape);
|
||||
}
|
||||
|
||||
void RT_PentatopeElement::CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const
|
||||
{
|
||||
const int p = order - 1;
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1);
|
||||
Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1);
|
||||
Vector divu(Dof);
|
||||
#endif
|
||||
|
||||
poly1d.CalcBasis(p, ip.x, shape_x, dshape_x);
|
||||
poly1d.CalcBasis(p, ip.y, shape_y, dshape_y);
|
||||
poly1d.CalcBasis(p, ip.z, shape_z, dshape_z);
|
||||
poly1d.CalcBasis(p, ip.t, shape_t, dshape_t);
|
||||
poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z - ip.t, shape_l, dshape_l);
|
||||
|
||||
int o = 0;
|
||||
for (int m = 0; m <= p; m++)
|
||||
for (int k = 0; k + m <= p; k++)
|
||||
for (int j = 0; j + k + m <= p; j++)
|
||||
for (int i = 0; i + j + k + m <= p; i++)
|
||||
{
|
||||
int l = p - i - j - k - m;
|
||||
divu(o++) = (dshape_x(i)*shape_l(l) -
|
||||
shape_x(i)*dshape_l(l))*shape_y(j)*shape_z(k)*shape_t(m);
|
||||
divu(o++) = (dshape_y(j)*shape_l(l) -
|
||||
shape_y(j)*dshape_l(l))*shape_x(i)*shape_z(k)*shape_t(m);
|
||||
divu(o++) = (dshape_z(k)*shape_l(l) -
|
||||
shape_z(k)*dshape_l(l))*shape_x(i)*shape_y(j)*shape_t(m);
|
||||
divu(o++) = (dshape_t(m)*shape_l(l) -
|
||||
shape_t(m)*dshape_l(l))*shape_x(i)*shape_y(j)*shape_z(k);
|
||||
}
|
||||
for (int l = 0; l <= p; l++)
|
||||
for (int j = 0; j + l<= p; j++)
|
||||
for (int i = 0; i + j + l <= p; i++)
|
||||
{
|
||||
int k = p - i - j - l;
|
||||
divu(o++) =
|
||||
(shape_x(i) + (ip.x - c)*dshape_x(i))*shape_y(j)*shape_z(l)*shape_t(k) +
|
||||
(shape_y(j) + (ip.y - c)*dshape_y(j))*shape_x(i)*shape_z(l)*shape_t(k) +
|
||||
(shape_z(l) + (ip.z - c)*dshape_z(l))*shape_x(i)*shape_y(j)*shape_t(k) +
|
||||
(shape_t(k) + (ip.t - c)*dshape_t(k))*shape_x(i)*shape_y(j)*shape_z(l);
|
||||
}
|
||||
|
||||
Ti.Mult(divu, divshape);
|
||||
}
|
||||
|
||||
void RT_PentatopeElement::ProjectDivSkew(const FiniteElement& fe,
|
||||
ElementTransformation& Trans, DenseMatrix& DivSkew) const
|
||||
{
|
||||
int dof = fe.GetDof();
|
||||
|
||||
mfem_warning("RT_PentatopeElement::ProjectDivSkew(...) Implementation not tested!"); // TODO
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix Jinv(dim, dim);
|
||||
#endif
|
||||
|
||||
DivSkew.SetSize(dof,dof);
|
||||
DivSkew = 0.0;
|
||||
|
||||
double n[4];
|
||||
Vector ni(n, 4);
|
||||
Vector vecF(4);
|
||||
|
||||
DenseMatrix DivSkewshape(dof,4);
|
||||
DenseMatrix DivSkew_dFt(dof,4);
|
||||
for (int k = 0; k < dof; k++)
|
||||
{
|
||||
Trans.SetIntPoint(&Nodes.IntPoint(k));
|
||||
const DenseMatrix &J = Trans.Jacobian();
|
||||
CalcAdjugateTranspose(J, Jinv);
|
||||
|
||||
fe.CalcDivSkewShape(Nodes.IntPoint(k), DivSkewshape);
|
||||
MultABt(DivSkewshape, J, DivSkew_dFt);
|
||||
DivSkew_dFt *= (1.0 / Trans.Weight());
|
||||
|
||||
Jinv.Mult(nk + dof2nk[k] * dim,n);
|
||||
|
||||
for (int j=0; j<dof; j++)
|
||||
{
|
||||
vecF(0) = DivSkew_dFt(j,0);
|
||||
vecF(1) = DivSkew_dFt(j,1);
|
||||
vecF(2) = DivSkew_dFt(j,2);
|
||||
vecF(3) = DivSkew_dFt(j,3);
|
||||
|
||||
DivSkew(k, j) = vecF * ni;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -524,6 +524,53 @@ public:
|
||||
Vector &divshape) const;
|
||||
};
|
||||
|
||||
class RT_PentatopeElement : public VectorFiniteElement
|
||||
{
|
||||
static const double nk[20], c;
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector shape_x, shape_y, shape_z, shape_t, shape_l;
|
||||
mutable Vector dshape_x, dshape_y, dshape_z, dshape_t, dshape_l;
|
||||
mutable DenseMatrix u;
|
||||
mutable Vector divu;
|
||||
#endif
|
||||
Array<int> dof2nk;
|
||||
DenseMatrixInverse Ti;
|
||||
|
||||
public:
|
||||
RT_PentatopeElement(const int p);
|
||||
virtual void CalcVShape(const IntegrationPoint &ip,
|
||||
DenseMatrix &shape) const;
|
||||
virtual void CalcVShape(ElementTransformation &Trans,
|
||||
DenseMatrix &shape) const
|
||||
{ CalcVShape_RT(Trans, shape); }
|
||||
virtual void CalcDivShape(const IntegrationPoint &ip,
|
||||
Vector &divshape) const;
|
||||
virtual void GetLocalInterpolation(ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ LocalInterpolation_RT(*this, nk, dof2nk, Trans, I); }
|
||||
virtual void GetLocalRestriction(ElementTransformation &Trans,
|
||||
DenseMatrix &R) const
|
||||
{ LocalRestriction_RT(nk, dof2nk, Trans, R); }
|
||||
virtual void GetTransferMatrix(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ LocalInterpolation_RT(CheckVectorFE(fe), nk, dof2nk, Trans, I); }
|
||||
using FiniteElement::Project;
|
||||
virtual void Project(VectorCoefficient &vc,
|
||||
ElementTransformation &Trans, Vector &dofs) const
|
||||
{ Project_RT(nk, dof2nk, vc, Trans, dofs); }
|
||||
virtual void ProjectMatrixCoefficient(
|
||||
MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
|
||||
{ ProjectMatrixCoefficient_RT(nk, dof2nk, mc, T, dofs); }
|
||||
virtual void Project(const FiniteElement &fe, ElementTransformation &Trans,
|
||||
DenseMatrix &I) const
|
||||
{ Project_RT(nk, dof2nk, fe, Trans, I); }
|
||||
virtual void ProjectDivSkew(const FiniteElement &fe,
|
||||
ElementTransformation &Trans,
|
||||
DenseMatrix &DivSkew) const;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mfem
|
||||
|
||||
|
||||
+345
-2
@@ -111,12 +111,29 @@ int FiniteElementCollection::HasFaceDofs(Geometry::Type geom, int p) const
|
||||
case Geometry::PYRAMID:
|
||||
return max(GetNumDof(Geometry::TRIANGLE, p),
|
||||
GetNumDof(Geometry::SQUARE, p));
|
||||
case Geometry::PENTATOPE:
|
||||
return GetNumDof(Geometry::TETRAHEDRON, p);
|
||||
case Geometry::TESSERACT:
|
||||
return GetNumDof(Geometry::CUBE, p);
|
||||
default:
|
||||
MFEM_ABORT("unknown geometry type");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FiniteElementCollection::HasPlanarDofs(Geometry::Type GeomType, int p) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::PENTATOPE: return GetNumDof(Geometry::TRIANGLE, p);
|
||||
case Geometry::TESSERACT: return GetNumDof(Geometry::SQUARE, p);
|
||||
default:
|
||||
mfem_error ("FiniteElementCollection::HasPlanarDofs:"
|
||||
" unknown geometry type.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
FiniteElementCollection *FiniteElementCollection::GetTraceCollection() const
|
||||
{
|
||||
MFEM_ABORT("this method is not implemented in this derived class!");
|
||||
@@ -653,6 +670,8 @@ LinearFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PYRAMID: return &PyramidFE;
|
||||
case Geometry::PENTATOPE: return &PentatopeFE;
|
||||
case Geometry::TESSERACT: return &TesseractFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("LinearFECollection: unknown geometry type.");
|
||||
@@ -672,6 +691,8 @@ int LinearFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PRISM: return 0;
|
||||
case Geometry::PYRAMID: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
case Geometry::TESSERACT: return 0;
|
||||
default:
|
||||
mfem_error ("LinearFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -697,6 +718,7 @@ QuadraticFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::CUBE: return &ParallelepipedFE;
|
||||
case Geometry::PRISM: return &WedgeFE;
|
||||
case Geometry::PENTATOPE: return &PentatopeFE;
|
||||
default:
|
||||
if (error_mode == RETURN_NULL) { return nullptr; }
|
||||
mfem_error ("QuadraticFECollection: unknown geometry type.");
|
||||
@@ -715,6 +737,7 @@ int QuadraticFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 1;
|
||||
case Geometry::PRISM: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("QuadraticFECollection: unknown geometry type.");
|
||||
}
|
||||
@@ -1541,6 +1564,135 @@ const int *ND1_3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
return ind_neg;
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
ND1_4DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::PENTATOPE: return &NedPentatopFE;
|
||||
default:
|
||||
mfem_error ("ND1_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &NedPentatopFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
int ND1_4DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::POINT: return 0;
|
||||
case Geometry::SEGMENT: return 1;
|
||||
case Geometry::TRIANGLE: return 0;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("ND1_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int * ND1_4DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or)
|
||||
const
|
||||
{
|
||||
static int ind_pos[] = { 0 };
|
||||
static int ind_neg[] = { -1 };
|
||||
|
||||
if (Or > 0)
|
||||
{
|
||||
return ind_pos;
|
||||
}
|
||||
return ind_neg;
|
||||
}
|
||||
|
||||
|
||||
const FiniteElement *
|
||||
ND2_4DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::PENTATOPE: return &NedPentatopFE;
|
||||
default:
|
||||
mfem_error ("ND2_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &NedPentatopFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
int ND2_4DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::POINT: return 0;
|
||||
case Geometry::SEGMENT: return 2;
|
||||
case Geometry::TRIANGLE: return 0;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("ND2_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int * ND2_4DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or)
|
||||
const
|
||||
{
|
||||
static int ind_pos[] = { 0, 1 };
|
||||
static int ind_neg[] = { -2, -1};
|
||||
|
||||
if (Or > 0)
|
||||
{
|
||||
return ind_pos;
|
||||
}
|
||||
return ind_neg;
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
DivSkew1_4DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::PENTATOPE: return &DivSkew0PentatopFE;
|
||||
default:
|
||||
mfem_error ("DivSkew1_4DFECollection: unknown geometry type 1.");
|
||||
}
|
||||
return &DivSkew0PentatopFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
int DivSkew1_4DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::POINT: return 0;
|
||||
case Geometry::SEGMENT: return 0;
|
||||
case Geometry::TRIANGLE: return 1;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 0;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("DivSkew1_4DFECollection: unknown geometry type 2.");
|
||||
}
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int * DivSkew1_4DFECollection::DofOrderForOrientation(
|
||||
Geometry::Type GeomType, int Or)
|
||||
const
|
||||
{
|
||||
static int ind_pos[] = { 0 };
|
||||
static int ind_neg[] = { -1 };
|
||||
|
||||
if (Or %2 == 0)
|
||||
{
|
||||
return ind_pos;
|
||||
}
|
||||
return ind_neg;
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
RT0_3DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
@@ -1646,13 +1798,57 @@ const int *RT1_3DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
RT0_4DFECollection::FiniteElementForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::TETRAHEDRON: return &TetrahedronFE;
|
||||
case Geometry::PENTATOPE: return &PentatopeFE;
|
||||
default:
|
||||
mfem_error ("RT0_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return &PentatopeFE; // Make some compilers happy
|
||||
}
|
||||
|
||||
int RT0_4DFECollection::DofForGeometry(Geometry::Type GeomType) const
|
||||
{
|
||||
switch (GeomType)
|
||||
{
|
||||
case Geometry::POINT: return 0;
|
||||
case Geometry::SEGMENT: return 0;
|
||||
case Geometry::TRIANGLE: return 0;
|
||||
case Geometry::SQUARE: return 0;
|
||||
case Geometry::TETRAHEDRON: return 1;
|
||||
case Geometry::CUBE: return 0;
|
||||
case Geometry::PENTATOPE: return 0;
|
||||
default:
|
||||
mfem_error ("RT0_4DFECollection: unknown geometry type.");
|
||||
}
|
||||
return 0; // Make some compilers happy
|
||||
}
|
||||
|
||||
const int * RT0_4DFECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or)
|
||||
const
|
||||
{
|
||||
static int ind_pos[] = { 0 };
|
||||
static int ind_neg[] = { -1 };
|
||||
|
||||
if (GeomType == Geometry::TETRAHEDRON)
|
||||
{
|
||||
if (Or % 2 == 0) { return ind_pos; }
|
||||
return ind_neg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
: FiniteElementCollection(p)
|
||||
, dim(dim)
|
||||
{
|
||||
MFEM_VERIFY(p >= 1, "H1_FECollection requires order >= 1.");
|
||||
MFEM_VERIFY(dim >= 0 && dim <= 3, "H1_FECollection requires 0 <= dim <= 3.");
|
||||
MFEM_VERIFY(dim >= 0 && dim <= 4, "H1_FECollection requires 0 <= dim <= 4.");
|
||||
|
||||
const int pm1 = p - 1, pm2 = pm1 - 1, pm3 = pm2 - 1, pm4 = pm3 - 1;
|
||||
|
||||
@@ -1953,6 +2149,20 @@ H1_FECollection::H1_FECollection(const int p, const int dim, const int btype)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dim >= 4)
|
||||
{
|
||||
H1_dof[Geometry::PENTATOPE] = (TriDof*pm3*pm4)/12;
|
||||
H1_dof[Geometry::TESSERACT] = QuadDof*pm1*pm1;
|
||||
if (b_type == BasisType::Positive)
|
||||
{
|
||||
mfem_error("H1_FECollection: BasisType::Positive not implemented");
|
||||
}
|
||||
else
|
||||
{
|
||||
H1_Elements[Geometry::PENTATOPE] = new H1_PentatopeElement(p, pt_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2330,6 +2540,38 @@ L2_FECollection::L2_FECollection(const int p, const int dim, const int btype,
|
||||
OtherDofOrd[j] = j; // for Or == 0
|
||||
}
|
||||
}
|
||||
else if (dim == 4)
|
||||
{
|
||||
if (b_type == BasisType::Positive)
|
||||
{
|
||||
mfem::err <<
|
||||
"L2_FECollection::L2_FECollection : BasisType::Positive not implemented" <<
|
||||
endl;
|
||||
mfem_error();
|
||||
}
|
||||
else
|
||||
{
|
||||
L2_Elements[Geometry::PENTATOPE] =
|
||||
new L2_PentatopeElement(p, btype);
|
||||
|
||||
// 2025 November: check this
|
||||
L2_Elements[Geometry::TESSERACT] = new L2_HexahedronElement(p, btype);
|
||||
}
|
||||
L2_Elements[Geometry::PENTATOPE]->SetMapType(map_type);
|
||||
L2_Elements[Geometry::TESSERACT]->SetMapType(map_type);
|
||||
// All trace element use the default Gauss-Legendre nodal points
|
||||
Tr_Elements[Geometry::TETRAHEDRON] = new L2_TetrahedronElement(p);
|
||||
Tr_Elements[Geometry::CUBE] = new L2_HexahedronElement(p);
|
||||
|
||||
const int PentDof = L2_Elements[Geometry::PENTATOPE]->GetDof();
|
||||
const int TessDof = L2_Elements[Geometry::TESSERACT]->GetDof();
|
||||
const int MaxDof = std::max(PentDof, TessDof);
|
||||
OtherDofOrd = new int[MaxDof];
|
||||
for (int j = 0; j < MaxDof; j++)
|
||||
{
|
||||
OtherDofOrd[j] = j; // for Or == 0
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mfem::err << "L2_FECollection::L2_FECollection : dim = "
|
||||
@@ -2368,6 +2610,9 @@ const int *L2_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
case Geometry::TETRAHEDRON:
|
||||
return TetDofOrd[Or%24];
|
||||
|
||||
case Geometry::PENTATOPE:
|
||||
return TetDofOrd[Or%120];
|
||||
|
||||
default:
|
||||
return (Or == 0) ? OtherDofOrd : NULL;
|
||||
}
|
||||
@@ -2452,6 +2697,13 @@ RT_FECollection::RT_FECollection(const int order, const int dim,
|
||||
RT_Elements[Geometry::PYRAMID] = new RT0PyrFiniteElement(false);
|
||||
RT_dof[Geometry::PYRAMID] = 0;
|
||||
}
|
||||
else if (dim == 4)
|
||||
{
|
||||
RT_Elements[Geometry::PENTATOPE] = new RT_PentatopeElement(p);
|
||||
RT_dof[Geometry::PENTATOPE] = p*pp1*(p + 2)*(p + 3)/6;
|
||||
|
||||
//TODO: tesseracts
|
||||
}
|
||||
else
|
||||
{
|
||||
MFEM_ABORT("invalid dim = " << dim);
|
||||
@@ -2484,7 +2736,7 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
MFEM_VERIFY(Quadrature1D::CheckOpen(op_type) != Quadrature1D::Invalid,
|
||||
"invalid open point type");
|
||||
|
||||
const int pp1 = p + 1, pp2 = p + 2;
|
||||
const int pp1 = p + 1, pp2 = p + 2, pp3 = p + 3;
|
||||
|
||||
for (int g = 0; g < Geometry::NumGeom; g++)
|
||||
{
|
||||
@@ -2504,6 +2756,10 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
{
|
||||
QuadDofOrd[i] = NULL;
|
||||
}
|
||||
for (int i = 0; i < 24; i++)
|
||||
{
|
||||
TetDofOrd[i] = NULL;
|
||||
}
|
||||
|
||||
if (dim_ == 2)
|
||||
{
|
||||
@@ -2592,6 +2848,89 @@ void RT_FECollection::InitFaces(const int p, const int dim_,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (dim == 4)
|
||||
{
|
||||
L2_TetrahedronElement *l2_tet = new L2_TetrahedronElement(p, ob_type);
|
||||
l2_tet->SetMapType(map_type);
|
||||
RT_Elements[Geometry::TETRAHEDRON] = l2_tet;
|
||||
RT_dof[Geometry::TETRAHEDRON] = pp1*pp2*pp3/6;
|
||||
|
||||
int TetDof = RT_dof[Geometry::TETRAHEDRON];
|
||||
int TriDof2 = pp2*pp1/2;
|
||||
TetDofOrd[0] = new int[24*TetDof];
|
||||
for (int i = 1; i < 24; i++)
|
||||
{
|
||||
TetDofOrd[i] = TetDofOrd[i-1] + TetDof;
|
||||
}
|
||||
// see Mesh::GetTriOrientation in mesh/mesh.cpp,
|
||||
// the constructor of H1_FECollection
|
||||
for (int k=0; k<=p; k++)
|
||||
{
|
||||
for (int j=0; j+k<=p; j++)
|
||||
{
|
||||
for (int i=0; i+j+k<=p; i++)
|
||||
{
|
||||
int o = TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 - (pp2-j)*
|
||||
(pp1-j)/2 - k*j + i;
|
||||
int l = p-k-j-i;
|
||||
TetDofOrd[0][o] = o;
|
||||
TetDofOrd[1][o] = -1 - (TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - k*j + l);
|
||||
TetDofOrd[2][o] = TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - k*i + l;
|
||||
TetDofOrd[3][o] = -1 - (TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - k*l + i);
|
||||
TetDofOrd[4][o] = TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - k*l + j;
|
||||
TetDofOrd[5][o] = -1 - (TetDof + TriDof2 - ((pp3-k)*(pp2-k)*(pp1-k))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - k*i + j);
|
||||
TetDofOrd[6][o] = TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - j*i + k;
|
||||
TetDofOrd[7][o] = -1 - (TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - j*l + k);
|
||||
TetDofOrd[8][o] = TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - i*l + k;
|
||||
TetDofOrd[9][o] = -1 - (TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - l*i + k);
|
||||
TetDofOrd[10][o] = TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - l*j + k;
|
||||
TetDofOrd[11][o] = -1 - (TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - i*j + k);
|
||||
TetDofOrd[12][o] = TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - i*k + j;
|
||||
TetDofOrd[13][o] = -1 - (TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - l*k + j);
|
||||
TetDofOrd[14][o] = TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - l*k + i;
|
||||
TetDofOrd[15][o] = -1 - (TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - i*k + l);
|
||||
TetDofOrd[16][o] = TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - j*k + l;
|
||||
TetDofOrd[17][o] = -1 - (TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-k)*(pp1-k)/2 - j*k + i);
|
||||
TetDofOrd[18][o] = TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - j*l + i;
|
||||
TetDofOrd[19][o] = -1 - (TetDof + TriDof2 - ((pp3-j)*(pp2-j)*(pp1-j))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - j*i + l);
|
||||
TetDofOrd[20][o] = TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - i*j + l;
|
||||
TetDofOrd[21][o] = -1 - (TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-j)*(pp1-j)/2 - l*j + i);
|
||||
TetDofOrd[22][o] = TetDof + TriDof2 - ((pp3-l)*(pp2-l)*(pp1-l))/6 -
|
||||
(pp2-i)*(pp1-i)/2 - l*i + j;
|
||||
TetDofOrd[23][o] = -1 - (TetDof + TriDof2 - ((pp3-i)*(pp2-i)*(pp1-i))/6 -
|
||||
(pp2-l)*(pp1-l)/2 - i*l + j);
|
||||
if (!signs)
|
||||
{
|
||||
for (int m = 0; m < 24; m+=2)
|
||||
{
|
||||
TetDofOrd[m][o] = -1 - TetDofOrd[m][o];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FiniteElement *
|
||||
@@ -2625,6 +2964,10 @@ const int *RT_FECollection::DofOrderForOrientation(Geometry::Type GeomType,
|
||||
{
|
||||
return QuadDofOrd[Or%8];
|
||||
}
|
||||
else if (GeomType == Geometry::TETRAHEDRON)
|
||||
{
|
||||
return TetDofOrd[Or%24];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
+85
-1
@@ -94,6 +94,8 @@ public:
|
||||
|
||||
int HasFaceDofs(Geometry::Type geom, int p) const;
|
||||
|
||||
int HasPlanarDofs(Geometry::Type GeomType, int p) const;
|
||||
|
||||
virtual const FiniteElement *TraceFiniteElementForGeometry(
|
||||
Geometry::Type GeomType) const
|
||||
{
|
||||
@@ -391,7 +393,7 @@ protected:
|
||||
char rt_name[32];
|
||||
FiniteElement *RT_Elements[Geometry::NumGeom];
|
||||
int RT_dof[Geometry::NumGeom];
|
||||
int *SegDofOrd[2], *TriDofOrd[6], *QuadDofOrd[8];
|
||||
int *SegDofOrd[2], *TriDofOrd[6], *QuadDofOrd[8], *TetDofOrd[24];
|
||||
|
||||
// Initialize only the face elements
|
||||
void InitFaces(const int p, const int dim, const int map_type,
|
||||
@@ -746,6 +748,8 @@ private:
|
||||
const TriLinear3DFiniteElement ParallelepipedFE;
|
||||
const LinearWedgeFiniteElement WedgeFE;
|
||||
const LinearPyramidFiniteElement PyramidFE;
|
||||
const Linear4DFiniteElement PentatopeFE;
|
||||
const QuadLinear4DFiniteElement TesseractFE;
|
||||
public:
|
||||
LinearFECollection() : FiniteElementCollection(1) {}
|
||||
|
||||
@@ -773,6 +777,7 @@ private:
|
||||
const Quadratic3DFiniteElement TetrahedronFE;
|
||||
const LagrangeHexFiniteElement ParallelepipedFE;
|
||||
const H1_WedgeElement WedgeFE;
|
||||
const Quadratic4DFiniteElement PentatopeFE;
|
||||
|
||||
public:
|
||||
QuadraticFECollection()
|
||||
@@ -1290,6 +1295,65 @@ public:
|
||||
int GetContType() const override { return TANGENTIAL; }
|
||||
};
|
||||
|
||||
class ND1_4DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const Nedelec1PentFiniteElement NedPentatopFE;
|
||||
|
||||
public:
|
||||
ND1_4DFECollection() { }
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
|
||||
virtual const char * Name() const { return "ND1_4D"; }
|
||||
};
|
||||
|
||||
class ND2_4DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const Nedelec1FullPentFiniteElement NedPentatopFE;
|
||||
|
||||
public:
|
||||
ND2_4DFECollection() { }
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
|
||||
virtual const char * Name() const { return "ND2_4D"; }
|
||||
};
|
||||
|
||||
|
||||
class DivSkew1_4DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const DivSkew1PentFiniteElement DivSkew0PentatopFE;
|
||||
|
||||
public:
|
||||
DivSkew1_4DFECollection() { }
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
|
||||
virtual const char * Name() const { return "F2K0_4D"; }
|
||||
};
|
||||
|
||||
|
||||
/** @brief First order Raviart-Thomas finite elements in 3D. This class is kept
|
||||
only for backward compatibility, consider using RT_FECollection instead. */
|
||||
class RT0_3DFECollection : public FiniteElementCollection
|
||||
@@ -1341,6 +1405,26 @@ public:
|
||||
int GetContType() const override { return NORMAL; }
|
||||
};
|
||||
|
||||
/** First order Raviart-Thomas finite elements in 4D. */
|
||||
class RT0_4DFECollection : public FiniteElementCollection
|
||||
{
|
||||
private:
|
||||
const P0TetFiniteElement TetrahedronFE;
|
||||
const RT0PentFiniteElement PentatopeFE;
|
||||
public:
|
||||
RT0_4DFECollection() { };
|
||||
|
||||
virtual const FiniteElement *
|
||||
FiniteElementForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual int DofForGeometry(Geometry::Type GeomType) const;
|
||||
|
||||
virtual const int * DofOrderForOrientation(Geometry::Type GeomType,
|
||||
int Or) const;
|
||||
|
||||
virtual const char * Name() const { return "RT0_4D"; };
|
||||
};
|
||||
|
||||
/// Discontinuous collection defined locally by a given finite element.
|
||||
class Local_FECollection : public FiniteElementCollection
|
||||
{
|
||||
|
||||
+356
-13
@@ -58,8 +58,8 @@ DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
|
||||
|
||||
FiniteElementSpace::FiniteElementSpace()
|
||||
: mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
|
||||
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
|
||||
bdofs(NULL),
|
||||
ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0), npdofs(0),
|
||||
bdofs(NULL), pdofs(NULL),
|
||||
elem_dof(NULL), elem_fos(NULL), bdr_elem_dof(NULL), bdr_elem_fos(NULL),
|
||||
face_dof(NULL),
|
||||
NURBSext(NULL), own_ext(false),
|
||||
@@ -319,6 +319,12 @@ void FiniteElementSpace::GetFaceVDofs(int i, Array<int> &vdofs) const
|
||||
DofsToVDofs(vdofs);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetPlanarVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
GetPlanarDofs(i, vdofs);
|
||||
DofsToVDofs(vdofs);
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetEdgeVDofs(int i, Array<int> &vdofs) const
|
||||
{
|
||||
GetEdgeDofs(i, vdofs);
|
||||
@@ -540,7 +546,13 @@ void FiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
|
||||
// local DOFs affected by boundary elements on other processors
|
||||
if (Nonconforming())
|
||||
{
|
||||
Array<int> bdr_verts, bdr_edges, bdr_faces;
|
||||
Array<int> bdr_verts, bdr_edges, bdr_faces, bdr_planars;
|
||||
// if (mesh->Dimension() > 3)
|
||||
// {
|
||||
// mesh->ncmesh->GetBoundaryClosure(bdr_attr_is_ess, bdr_verts, bdr_edges,
|
||||
// bdr_faces, bdr_planars);
|
||||
// }
|
||||
// else
|
||||
mesh->ncmesh->GetBoundaryClosure(bdr_attr_is_ess, bdr_verts, bdr_edges,
|
||||
bdr_faces);
|
||||
for (auto v : bdr_verts)
|
||||
@@ -582,6 +594,20 @@ void FiniteElementSpace::GetEssentialVDofs(const Array<int> &bdr_attr_is_ess,
|
||||
}
|
||||
MarkDofs(dofs, ess_vdofs);
|
||||
}
|
||||
for (int i = 0; i < bdr_planars.Size(); i++)
|
||||
{
|
||||
if (component < 0)
|
||||
{
|
||||
GetPlanarVDofs(bdr_planars[i], dofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetPlanarVDofs(bdr_planars[i], dofs);
|
||||
for (int d = 0; d < dofs.Size(); d++)
|
||||
{ dofs[d] = DofToVDof(dofs[d], component); }
|
||||
}
|
||||
MarkDofs(dofs, ess_vdofs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,6 +1015,8 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
"This method should not be used with a ParFiniteElementSpace!");
|
||||
#endif
|
||||
|
||||
if (mesh->Dimension() == 4) { BuildConformingInterpolation4D(); return; }
|
||||
|
||||
if (cP_is_set) { return; }
|
||||
cP_is_set = true;
|
||||
|
||||
@@ -1271,6 +1299,178 @@ void FiniteElementSpace::BuildConformingInterpolation() const
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::BuildConformingInterpolation4D() const
|
||||
{
|
||||
#if 0
|
||||
#ifdef MFEM_USE_MPI
|
||||
MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
|
||||
"This method should not be used with a ParFiniteElementSpace!");
|
||||
#endif
|
||||
|
||||
if (cP_is_set) { return; }
|
||||
cP_is_set = true;
|
||||
|
||||
// For each slave DOF, the dependency matrix will contain a row that
|
||||
// expresses the slave DOF as a linear combination of its immediate master
|
||||
// DOFs. Rows of independent DOFs will remain empty.
|
||||
SparseMatrix deps(ndofs);
|
||||
|
||||
// collect local edge/planar/face dependencies
|
||||
for (int entity = 1; entity <= 3; entity++)
|
||||
{
|
||||
const NCMesh::NCList &list = (entity > 2) ? mesh->ncmesh->GetFaceList()
|
||||
/* */ : ( (entity > 1) ? mesh->ncmesh->GetPlanarList() :
|
||||
mesh->ncmesh->GetEdgeList() );
|
||||
if (!list.masters.size()) { continue; }
|
||||
|
||||
IsoparametricTransformation T;
|
||||
if (entity > 2) { T.SetFE(&TetrahedronFE); }
|
||||
else if (entity > 1) { T.SetFE(&TriangleFE); }
|
||||
else { T.SetFE(&SegmentFE); }
|
||||
|
||||
Geometry::Type geom = (entity > 2) ? Geometry::TETRAHEDRON : ( (
|
||||
entity > 1) ? Geometry::TRIANGLE : Geometry::SEGMENT );
|
||||
const FiniteElement* fe = fec->FiniteElementForGeometry(geom);
|
||||
if (!fe) { continue; }
|
||||
|
||||
Array<int> master_dofs, slave_dofs;
|
||||
DenseMatrix I(fe->GetDof());
|
||||
|
||||
// loop through all master edges/faces, constrain their slave edges/faces
|
||||
for (unsigned mi = 0; mi < list.masters.size(); mi++)
|
||||
{
|
||||
const NCMesh::Master &master = list.masters[mi];
|
||||
GetEntityDofs4D(entity, master.index, master_dofs);
|
||||
if (!master_dofs.Size()) { continue; }
|
||||
|
||||
// mfem::out << "--------------------\n";
|
||||
// master_dofs.Print(mfem::out,master_dofs.Size());
|
||||
|
||||
for (int si = master.slaves_begin; si < master.slaves_end; si++)
|
||||
{
|
||||
const NCMesh::Slave &slave = list.slaves[si];
|
||||
GetEntityDofs4D(entity, slave.index, slave_dofs);
|
||||
if (!slave_dofs.Size()) { continue; }
|
||||
|
||||
slave.OrientedPointMatrix(T.GetPointMat());
|
||||
T.FinalizeTransformation();
|
||||
fe->GetLocalInterpolation(T, I);
|
||||
|
||||
// mfem::out << "********************\n";
|
||||
// slave_dofs.Print(mfem::out,slave_dofs.Size());
|
||||
// mfem::out << "++++++++++++++++++++\n";
|
||||
// I.PrintMatlab(mfem::out);
|
||||
// mfem::out << "++++++++++++++++++++\n";
|
||||
|
||||
// make each slave DOF dependent on all master DOFs
|
||||
AddDependencies(deps, master_dofs, slave_dofs, I);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deps.Finalize();
|
||||
// deps.PrintMatlab(mfem::out);
|
||||
|
||||
// DOFs that stayed independent are true DOFs
|
||||
int n_true_dofs = 0;
|
||||
for (int i = 0; i < ndofs; i++)
|
||||
{
|
||||
if (!deps.RowSize(i)) { n_true_dofs++; }
|
||||
}
|
||||
|
||||
// if all dofs are true dofs leave cP and cR NULL
|
||||
if (n_true_dofs == ndofs)
|
||||
{
|
||||
cP = cR = NULL; // will be treated as identities
|
||||
return;
|
||||
}
|
||||
|
||||
// create the conforming restriction matrix cR
|
||||
int *cR_J;
|
||||
{
|
||||
int *cR_I = new int[n_true_dofs+1];
|
||||
double *cR_A = new double[n_true_dofs];
|
||||
cR_J = new int[n_true_dofs];
|
||||
for (int i = 0; i < n_true_dofs; i++)
|
||||
{
|
||||
cR_I[i] = i;
|
||||
cR_A[i] = 1.0;
|
||||
}
|
||||
cR_I[n_true_dofs] = n_true_dofs;
|
||||
cR = new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs);
|
||||
}
|
||||
|
||||
// create the conforming prolongation matrix cP
|
||||
cP = new SparseMatrix(ndofs, n_true_dofs);
|
||||
|
||||
Array<bool> finalized(ndofs);
|
||||
finalized = false;
|
||||
|
||||
// put identity in the restriction and prolongation matrices for true DOFs
|
||||
for (int i = 0, true_dof = 0; i < ndofs; i++)
|
||||
{
|
||||
if (!deps.RowSize(i))
|
||||
{
|
||||
cR_J[true_dof] = i;
|
||||
cP->Add(i, true_dof++, 1.0);
|
||||
finalized[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Now calculate cP rows of slave DOFs as combinations of cP rows of their
|
||||
// master DOFs. It is possible that some slave DOFs depend on DOFs that are
|
||||
// themselves slaves. Here we resolve such indirect constraints by first
|
||||
// calculating rows of the cP matrix for DOFs whose master DOF cP rows are
|
||||
// already known (in the first iteration these are the true DOFs). In the
|
||||
// second iteration, slaves of slaves can be 'finalized' (given a row in the
|
||||
// cP matrix), in the third iteration slaves of slaves of slaves, etc.
|
||||
bool finished;
|
||||
int n_finalized = n_true_dofs;
|
||||
Array<int> cols;
|
||||
Vector srow;
|
||||
do
|
||||
{
|
||||
finished = true;
|
||||
for (int dof = 0; dof < ndofs; dof++)
|
||||
{
|
||||
if (!finalized[dof] && DofFinalizable(dof, finalized, deps))
|
||||
{
|
||||
const int* dep_col = deps.GetRowColumns(dof);
|
||||
const double* dep_coef = deps.GetRowEntries(dof);
|
||||
int n_dep = deps.RowSize(dof);
|
||||
|
||||
for (int j = 0; j < n_dep; j++)
|
||||
{
|
||||
cP->GetRow(dep_col[j], cols, srow);
|
||||
srow *= dep_coef[j];
|
||||
cP->AddRow(dof, cols, srow);
|
||||
}
|
||||
|
||||
finalized[dof] = true;
|
||||
n_finalized++;
|
||||
finished = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!finished);
|
||||
|
||||
// if everything is consistent (mesh, face orientations, etc.), we should
|
||||
// be able to finalize all slave DOFs, otherwise it's a serious error
|
||||
if (n_finalized != ndofs)
|
||||
{
|
||||
MFEM_ABORT("Error creating cP matrix.");
|
||||
}
|
||||
|
||||
cP->Finalize();
|
||||
|
||||
if (vdim > 1)
|
||||
{
|
||||
MakeVDimMatrix(*cP);
|
||||
MakeVDimMatrix(*cR);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FiniteElementSpace::MakeVDimMatrix(SparseMatrix &mat) const
|
||||
{
|
||||
if (vdim == 1) { return; }
|
||||
@@ -2304,8 +2504,10 @@ void FiniteElementSpace::UpdateNURBS()
|
||||
|
||||
nvdofs = 0;
|
||||
nedofs = 0;
|
||||
npdofs = 0;
|
||||
nfdofs = 0;
|
||||
nbdofs = 0;
|
||||
pdofs = NULL;
|
||||
bdofs = NULL;
|
||||
|
||||
delete face_dof;
|
||||
@@ -2388,6 +2590,8 @@ void FiniteElementSpace::Construct()
|
||||
face_dof = NULL;
|
||||
|
||||
ndofs = 0;
|
||||
npdofs = 0;
|
||||
pdofs = NULL;
|
||||
nvdofs = nedofs = nfdofs = nbdofs = 0;
|
||||
bdofs = NULL;
|
||||
|
||||
@@ -2460,6 +2664,24 @@ void FiniteElementSpace::Construct()
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh->Dimension() >= 4 && mesh->GetNE())
|
||||
{
|
||||
// Here we assume that all planars in the mesh have the same base
|
||||
// geometry -- the base geometry of the 0-th face element.
|
||||
int pdof = fec->DofForGeometry(mesh->GetPlanarBaseGeometry(0));
|
||||
if (pdof > 0)
|
||||
{
|
||||
pdofs = new int[mesh->GetNPlanars()+1];
|
||||
pdofs[0] = 0;
|
||||
for (int i = 0; i < mesh->GetNPlanars(); i++)
|
||||
{
|
||||
npdofs += pdof;
|
||||
// npdofs += fec->DofForGeometry(mesh->GetPlanarBaseGeometry(i));
|
||||
pdofs[i+1] = npdofs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assign internal ("bubble") DOFs
|
||||
if (mesh->GetNE() && dim > 0)
|
||||
{
|
||||
@@ -2483,7 +2705,7 @@ void FiniteElementSpace::Construct()
|
||||
}
|
||||
}
|
||||
|
||||
ndofs = nvdofs + nedofs + nfdofs + nbdofs;
|
||||
ndofs = nvdofs + nedofs + npdofs + nfdofs + nbdofs;
|
||||
|
||||
ConstructDoFTransArray();
|
||||
|
||||
@@ -2756,7 +2978,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
return;
|
||||
}
|
||||
|
||||
Array<int> V, E, Eo, F, Fo; // TODO: LocalArray
|
||||
Array<int> V, E, Eo, F, Fo, P, Po; // TODO: LocalArray
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
auto geom = mesh->GetElementGeometry(elem);
|
||||
@@ -2765,9 +2987,11 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
int nv = fec->GetNumDof(Geometry::POINT, order);
|
||||
int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
|
||||
int nb = (dim > 0) ? fec->GetNumDof(geom, order) : 0;
|
||||
int np = (dim > 3) ? fec->GetNumDof(Geometry::TRIANGLE, order) : 0;
|
||||
|
||||
if (nv) { mesh->GetElementVertices(elem, V); }
|
||||
if (ne) { mesh->GetElementEdges(elem, E, Eo); }
|
||||
if (np) { mesh->GetElementPlanars(elem, P, Po); }
|
||||
|
||||
int nfd = 0;
|
||||
if (dim > 2 && fec->HasFaceDofs(geom, order))
|
||||
@@ -2787,7 +3011,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
}
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + nfd + nb);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + np*P.Size() + nfd + nb);
|
||||
|
||||
if (nv) // vertex DOFs
|
||||
{
|
||||
@@ -2814,6 +3038,20 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
}
|
||||
}
|
||||
|
||||
if(np)
|
||||
{
|
||||
for (int i = 0; i < P.Size(); i++)
|
||||
{
|
||||
int pbase = /* IsVariableOrder() ? FindEdgeDof(E[i], ne) : */P[i]*np;
|
||||
const int *ind = fec->GetDofOrdering(Geometry::TRIANGLE, order, Po[i]);
|
||||
|
||||
for (int j = 0; j < np; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + pbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nfd) // face DOFs
|
||||
{
|
||||
for (int i = 0; i < F.Size(); i++)
|
||||
@@ -2826,7 +3064,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
|
||||
for (int j = 0; j < nf; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + npdofs + fbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2834,7 +3072,7 @@ void FiniteElementSpace::GetElementDofs(int elem, Array<int> &dofs,
|
||||
if (nb) // interior ("bubble") DOFs
|
||||
{
|
||||
int bbase = bdofs ? bdofs[elem] : elem*nb;
|
||||
bbase += nvdofs + nedofs + nfdofs;
|
||||
bbase += nvdofs + nedofs + npdofs + nfdofs;
|
||||
|
||||
for (int j = 0; j < nb; j++)
|
||||
{
|
||||
@@ -2872,7 +3110,7 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
return;
|
||||
}
|
||||
|
||||
Array<int> V, E, Eo; // TODO: LocalArray
|
||||
Array<int> V, E, Eo, P, Po; // TODO: LocalArray
|
||||
int F, oF;
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
@@ -2889,9 +3127,13 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
int nv = fec->GetNumDof(Geometry::POINT, order);
|
||||
int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
|
||||
int nf = (dim > 2) ? fec->GetNumDof(geom, order) : 0;
|
||||
int np = (dim > 3) ? fec->DofForGeometry(Geometry::TRIANGLE) : (0);
|
||||
|
||||
if (nv) { mesh->GetBdrElementVertices(bel, V); }
|
||||
if (ne) { mesh->GetBdrElementEdges(bel, E, Eo); }
|
||||
|
||||
if (np) { mesh->GetBdrElementPlanars(bel, P, Po); }
|
||||
|
||||
if (nf)
|
||||
{
|
||||
mesh->GetBdrElementFace(bel, &F, &oF);
|
||||
@@ -2908,7 +3150,7 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
}
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + nf);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + np * P.Size() + nf);
|
||||
|
||||
if (nv) // vertex DOFs
|
||||
{
|
||||
@@ -2935,6 +3177,20 @@ void FiniteElementSpace::GetBdrElementDofs(int bel, Array<int> &dofs,
|
||||
}
|
||||
}
|
||||
|
||||
if(np)
|
||||
{
|
||||
for (int i = 0; i < P.Size(); i++)
|
||||
{
|
||||
int pbase = /* IsVariableOrder() ? FindEdgeDof(E[i], ne) : */P[i]*np;
|
||||
const int *ind = fec->GetDofOrdering(Geometry::TRIANGLE, order, Po[i]);
|
||||
|
||||
for (int j = 0; j < np; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + pbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nf) // face DOFs
|
||||
{
|
||||
int fbase = (var_face_dofs.Size() > 0) ? FindFaceDof(F, nf) : F*nf;
|
||||
@@ -3004,10 +3260,12 @@ int FiniteElementSpace::GetFaceDofs(int face, Array<int> &dofs,
|
||||
// for 1D, 2D and 3D faces
|
||||
int nv = fec->GetNumDof(Geometry::POINT, order);
|
||||
int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
|
||||
int np = (dim > 3) ? fec->GetNumDof(Geometry::TRIANGLE, order) : 0;
|
||||
|
||||
Array<int> V, E, Eo;
|
||||
Array<int> V, E, Eo, P, Po;
|
||||
if (nv) { mesh->GetFaceVertices(face, V); }
|
||||
if (ne) { mesh->GetFaceEdges(face, E, Eo); }
|
||||
if (np) { mesh->GetFacePlanars(face, P, Po); }
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(V.Size() * nv + E.Size() * ne + nf);
|
||||
@@ -3035,14 +3293,92 @@ int FiniteElementSpace::GetFaceDofs(int face, Array<int> &dofs,
|
||||
}
|
||||
}
|
||||
}
|
||||
if(np)
|
||||
{
|
||||
for (int i = 0; i < P.Size(); i++)
|
||||
{
|
||||
int pbase = /* IsVariableOrder() ? FindEdgeDof(E[i], ne) : */P[i]*np;
|
||||
const int *ind = fec->GetDofOrdering(Geometry::TRIANGLE, order, Po[i]);
|
||||
|
||||
for (int j = 0; j < np; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + nedofs + pbase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < nf; j++)
|
||||
{
|
||||
dofs.Append(nvdofs + nedofs + fbase + j);
|
||||
dofs.Append(nvdofs + nedofs + npdofs + fbase + j);
|
||||
}
|
||||
|
||||
return order;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetPlanarDofs(int planar, Array<int> &dofs) const
|
||||
{
|
||||
MFEM_VERIFY(!orders_changed, msg_orders_changed);
|
||||
|
||||
// if (planar_dof)
|
||||
// {
|
||||
// planar_dof->GetRow(planar, dofs);
|
||||
// return;
|
||||
// }
|
||||
|
||||
Array<int> V, E, Eo; // TODO: LocalArray
|
||||
|
||||
int dim = mesh->Dimension();
|
||||
int order = fec->GetOrder();
|
||||
|
||||
// if (IsVariableOrder()) // determine order from adjacent element
|
||||
// {
|
||||
// int elem, info;
|
||||
// mesh->GetBdrElementAdjacentElement(bel, elem, info);
|
||||
// order = elem_order[elem];
|
||||
// }
|
||||
|
||||
int nv = fec->GetNumDof(Geometry::POINT, order);
|
||||
int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
|
||||
int np = fec->GetNumDof(Geometry::TRIANGLE, order);
|
||||
|
||||
if (nv) { mesh->GetPlanVertices(planar, V); }
|
||||
if (ne) { mesh->GetPlanarEdges(planar, E, Eo); }
|
||||
|
||||
dofs.SetSize(0);
|
||||
dofs.Reserve(nv*V.Size() + ne*E.Size() + np);
|
||||
|
||||
if (nv) // vertex DOFs
|
||||
{
|
||||
for (int i = 0; i < V.Size(); i++)
|
||||
{
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
dofs.Append(V[i]*nv + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ne) // edge DOFs
|
||||
{
|
||||
for (int i = 0; i < E.Size(); i++)
|
||||
{
|
||||
int ebase = IsVariableOrder() ? FindEdgeDof(E[i], ne) : E[i]*ne;
|
||||
const int *ind = fec->GetDofOrdering(Geometry::SEGMENT, order, Eo[i]);
|
||||
|
||||
for (int j = 0; j < ne; j++)
|
||||
{
|
||||
dofs.Append(EncodeDof(nvdofs + ebase, ind[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pbase = planar*np;
|
||||
for (int i = 0; i < np; i++)
|
||||
{
|
||||
dofs.Append(nvdofs + nedofs + pbase + i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int FiniteElementSpace::GetEdgeDofs(int edge, Array<int> &dofs,
|
||||
int variant) const
|
||||
{
|
||||
@@ -3109,7 +3445,7 @@ void FiniteElementSpace::GetElementInteriorDofs(int i, Array<int> &dofs) const
|
||||
int base = bdofs ? bdofs[i] : i*nb;
|
||||
|
||||
dofs.SetSize(nb);
|
||||
base += nvdofs + nedofs + nfdofs;
|
||||
base += nvdofs + nedofs + npdofs + nfdofs;
|
||||
for (int j = 0; j < nb; j++)
|
||||
{
|
||||
dofs[j] = base + j;
|
||||
@@ -3264,6 +3600,11 @@ const FiniteElement *FiniteElementSpace::GetFaceElement(int i) const
|
||||
return fe;
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetPlanarElement(int i) const
|
||||
{
|
||||
return fec->FiniteElementForGeometry(mesh->GetPlanarBaseGeometry(i));
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetEdgeElement(int i,
|
||||
int variant) const
|
||||
{
|
||||
@@ -3333,6 +3674,8 @@ void FiniteElementSpace::Destroy()
|
||||
delete bdr_elem_fos;
|
||||
delete face_dof;
|
||||
delete [] bdofs;
|
||||
|
||||
delete [] pdofs;
|
||||
}
|
||||
ceed::RemoveBasisAndRestriction(this);
|
||||
}
|
||||
|
||||
+14
-2
@@ -245,9 +245,9 @@ protected:
|
||||
to be of the default order (fec->GetOrder()). */
|
||||
Array<char> elem_order;
|
||||
|
||||
int nvdofs, nedofs, nfdofs, nbdofs;
|
||||
int nvdofs, nedofs, nfdofs, nbdofs, npdofs;
|
||||
int uni_fdof; ///< # of single face DOFs if all faces uniform; -1 otherwise
|
||||
int *bdofs; ///< internal DOFs of elements if mixed/var-order; NULL otherwise
|
||||
int *bdofs, *pdofs; ///< internal DOFs of elements if mixed/var-order; NULL otherwise
|
||||
|
||||
/** Variable order spaces only: DOF assignments for edges and faces, see
|
||||
docs in MakeDofTable. For constant order spaces the tables are empty. */
|
||||
@@ -396,6 +396,7 @@ protected:
|
||||
|
||||
/// Calculate the cP and cR matrices for a nonconforming mesh.
|
||||
void BuildConformingInterpolation() const;
|
||||
void BuildConformingInterpolation4D() const;
|
||||
|
||||
static void AddDependencies(SparseMatrix& deps, Array<int>& master_dofs,
|
||||
Array<int>& slave_dofs, DenseMatrix& I,
|
||||
@@ -730,6 +731,7 @@ public:
|
||||
int GetNVDofs() const { return nvdofs; }
|
||||
/// Number of all scalar edge-interior dofs
|
||||
int GetNEDofs() const { return nedofs; }
|
||||
int GetNPDofs() const { return npdofs; }
|
||||
/// Number of all scalar face-interior dofs
|
||||
int GetNFDofs() const { return nfdofs; }
|
||||
|
||||
@@ -745,6 +747,9 @@ public:
|
||||
the edges. */
|
||||
inline int GetNF() const { return mesh->GetNumFaces(); }
|
||||
|
||||
/// Returns number of planars (i.e. co-dimension 2 entities) in the mesh.
|
||||
inline int GetNP() const { return mesh->GetNPlanars(); }
|
||||
|
||||
/// Returns number of boundary elements in the mesh.
|
||||
inline int GetNBE() const { return mesh->GetNBE(); }
|
||||
|
||||
@@ -786,6 +791,8 @@ public:
|
||||
|
||||
int GetBdrAttribute(int i) const { return mesh->GetBdrAttribute(i); }
|
||||
|
||||
virtual void GetPlanarDofs(int i, Array<int> &dofs) const;
|
||||
|
||||
/// @anchor getdof @name Local DoF Access Members
|
||||
/// These member functions produce arrays of local degree of freedom
|
||||
/// indices, see @ref ldof. If @b vdim == 1 these indices can be used to
|
||||
@@ -1087,6 +1094,9 @@ public:
|
||||
/// not necessarily equal to 1. See GetFaceDofs() for more information.
|
||||
void GetFaceVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// Returns indexes of degrees of freedom for i'th planar element (4D).
|
||||
void GetPlanarVDofs(int i, Array<int> &vdofs) const;
|
||||
|
||||
/// @brief Returns the indices of the degrees of freedom for the specified
|
||||
/// edge, including the DOFs for the vertices of the edge.
|
||||
///
|
||||
@@ -1178,6 +1188,8 @@ public:
|
||||
points.*/
|
||||
const FiniteElement *GetFaceElement(int i) const;
|
||||
|
||||
const FiniteElement *GetPlanarElement(int i) const;
|
||||
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
associated with i'th edge in the mesh object. */
|
||||
const FiniteElement *GetEdgeElement(int i, int variant = 0) const;
|
||||
|
||||
+371
-39
@@ -19,11 +19,11 @@ namespace mfem
|
||||
const char *Geometry::Name[NumGeom] =
|
||||
{
|
||||
"Point", "Segment", "Triangle", "Square", "Tetrahedron", "Cube", "Prism",
|
||||
"Pyramid"
|
||||
"Pyramid", "Pentatope", "Tesseract"
|
||||
};
|
||||
|
||||
const real_t Geometry::Volume[NumGeom] =
|
||||
{ 1.0, 1.0, 0.5, 1.0, 1./6, 1.0, 0.5, 1./3 };
|
||||
{ 1.0, 1.0, 0.5, 1.0, 1./6, 1.0, 0.5, 1./3, 1./24., 1.0 };
|
||||
|
||||
Geometry::Geometry()
|
||||
{
|
||||
@@ -165,6 +165,36 @@ Geometry::Geometry()
|
||||
GeomVert[7]->IntPoint(4).y = 0.0;
|
||||
GeomVert[7]->IntPoint(4).z = 1.0;
|
||||
|
||||
// Vertices for Geometry::PENTATOPE
|
||||
GeomVert[8] = new IntegrationRule(5);
|
||||
GeomVert[8]->IntPoint(0).x = 0.0;
|
||||
GeomVert[8]->IntPoint(0).y = 0.0;
|
||||
GeomVert[8]->IntPoint(0).z = 0.0;
|
||||
GeomVert[8]->IntPoint(0).t = 0.0;
|
||||
|
||||
GeomVert[8]->IntPoint(1).x = 1.0;
|
||||
GeomVert[8]->IntPoint(1).y = 0.0;
|
||||
GeomVert[8]->IntPoint(1).z = 0.0;
|
||||
GeomVert[8]->IntPoint(1).t = 0.0;
|
||||
|
||||
GeomVert[8]->IntPoint(2).x = 0.0;
|
||||
GeomVert[8]->IntPoint(2).y = 1.0;
|
||||
GeomVert[8]->IntPoint(2).z = 0.0;
|
||||
GeomVert[8]->IntPoint(2).t = 0.0;
|
||||
|
||||
GeomVert[8]->IntPoint(3).x = 0.0;
|
||||
GeomVert[8]->IntPoint(3).y = 0.0;
|
||||
GeomVert[8]->IntPoint(3).z = 1.0;
|
||||
GeomVert[8]->IntPoint(3).t = 0.0;
|
||||
|
||||
GeomVert[8]->IntPoint(4).x = 0.0;
|
||||
GeomVert[8]->IntPoint(4).y = 0.0;
|
||||
GeomVert[8]->IntPoint(4).z = 0.0;
|
||||
GeomVert[8]->IntPoint(4).t = 1.0;
|
||||
|
||||
// Vertices for Geometry::TESSERACT
|
||||
// TODO
|
||||
|
||||
GeomCenter[POINT].x = 0.0;
|
||||
GeomCenter[POINT].y = 0.0;
|
||||
GeomCenter[POINT].z = 0.0;
|
||||
@@ -197,6 +227,14 @@ Geometry::Geometry()
|
||||
GeomCenter[PYRAMID].y = 0.375;
|
||||
GeomCenter[PYRAMID].z = 0.25;
|
||||
|
||||
GeomCenter[PENTATOPE].x = 0.2;
|
||||
GeomCenter[PENTATOPE].y = 0.2;
|
||||
GeomCenter[PENTATOPE].z = 0.2;
|
||||
GeomCenter[PENTATOPE].t = 0.2;
|
||||
|
||||
// GeomCenter[TESSERACT]
|
||||
// TODO
|
||||
|
||||
GeomToPerfGeomJac[POINT] = NULL;
|
||||
GeomToPerfGeomJac[SEGMENT] = new DenseMatrix(1);
|
||||
GeomToPerfGeomJac[TRIANGLE] = new DenseMatrix(2);
|
||||
@@ -205,6 +243,7 @@ Geometry::Geometry()
|
||||
GeomToPerfGeomJac[CUBE] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[PRISM] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[PYRAMID] = new DenseMatrix(3);
|
||||
GeomToPerfGeomJac[PENTATOPE] = new DenseMatrix(4);
|
||||
|
||||
PerfGeomToGeomJac[POINT] = NULL;
|
||||
PerfGeomToGeomJac[SEGMENT] = NULL;
|
||||
@@ -214,6 +253,7 @@ Geometry::Geometry()
|
||||
PerfGeomToGeomJac[CUBE] = NULL;
|
||||
PerfGeomToGeomJac[PRISM] = new DenseMatrix(3);
|
||||
PerfGeomToGeomJac[PYRAMID] = new DenseMatrix(3);
|
||||
PerfGeomToGeomJac[PENTATOPE] = new DenseMatrix(4);
|
||||
|
||||
GeomToPerfGeomJac[SEGMENT]->Diag(1.0, 1);
|
||||
{
|
||||
@@ -250,6 +290,16 @@ Geometry::Geometry()
|
||||
*GeomToPerfGeomJac[PYRAMID] = pyr_T.Jacobian();
|
||||
CalcInverse(pyr_T.Jacobian(), *PerfGeomToGeomJac[PYRAMID]);
|
||||
}
|
||||
{
|
||||
Linear4DFiniteElement PentFE;
|
||||
IsoparametricTransformation pent_T;
|
||||
pent_T.SetFE(&PentFE);
|
||||
GetPerfPointMat (PENTATOPE, pent_T.GetPointMat());
|
||||
// pent_T.FinalizeTransformation();
|
||||
pent_T.SetIntPoint(&GeomCenter[PENTATOPE]);
|
||||
*GeomToPerfGeomJac[PENTATOPE] = pent_T.Jacobian();
|
||||
CalcInverse(pent_T.Jacobian(), *PerfGeomToGeomJac[PENTATOPE]);
|
||||
}
|
||||
}
|
||||
|
||||
template <Geometry::Type GEOM>
|
||||
@@ -302,6 +352,8 @@ const IntegrationRule *Geometry::GetVertices(int GeomType) const
|
||||
case Geometry::CUBE: return GeomVert[5];
|
||||
case Geometry::PRISM: return GeomVert[6];
|
||||
case Geometry::PYRAMID: return GeomVert[7];
|
||||
case Geometry::PENTATOPE: return GeomVert[8];
|
||||
case Geometry::TESSERACT: return GeomVert[9];
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
mfem_error("Geometry::GetVertices(...)");
|
||||
@@ -399,6 +451,45 @@ void Geometry::GetRandomPoint(int GeomType, IntegrationPoint &ip)
|
||||
ip.x = 1.0 - z;
|
||||
}
|
||||
break;
|
||||
case Geometry::PENTATOPE:
|
||||
ip.x = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.y = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.z = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.t = real_t(rand()) / real_t(RAND_MAX);
|
||||
// map to the triangular 4D wedge obtained by extruding the reference
|
||||
// tetrahedron in t direction
|
||||
// needs to be updated
|
||||
// if (ip.x + ip.y > 1.0)
|
||||
// {
|
||||
// ip.x = 1.0 - ip.x;
|
||||
// ip.y = 1.0 - ip.y;
|
||||
// }
|
||||
// // split the prism into 3 parts: 1 is the reference tet, and the
|
||||
// // other two tets (as given below) are mapped to the reference tet
|
||||
// if (ip.x + ip.z > 1.0)
|
||||
// {
|
||||
// // tet with vertices: (0,0,1),(1,0,1),(0,1,1),(1,0,0)
|
||||
// ip.x = ip.x + ip.z - 1.0;
|
||||
// // ip.y = ip.y;
|
||||
// ip.z = 1.0 - ip.z;
|
||||
// // mapped to: (0,0,0),(1,0,0),(0,1,0),(0,0,1)
|
||||
// }
|
||||
// else if (ip.x + ip.y + ip.z > 1.0)
|
||||
// {
|
||||
// // tet with vertices: (0,1,1),(0,1,0),(0,0,1),(1,0,0)
|
||||
// real_t x = ip.x;
|
||||
// ip.x = 1.0 - x - ip.z;
|
||||
// ip.y = 1.0 - x - ip.y;
|
||||
// ip.z = x;
|
||||
// // mapped to: (0,0,0),(1,0,0),(0,1,0),(0,0,1)
|
||||
// }
|
||||
// break;
|
||||
case Geometry::TESSERACT:
|
||||
ip.x = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.y = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.z = real_t(rand()) / real_t(RAND_MAX);
|
||||
ip.t = real_t(rand()) / real_t(RAND_MAX);
|
||||
break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -465,6 +556,14 @@ bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip)
|
||||
if (ip.x < 0.0 || ip.y < 0.0 || ip.x+ip.z > 1.0 || ip.y+ip.z > 1.0 ||
|
||||
ip.z < 0.0 || ip.z > 1.0) { return false; }
|
||||
break;
|
||||
case Geometry::PENTATOPE:
|
||||
if (ip.x < 0.0 || ip.y < 0.0 || ip.z < 0.0 || ip.t < 0 ||
|
||||
ip.x+ip.y+ip.z+ip.t > 1.0) { return false; }
|
||||
break;
|
||||
case Geometry::TESSERACT:
|
||||
if (ip.x < 0.0 || ip.x > 1.0 || ip.y < 0.0 || ip.y > 1.0 ||
|
||||
ip.z < 0.0 || ip.z > 1.0 || ip.t < 0.0 || ip.t > 1.0) { return false; }
|
||||
break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -548,6 +647,29 @@ bool Geometry::CheckPoint(int GeomType, const IntegrationPoint &ip, real_t eps)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Geometry::PENTATOPE:
|
||||
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|
||||
|| internal::FuzzyLT(ip.y, 0.0, eps)
|
||||
|| internal::FuzzyLT(ip.z, 0.0, eps)
|
||||
|| internal::FuzzyLT(ip.t, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.x+ip.y+ip.z+ip.t, 1.0, eps) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Geometry::TESSERACT:
|
||||
if ( internal::FuzzyLT(ip.x, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.x, 1.0, eps)
|
||||
|| internal::FuzzyLT(ip.y, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.y, 1.0, eps)
|
||||
|| internal::FuzzyLT(ip.z, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.z, 1.0, eps)
|
||||
|| internal::FuzzyLT(ip.t, 0.0, eps)
|
||||
|| internal::FuzzyGT(ip.t, 1.0, eps) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -610,6 +732,81 @@ inline bool ProjectTriangle(real_t &x, real_t &y)
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ProjectTetrahedron(double &x, double &y, double &z)
|
||||
{
|
||||
if (z < 0.0)
|
||||
{
|
||||
z = 0.0;
|
||||
internal::ProjectTriangle(x, y);
|
||||
return false;
|
||||
}
|
||||
if (y < 0.0)
|
||||
{
|
||||
y = 0.0;
|
||||
internal::ProjectTriangle(x, z);
|
||||
return false;
|
||||
}
|
||||
if (x < 0.0)
|
||||
{
|
||||
x = 0.0;
|
||||
internal::ProjectTriangle(y, z);
|
||||
return false;
|
||||
}
|
||||
const double l4 = 1.0-x-y-z;
|
||||
if (l4 < 0.0)
|
||||
{
|
||||
const double l4_3 = l4/3;
|
||||
x += l4_3;
|
||||
y += l4_3;
|
||||
internal::ProjectTriangle(x, y);
|
||||
z = 1.0-x-y;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool ProjectPentatope(double &x, double &y, double &z, double &t)
|
||||
{
|
||||
if (t < 0.0)
|
||||
{
|
||||
t = 0.0;
|
||||
internal::ProjectTetrahedron(x, y, z);
|
||||
return false;
|
||||
}
|
||||
if (z < 0.0)
|
||||
{
|
||||
z = 0.0;
|
||||
internal::ProjectTetrahedron(x, y, t);
|
||||
return false;
|
||||
}
|
||||
if (y < 0.0)
|
||||
{
|
||||
y = 0.0;
|
||||
internal::ProjectTetrahedron(x, z, t);
|
||||
return false;
|
||||
}
|
||||
if (x < 0.0)
|
||||
{
|
||||
x = 0.0;
|
||||
internal::ProjectTetrahedron(y, z, t);
|
||||
return false;
|
||||
}
|
||||
const double l5 = 1.0-x-y-z-t;
|
||||
if (l5 < 0.0)
|
||||
{
|
||||
const double l5_4 = l5/4;
|
||||
// TODO
|
||||
// In Geometry::ProjectPoint 4d origianlly had const double l5_4 = l5/5
|
||||
x += l5_4;
|
||||
y += l5_4;
|
||||
z += l5_4;
|
||||
internal::ProjectTetrahedron(x, y, z);
|
||||
t = 1.0-x-y-z;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// static method
|
||||
@@ -675,6 +872,22 @@ bool Geometry::ProjectPoint(int GeomType, const IntegrationPoint &beg,
|
||||
};
|
||||
return internal::IntersectSegment<6,3>(lbeg, lend, end);
|
||||
}
|
||||
case Geometry::PENTATOPE:
|
||||
{
|
||||
real_t lend[5] = { end.x, end.y, end.z, end.t, fone-end.x-end.y-end.z-end.t };
|
||||
real_t lbeg[5] = { beg.x, beg.y, beg.z, beg.t, fone-beg.x-beg.y-beg.z-beg.t };
|
||||
return internal::IntersectSegment<5,4>(lbeg,lend,end);
|
||||
}
|
||||
case Geometry::TESSERACT:
|
||||
{
|
||||
real_t lend[8] = { end.x, end.y, end.z, end.t,
|
||||
fone-end.x, fone-end.y, fone-end.z, fone-end.t
|
||||
};
|
||||
real_t lbeg[8] = { beg.x, beg.y, beg.z, beg.t,
|
||||
fone-beg.x, fone-beg.y, fone-beg.z, fone-beg.t
|
||||
};
|
||||
return internal::IntersectSegment<8,3>(lbeg, lend, end);
|
||||
}
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -717,35 +930,7 @@ bool Geometry::ProjectPoint(int GeomType, IntegrationPoint &ip)
|
||||
|
||||
case TETRAHEDRON:
|
||||
{
|
||||
if (ip.z < 0.0)
|
||||
{
|
||||
ip.z = 0.0;
|
||||
internal::ProjectTriangle(ip.x, ip.y);
|
||||
return false;
|
||||
}
|
||||
if (ip.y < 0.0)
|
||||
{
|
||||
ip.y = 0.0;
|
||||
internal::ProjectTriangle(ip.x, ip.z);
|
||||
return false;
|
||||
}
|
||||
if (ip.x < 0.0)
|
||||
{
|
||||
ip.x = 0.0;
|
||||
internal::ProjectTriangle(ip.y, ip.z);
|
||||
return false;
|
||||
}
|
||||
const real_t l4 = 1.0-ip.x-ip.y-ip.z;
|
||||
if (l4 < 0.0)
|
||||
{
|
||||
const real_t l4_3 = l4/3;
|
||||
ip.x += l4_3;
|
||||
ip.y += l4_3;
|
||||
internal::ProjectTriangle(ip.x, ip.y);
|
||||
ip.z = 1.0-ip.x-ip.y;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return internal::ProjectTetrahedron(ip.x, ip.y, ip.z);
|
||||
}
|
||||
|
||||
case CUBE:
|
||||
@@ -810,6 +995,29 @@ bool Geometry::ProjectPoint(int GeomType, IntegrationPoint &ip)
|
||||
}
|
||||
}
|
||||
|
||||
case PENTATOPE:
|
||||
{
|
||||
return internal::ProjectPentatope(ip.x, ip.y, ip.z, ip.t);
|
||||
}
|
||||
|
||||
case TESSERACT:
|
||||
{
|
||||
bool in_x, in_y, in_z, in_t;
|
||||
if (ip.x < 0.0) { in_x = false; ip.x = 0.0; }
|
||||
else if (ip.x > 1.0) { in_x = false; ip.x = 1.0; }
|
||||
else { in_x = true; }
|
||||
if (ip.y < 0.0) { in_y = false; ip.y = 0.0; }
|
||||
else if (ip.y > 1.0) { in_y = false; ip.y = 1.0; }
|
||||
else { in_y = true; }
|
||||
if (ip.z < 0.0) { in_z = false; ip.z = 0.0; }
|
||||
else if (ip.z > 1.0) { in_z = false; ip.z = 1.0; }
|
||||
else { in_z = true; }
|
||||
if (ip.t < 0.0) { in_t = false; ip.t = 0.0; }
|
||||
else if (ip.t > 1.0) { in_t = false; ip.t = 1.0; }
|
||||
else { in_t = true; }
|
||||
return in_x && in_y && in_z && in_t;
|
||||
}
|
||||
|
||||
case Geometry::POINT:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::INVALID:
|
||||
@@ -898,6 +1106,42 @@ void Geometry::GetPerfPointMat(int GeomType, DenseMatrix &pm) const
|
||||
}
|
||||
break;
|
||||
|
||||
case Geometry::PENTATOPE:
|
||||
{
|
||||
pm.SetSize(4,5);
|
||||
pm(0,0) = 0.0; pm(1,0) = 0.0; pm(2,0) = 0.0; pm(3,0) = 0.0;
|
||||
pm(0,1) = 1.0; pm(1,1) = 0.0; pm(2,1) = 0.0; pm(3,1) = 0.0;
|
||||
pm(0,2) = 0.5; pm(1,2) = 0.86602540378443864676; pm(2,2) = 0.0; pm(3,2) = 0.0;
|
||||
pm(0,3) = 0.5; pm(1,3) = 0.28867513459481288225;
|
||||
pm(2,3) = 0.81649658092772603273; pm(3,3) = 0.0;
|
||||
pm(0,4) = 0.5; pm(1,4) = 0.28867513459481288225;
|
||||
pm(2,4) = 0.20412414523193150819; pm(3,4) = 0.7905694150420948330;
|
||||
}
|
||||
break;
|
||||
|
||||
case Geometry::TESSERACT:
|
||||
{
|
||||
pm.SetSize (4, 16);
|
||||
pm(0,0) = 0.0; pm(1,0) = 0.0; pm(2,0) = 0.0; pm(4,0) = 0.0;
|
||||
pm(0,1) = 1.0; pm(1,1) = 0.0; pm(2,1) = 0.0; pm(4,1) = 0.0;
|
||||
pm(0,2) = 1.0; pm(1,2) = 1.0; pm(2,2) = 0.0; pm(4,2) = 0.0;
|
||||
pm(0,3) = 0.0; pm(1,3) = 1.0; pm(2,3) = 0.0; pm(4,3) = 0.0;
|
||||
pm(0,4) = 0.0; pm(1,4) = 0.0; pm(2,4) = 1.0; pm(4,4) = 0.0;
|
||||
pm(0,5) = 1.0; pm(1,5) = 0.0; pm(2,5) = 1.0; pm(4,5) = 0.0;
|
||||
pm(0,6) = 1.0; pm(1,6) = 1.0; pm(2,6) = 1.0; pm(4,6) = 0.0;
|
||||
pm(0,7) = 0.0; pm(1,7) = 1.0; pm(2,7) = 1.0; pm(4,7) = 0.0;
|
||||
|
||||
pm(0,8) = 0.0; pm(1,8) = 0.0; pm(2,8) = 0.0; pm(4,8) = 1.0;
|
||||
pm(0,9) = 1.0; pm(1,9) = 0.0; pm(2,9) = 0.0; pm(4,9) = 1.0;
|
||||
pm(0,10) = 1.0; pm(1,10) = 1.0; pm(2,10) = 0.0; pm(4,10) = 1.0;
|
||||
pm(0,11) = 0.0; pm(1,11) = 1.0; pm(2,11) = 0.0; pm(4,11) = 1.0;
|
||||
pm(0,12) = 0.0; pm(1,12) = 0.0; pm(2,12) = 1.0; pm(4,12) = 1.0;
|
||||
pm(0,13) = 1.0; pm(1,13) = 0.0; pm(2,13) = 1.0; pm(4,13) = 1.0;
|
||||
pm(0,14) = 1.0; pm(1,14) = 1.0; pm(2,14) = 1.0; pm(4,14) = 1.0;
|
||||
pm(0,15) = 0.0; pm(1,15) = 1.0; pm(2,15) = 1.0; pm(4,15) = 1.0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Geometry::POINT:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::INVALID:
|
||||
@@ -919,13 +1163,13 @@ void Geometry::JacToPerfJac(int GeomType, const DenseMatrix &J,
|
||||
}
|
||||
}
|
||||
|
||||
const int Geometry::NumBdrArray[NumGeom] = { 0, 2, 3, 4, 4, 6, 5, 5 };
|
||||
const int Geometry::Dimension[NumGeom] = { 0, 1, 2, 2, 3, 3, 3, 3 };
|
||||
const int Geometry::DimStart[MaxDim+2] =
|
||||
{ POINT, SEGMENT, TRIANGLE, TETRAHEDRON, NUM_GEOMETRIES };
|
||||
const int Geometry::NumVerts[NumGeom] = { 1, 2, 3, 4, 4, 8, 6, 5 };
|
||||
const int Geometry::NumEdges[NumGeom] = { 0, 1, 3, 4, 6, 12, 9, 8 };
|
||||
const int Geometry::NumFaces[NumGeom] = { 0, 0, 1, 1, 4, 6, 5, 5 };
|
||||
const int Geometry::NumBdrArray[NumGeom] = { 0, 2, 3, 4, 4, 6, 5, 5, 5, 24 };
|
||||
const int Geometry::Dimension[NumGeom] = { 0, 1, 2, 2, 3, 3, 3, 3, 4, 4 };
|
||||
const int Geometry::DimStart[MaxDim+2] =
|
||||
{ POINT, SEGMENT, TRIANGLE, TETRAHEDRON, PENTATOPE, NUM_GEOMETRIES };
|
||||
const int Geometry::NumVerts[NumGeom] = { 1, 2, 3, 4, 4, 8, 6, 5, 5, 16 };
|
||||
const int Geometry::NumEdges[NumGeom] = { 0, 1, 3, 4, 6, 12, 9, 8, 10, 32 };
|
||||
const int Geometry::NumFaces[NumGeom] = { 0, 0, 1, 1, 4, 6, 5, 5, 5, 24 };
|
||||
|
||||
const int Geometry::
|
||||
Constants<Geometry::POINT>::Orient[1][1] = {{0}};
|
||||
@@ -1096,6 +1340,63 @@ Constants<Geometry::PYRAMID>::VertToVert::J[8][2] =
|
||||
{4, 7} // 3,4:7
|
||||
};
|
||||
|
||||
const int Geometry::
|
||||
Constants<Geometry::PENTATOPE>::Edges[10][2] =
|
||||
{{0, 1}, {0, 2}, {0, 3}, {0, 4}, {1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4}};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PENTATOPE>::FaceTypes[5] =
|
||||
{
|
||||
Geometry::TETRAHEDRON, Geometry::TETRAHEDRON,
|
||||
Geometry::TETRAHEDRON, Geometry::TETRAHEDRON,
|
||||
Geometry::TETRAHEDRON
|
||||
};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PENTATOPE>::FaceVert[5][4] =
|
||||
{
|
||||
// {0, 1, 2, 3}, {0, 1, 2, 4},
|
||||
// {0, 1, 3, 4}, {0, 2, 3, 4},
|
||||
// {1, 2, 3, 4}
|
||||
{0, 1, 2, 3}, {0, 2, 1, 4}, //<---- sorted such that the normal vectors are outer normal vectors
|
||||
{0, 1, 3, 4}, {0, 3, 2, 4},
|
||||
{1, 2, 3, 4}
|
||||
};
|
||||
const int Geometry::
|
||||
Constants<Geometry::PENTATOPE>::PlanarVert[10][3] =
|
||||
{
|
||||
{0, 1, 2}, {0, 1, 3}, {0, 1, 4},
|
||||
{0, 2, 3}, {0, 2, 4}, {0, 3, 4},
|
||||
{1, 2, 3}, {1, 2, 4}, {1, 3, 4},
|
||||
{2, 3, 4}
|
||||
};
|
||||
|
||||
//const int Geometry::
|
||||
//Constants<Geometry::PENTATOPE>::VertToVert::I[4] = {0, 3, 5, 6};
|
||||
//const int Geometry::
|
||||
//Constants<Geometry::PENTATOPE>::VertToVert::J[6][2] =
|
||||
//{{1, 0}, {2, 1}, {3, 2}, {2, 3}, {3, 4}, {3, 5}};
|
||||
|
||||
|
||||
const int Geometry::
|
||||
Constants<Geometry::TESSERACT>::FaceVert[8][8] =
|
||||
{
|
||||
// {8,11,12,15,0,3,4,7}, //x bottom
|
||||
// {1,2,6,5,9,10,14,13}, //x top
|
||||
// {0,1,5,4,8,9,13,12}, //y bottom
|
||||
// {2,3,7,6,10,11,15,14}, //y top
|
||||
// {8,9,10,11,0,1,2,3}, // z bottom
|
||||
// {4,5,6,7,12,13,14,15}, //z top
|
||||
// {0,1,2,3,4,5,6,7}, //t botom
|
||||
// {12,13,14,15,8,9,10,11} //t top
|
||||
{8,11,15,12,0,3,7,4}, //x bottom
|
||||
{1,2,6,5,9,10,14,13}, //x top
|
||||
{0,1,5,4,8,9,13,12}, //y bottom
|
||||
{2,3,7,6,10,11,15,14}, //y top
|
||||
{8,9,10,11,0,1,2,3}, // z bottom
|
||||
{4,5,6,7,12,13,14,15}, //z top
|
||||
{0,1,2,3,4,5,6,7}, //t botom
|
||||
{12,13,14,15,8,9,10,11} //t top
|
||||
};
|
||||
|
||||
|
||||
GeometryRefiner::~GeometryRefiner()
|
||||
{
|
||||
@@ -1656,7 +1957,9 @@ RefinedGeometry *GeometryRefiner::Refine(Geometry::Type Geom, int Times,
|
||||
RGeom[Geometry::PRISM].Append(RG);
|
||||
}
|
||||
break;
|
||||
|
||||
case Geometry::PENTATOPE:
|
||||
case Geometry::TESSERACT:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -1768,6 +2071,8 @@ const IntegrationRule *GeometryRefiner::RefineInterior(Geometry::Type Geom,
|
||||
case Geometry::CUBE:
|
||||
case Geometry::PYRAMID:
|
||||
case Geometry::PRISM:
|
||||
case Geometry::PENTATOPE:
|
||||
case Geometry::TESSERACT:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
@@ -1837,6 +2142,24 @@ int GeometryRefiner::GetRefinementLevelFromPoints(Geometry::Type geom, int Npts)
|
||||
}
|
||||
case Geometry::PYRAMID:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::PENTATOPE:
|
||||
{
|
||||
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
|
||||
{
|
||||
np = (n+4)*(n+3)*(n+2)*(n+1)/24;
|
||||
if (np == Npts) { return n; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
case Geometry::TESSERACT:
|
||||
{
|
||||
for (int n = 0, np = 0; (n < 15) && (np < Npts) ; n++)
|
||||
{
|
||||
np = (n+1)*(n+1)*(n+1)*(n+1);
|
||||
if (np == Npts) { return n; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -1879,6 +2202,15 @@ int GeometryRefiner::GetRefinementLevelFromElems(Geometry::Type geom, int Nels)
|
||||
}
|
||||
case Geometry::PYRAMID:
|
||||
MFEM_ABORT("Reference element type is not supported!");
|
||||
case Geometry::PENTATOPE:
|
||||
case Geometry::TESSERACT:
|
||||
{
|
||||
for (int n = 0; (n < 15) && (n*n*n*n < Nels+1) ; n++)
|
||||
{
|
||||
if (n*n*n*n == Nels) { return n-1; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
|
||||
+52
-2
@@ -28,6 +28,8 @@ namespace mfem
|
||||
Geometry::CUBE - the unit cube
|
||||
Geometry::PRISM - w/ vert. (0,0,0),(1,0,0),(0,1,0),(0,0,1),(1,0,1),(0,1,1)
|
||||
Geometry::PYRAMID - w/ vert. (0,0,0),(1,0,0),(1,1,0),(0,1,0),(0,0,1)
|
||||
Geometry::PENTATOPE - w/ vert. (0,0,0,0),(1,0,0,0),(0,1,0,0),(0,0,1,0),(0,0,0,1)
|
||||
Geometry::TESSERACT - the 4d unit cube
|
||||
*/
|
||||
class MFEM_EXPORT Geometry
|
||||
{
|
||||
@@ -35,12 +37,12 @@ public:
|
||||
enum Type
|
||||
{
|
||||
INVALID = -1,
|
||||
POINT = 0, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM, PYRAMID,
|
||||
POINT = 0, SEGMENT, TRIANGLE, SQUARE, TETRAHEDRON, CUBE, PRISM, PYRAMID, PENTATOPE, TESSERACT,
|
||||
NUM_GEOMETRIES
|
||||
};
|
||||
|
||||
static const int NumGeom = NUM_GEOMETRIES;
|
||||
static const int MaxDim = 3;
|
||||
static const int MaxDim = 4;
|
||||
static const int NumBdrArray[NumGeom];
|
||||
static const char *Name[NumGeom];
|
||||
static const real_t Volume[NumGeom];
|
||||
@@ -118,6 +120,7 @@ public:
|
||||
case 1: return SEGMENT;
|
||||
case 2: return SQUARE;
|
||||
case 3: return CUBE;
|
||||
case 4: return TESSERACT;
|
||||
default: MFEM_ABORT("Invalid dimension."); return INVALID;
|
||||
}
|
||||
}
|
||||
@@ -305,6 +308,53 @@ template <> struct
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
MFEM_EXPORT
|
||||
/// @endcond
|
||||
Geometry::Constants<Geometry::PENTATOPE>
|
||||
{
|
||||
static const int Dimension = 4;
|
||||
static const int NumVert = 5;
|
||||
static const int NumEdges = 10;
|
||||
static const int Edges[NumEdges][2];
|
||||
static const int NumFaces = 5;
|
||||
static const int FaceTypes[NumFaces];
|
||||
static const int MaxFaceVert = 4;
|
||||
static const int FaceVert[NumFaces][MaxFaceVert];
|
||||
static const int NumPlanar = 10;
|
||||
static const int MaxPlanarVert = 3;
|
||||
static const int PlanarVert[NumPlanar][MaxPlanarVert];
|
||||
// Lower-triangular part of the local vertex-to-vertex graph.
|
||||
struct VertToVert
|
||||
{
|
||||
static const int I[NumVert];
|
||||
static const int J[NumEdges][2]; // {end,edge_idx}
|
||||
};
|
||||
};
|
||||
|
||||
template <> struct
|
||||
/// @cond Suppress_Doxygen_warnings
|
||||
MFEM_EXPORT
|
||||
/// @endcond
|
||||
Geometry::Constants<Geometry::TESSERACT>
|
||||
{
|
||||
static const int Dimension = 4;
|
||||
static const int NumVert = 16;
|
||||
static const int NumEdges = 32;
|
||||
static const int Edges[NumEdges][2];
|
||||
static const int NumFaces = 8;
|
||||
static const int FaceTypes[NumFaces];
|
||||
static const int MaxFaceVert = 8;
|
||||
static const int FaceVert[NumFaces][MaxFaceVert];
|
||||
// Lower-triangular part of the local vertex-to-vertex graph.
|
||||
struct VertToVert
|
||||
{
|
||||
static const int I[NumVert];
|
||||
static const int J[NumEdges][2]; // {end,edge_idx}
|
||||
};
|
||||
};
|
||||
|
||||
// Defined in fe.cpp to ensure construction after 'mfem::TriangleFE' and
|
||||
// `mfem::TetrahedronFE`.
|
||||
extern MFEM_EXPORT Geometry Geometries;
|
||||
|
||||
+50
-12
@@ -39,7 +39,7 @@ GridFunction::GridFunction(Mesh *m, std::istream &input)
|
||||
UseDevice(true);
|
||||
|
||||
fes = new FiniteElementSpace;
|
||||
fec = fes->Load(m, input);
|
||||
fec_owned = fes->Load(m, input);
|
||||
|
||||
skip_comment_lines(input, '#');
|
||||
istream::int_type next_char = input.peek();
|
||||
@@ -81,10 +81,10 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
int vdim, ordering;
|
||||
|
||||
fes = gf_array[0]->FESpace();
|
||||
fec = FiniteElementCollection::New(fes->FEColl()->Name());
|
||||
fec_owned = FiniteElementCollection::New(fes->FEColl()->Name());
|
||||
vdim = fes->GetVDim();
|
||||
ordering = fes->GetOrdering();
|
||||
fes = new FiniteElementSpace(m, fec, vdim, ordering);
|
||||
fes = new FiniteElementSpace(m, fec_owned, vdim, ordering);
|
||||
SetSize(fes->GetVSize());
|
||||
|
||||
if (m->NURBSext)
|
||||
@@ -153,11 +153,11 @@ GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
|
||||
|
||||
void GridFunction::Destroy()
|
||||
{
|
||||
if (fec)
|
||||
if (fec_owned)
|
||||
{
|
||||
delete fes;
|
||||
delete fec;
|
||||
fec = NULL;
|
||||
delete fec_owned;
|
||||
fec_owned = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,10 +325,9 @@ int GridFunction::VectorDim() const
|
||||
const FiniteElement *fe;
|
||||
if (!fes->GetNE())
|
||||
{
|
||||
const FiniteElementCollection *fe_coll = fes->FEColl();
|
||||
static const Geometry::Type geoms[3] =
|
||||
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
|
||||
fe = fe_coll->
|
||||
fe = fes->FEColl()->
|
||||
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
@@ -350,7 +349,8 @@ int GridFunction::CurlDim() const
|
||||
{
|
||||
static const Geometry::Type geoms[3] =
|
||||
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
|
||||
fe = fec->FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
fe = fes->FEColl()->
|
||||
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2123,8 +2123,15 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
Vector vals;
|
||||
Mesh *mesh = fes->GetMesh();
|
||||
NCMesh *ncmesh = mesh->ncmesh;
|
||||
Array<int> bdr_edges, bdr_vertices, bdr_faces;
|
||||
ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces);
|
||||
Array<int> bdr_edges, bdr_vertices, bdr_faces, bdr_planars;
|
||||
// if (mesh->Dimension() < 4)
|
||||
// {
|
||||
ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces, bdr_planars);
|
||||
// }
|
||||
|
||||
auto mark_dofs = [&](ElementTransformation &transf, const FiniteElement &fe)
|
||||
{
|
||||
@@ -2188,6 +2195,37 @@ void GridFunction::AccumulateAndCountBdrValues(
|
||||
const FiniteElement *fe = fes->GetFaceElement(face);
|
||||
mark_dofs(*transf, *fe);
|
||||
}
|
||||
for (int i = 0; i < bdr_planars.Size(); i++)
|
||||
{
|
||||
const FiniteElement *fe;
|
||||
ElementTransformation *transf;
|
||||
int planar = bdr_planars[i];
|
||||
fes->GetPlanarVDofs(planar, vdofs);
|
||||
if (vdofs.Size() == 0) { continue; }
|
||||
|
||||
transf = mesh->GetPlanarTransformation(planar);
|
||||
transf->Attribute = -1; // FIXME: set the boundary attribute
|
||||
fe = fes->GetPlanarElement(planar);
|
||||
vals.SetSize(fe->GetDof());
|
||||
for (int d = 0; d < vdim; d++)
|
||||
{
|
||||
if (!coeff[d]) { continue; }
|
||||
|
||||
fe->Project(*coeff[d], *transf, vals);
|
||||
for (int k = 0; k < vals.Size(); k++)
|
||||
{
|
||||
int ind = vdofs[d*vals.Size()+k];
|
||||
if (++values_counter[ind] == 1)
|
||||
{
|
||||
(*this)(ind) = vals(k);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*this)(ind) += vals(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3926,7 +3964,7 @@ void GridFunction::LegacyNCReorder()
|
||||
mesh->GetEdgeVertices(i, ev);
|
||||
if (old_vertex[ev[0]] > old_vertex[ev[1]])
|
||||
{
|
||||
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, -1);
|
||||
const int *ind = fes->FEColl()->DofOrderForOrientation(Geometry::SEGMENT, -1);
|
||||
|
||||
fes->GetEdgeInteriorDofs(i, dofs);
|
||||
for (int k = 0; k < dofs.Size(); k++)
|
||||
|
||||
+11
-11
@@ -30,14 +30,14 @@ namespace mfem
|
||||
class GridFunction : public Vector
|
||||
{
|
||||
protected:
|
||||
/// FE space on which the grid function lives. Owned if #fec is not NULL.
|
||||
/// FE space on which the grid function lives. Owned if #fec_owned is not NULL.
|
||||
FiniteElementSpace *fes;
|
||||
|
||||
/** @brief Used when the grid function is read from a file. It can also be
|
||||
set explicitly, see MakeOwner().
|
||||
|
||||
If not NULL, this pointer is owned by the GridFunction. */
|
||||
FiniteElementCollection *fec;
|
||||
FiniteElementCollection *fec_owned;
|
||||
|
||||
long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
|
||||
|
||||
@@ -72,16 +72,16 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
|
||||
GridFunction() { fes = NULL; fec_owned = NULL; fes_sequence = 0; UseDevice(true); }
|
||||
|
||||
/// Copy constructor. The internal true-dof vector #t_vec is not copied.
|
||||
GridFunction(const GridFunction &orig)
|
||||
: Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
|
||||
: Vector(orig), fes(orig.fes), fec_owned(NULL), fes_sequence(orig.fes_sequence)
|
||||
{ UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction associated with the FiniteElementSpace @a *f.
|
||||
GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction using previously allocated array @a data.
|
||||
/** The GridFunction does not assume ownership of @a data which is assumed to
|
||||
@@ -91,13 +91,13 @@ public:
|
||||
*/
|
||||
GridFunction(FiniteElementSpace *f, real_t *data)
|
||||
: Vector(data, f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/** @brief Construct a GridFunction using previously allocated Vector @a base
|
||||
starting at the given offset, @a base_offset. */
|
||||
GridFunction(FiniteElementSpace *f, Vector &base, int base_offset = 0)
|
||||
: Vector(base, base_offset, f->GetVSize())
|
||||
{ fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
{ fes = f; fec_owned = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
|
||||
|
||||
/// Construct a GridFunction on the given Mesh, using the data from @a input.
|
||||
/** The content of @a input should be in the format created by the method
|
||||
@@ -116,12 +116,12 @@ public:
|
||||
GridFunction &operator=(const GridFunction &rhs)
|
||||
{ return operator=((const Vector &)rhs); }
|
||||
|
||||
/// Make the GridFunction the owner of #fec and #fes.
|
||||
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
|
||||
/// Make the GridFunction the owner of #fec_owned and #fes.
|
||||
/** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec_owned
|
||||
and #fes is taken away. */
|
||||
void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
|
||||
void MakeOwner(FiniteElementCollection *fec_) { fec_owned = fec_; }
|
||||
|
||||
FiniteElementCollection *OwnFEC() { return fec; }
|
||||
FiniteElementCollection *OwnFEC() { return fec_owned; }
|
||||
|
||||
int VectorDim() const;
|
||||
int CurlDim() const;
|
||||
|
||||
+194
-1
@@ -151,10 +151,14 @@ void IntegrationRule::GrundmannMollerSimplexRule(int s, int n)
|
||||
ip.weight = weight;
|
||||
ip.x = real_t(2*beta[0] + 1)/(d + n - 2*i);
|
||||
ip.y = real_t(2*beta[1] + 1)/(d + n - 2*i);
|
||||
if (n == 3)
|
||||
if (n >= 3)
|
||||
{
|
||||
ip.z = real_t(2*beta[2] + 1)/(d + n - 2*i);
|
||||
}
|
||||
if (n == 4)
|
||||
{
|
||||
ip.t = real_t(2*beta[3] + 1)/(d + n - 2*i);
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
while (sums[j] == k)
|
||||
@@ -994,6 +998,12 @@ IntegrationRules::IntegrationRules(int ref, int type)
|
||||
CubeIntRules.SetSize(32, h_mt);
|
||||
CubeIntRules = NULL;
|
||||
|
||||
PentatopeIntRules.SetSize(32, h_mt);
|
||||
PentatopeIntRules = NULL;
|
||||
|
||||
TesseractIntRules.SetSize(32, h_mt);
|
||||
TesseractIntRules = NULL;
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
IntRuleLocks.SetSize(Geometry::NUM_GEOMETRIES, h_mt);
|
||||
for (int i = 0; i < Geometry::NUM_GEOMETRIES; i++)
|
||||
@@ -1017,6 +1027,8 @@ const IntegrationRule &IntegrationRules::Get(int GeomType, int Order)
|
||||
case Geometry::CUBE: ir_array = &CubeIntRules; break;
|
||||
case Geometry::PRISM: ir_array = &PrismIntRules; break;
|
||||
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
|
||||
case Geometry::PENTATOPE: ir_array = &PentatopeIntRules; break;
|
||||
case Geometry::TESSERACT: ir_array = &TesseractIntRules; break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -1067,6 +1079,8 @@ void IntegrationRules::Set(int GeomType, int Order, IntegrationRule &IntRule)
|
||||
case Geometry::CUBE: ir_array = &CubeIntRules; break;
|
||||
case Geometry::PRISM: ir_array = &PrismIntRules; break;
|
||||
case Geometry::PYRAMID: ir_array = &PyramidIntRules; break;
|
||||
case Geometry::PENTATOPE: ir_array = &PentatopeIntRules; break;
|
||||
case Geometry::TESSERACT: ir_array = &TesseractIntRules; break;
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -1125,6 +1139,8 @@ IntegrationRules::~IntegrationRules()
|
||||
DeleteIntRuleArray(CubeIntRules);
|
||||
DeleteIntRuleArray(PrismIntRules);
|
||||
DeleteIntRuleArray(PyramidIntRules);
|
||||
DeleteIntRuleArray(PentatopeIntRules);
|
||||
DeleteIntRuleArray(TesseractIntRules);
|
||||
}
|
||||
|
||||
|
||||
@@ -1149,6 +1165,10 @@ IntegrationRule *IntegrationRules::GenerateIntegrationRule(int GeomType,
|
||||
return PrismIntegrationRule(Order);
|
||||
case Geometry::PYRAMID:
|
||||
return PyramidIntegrationRule(Order);
|
||||
case Geometry::PENTATOPE:
|
||||
return PentatopeIntegrationRule(Order);
|
||||
case Geometry::TESSERACT:
|
||||
return TesseractIntegrationRule(Order);
|
||||
case Geometry::INVALID:
|
||||
case Geometry::NUM_GEOMETRIES:
|
||||
MFEM_ABORT("Unknown type of reference element!");
|
||||
@@ -1862,6 +1882,179 @@ IntegrationRule *IntegrationRules::CubeIntegrationRule(int Order)
|
||||
return CubeIntRules[Order];
|
||||
}
|
||||
|
||||
IntegrationRule *IntegrationRules::PentatopeIntegrationRule(int Order)
|
||||
{
|
||||
IntegrationRule *ir;
|
||||
|
||||
#ifdef MFEM_DEBUG_INTRULES
|
||||
mfem::out << "requesting integration rules for pentatopes ( order = " << Order << " )!" << endl;
|
||||
#endif
|
||||
|
||||
switch (Order)
|
||||
{
|
||||
case 0: // 1 point - degree 1
|
||||
case 1:
|
||||
PentatopeIntRules[0] = PentatopeIntRules[1] = ir = new IntegrationRule(1);
|
||||
ir->AddPentMidPoint(0, 1./24.);
|
||||
ir->SetOrder(1);
|
||||
return ir;
|
||||
|
||||
case 2: // 5 points - degree 2 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
PentatopeIntRules[2] = ir = new IntegrationRule(5);
|
||||
ir->AddPentPoints5(0, 0.11835034190722738822731940899757, 1/120.);
|
||||
ir->SetOrder(2);
|
||||
return ir;
|
||||
|
||||
case 3: // 15 points - degree 3 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
PentatopeIntRules[3] = ir = new IntegrationRule(15);
|
||||
ir->AddPentPoints5(0, 0.05666638104005152637432374262971, 0.01971744594977651449108080328187 / 24.);
|
||||
ir->AddPentPoints10(5, 0.08282378463560803594223358459203, 0.5 - 1.5 * 0.08282378463560803594223358459203, 0.09014127702511173789723386562400 / 24.);
|
||||
ir->SetOrder(3);
|
||||
return ir;
|
||||
|
||||
case 4: // 35 points - degree 5 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
case 5:
|
||||
PentatopeIntRules[4] = PentatopeIntRules[5] = ir = new IntegrationRule(35);
|
||||
ir->AddPentPoints5(0, 0.08639272923225102540634168235556, 0.05144687284129603743743075483508 / 24.);
|
||||
ir->AddPentPoints10(5, 0.02401496720062019571417799568280, 0.5 - 1.5 * 0.02401496720062019571417799568280, 0.01075810672318828174753857496171 / 24.);
|
||||
ir->AddPentPoints20(15, 0.29381800402893687440553094347706, 0.06247517556258090631882140542075, 0.03175922842808185514451579933848 / 24.);
|
||||
ir->SetOrder(5);
|
||||
return ir;
|
||||
|
||||
case 6: // 70 points - degree 6 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
PentatopeIntRules[6] = ir = new IntegrationRule(70);
|
||||
ir->AddPentPoints5(0, 0.154743213149364, 0.027287104452858 / 24.);
|
||||
ir->AddPentPoints5(5, 0.243583446244066, 0.030022493650412 / 24.);
|
||||
ir->AddPentPoints10(10, 0.045742589279674, 0.5 - 1.5 * 0.045742589279674, 0.010857537843152 / 24.);
|
||||
ir->AddPentPoints20(20, 0.034061388191316, 0.153237752298796, 0.004213752156913 / 24.);
|
||||
ir->AddPentPoints30(40, 0.042203997139861, 0.211681755872075, 0.017353386263795 / 24.);
|
||||
ir->SetOrder(6);
|
||||
return ir;
|
||||
|
||||
case 7: // 126 points - degree 8 -- taken from https://doi.org/10.1016/j.camwa.2020.07.004
|
||||
case 8:
|
||||
PentatopeIntRules[7] = PentatopeIntRules[8] = ir = new IntegrationRule(126);
|
||||
ir->AddPentMidPoint(0, 0.018477072894310 / 24.);
|
||||
ir->AddPentPoints5(1, 0.041850193209872, 0.003356028785577 / 24.);
|
||||
ir->AddPentPoints20(6, 0.013234490721597, 0.279965061732618, 0.001166950584118 / 24.);
|
||||
ir->AddPentPoints20(26, 0.183538643543872, 0.051063845643639, 0.019804745119265 / 24.);
|
||||
ir->AddPentPoints20(46, 0.311385773831175, 0.014631015332223, 0.005373375682319 / 24.);
|
||||
ir->AddPentPoints30(66, 0.032042227982220, 0.160928155464441, 0.007544402046650 / 24.);
|
||||
ir->AddPentPoints30(96, 0.088725307776945, 0.403464343042675, 0.007050309802142 / 24.);
|
||||
ir->SetOrder(8);
|
||||
return ir;
|
||||
|
||||
case -1:
|
||||
{
|
||||
//construct the higher integration rules with the duffy transformation --> 1d integral in time and a tet quad-rule w.r.t space
|
||||
|
||||
IntegrationRule *timeIR = SegmentIntegrationRule(Order + 2);
|
||||
IntegrationRule *tetIR = TetrahedronIntegrationRule(Order);
|
||||
|
||||
int NIP = timeIR->GetNPoints() * tetIR->GetNPoints();
|
||||
AllocIntRule(PentatopeIntRules, Order);
|
||||
PentatopeIntRules[Order] = ir = new IntegrationRule(NIP);
|
||||
|
||||
#ifdef MFEM_DEBUG
|
||||
mfem::out << "higher integration rules for pentatopes implemented with duffy ( order = " << Order << " ) --> " << NIP << " int. points!" << endl;
|
||||
#endif
|
||||
|
||||
double xi,yi,zi,ti, weight;
|
||||
|
||||
int pos = 0;
|
||||
for (int i=0; i<timeIR->GetNPoints(); i++)
|
||||
{
|
||||
ti = timeIR->IntPoint(i).x;
|
||||
|
||||
for (int j=0; j<tetIR->GetNPoints(); j++)
|
||||
{
|
||||
xi = (1. - ti) * tetIR->IntPoint(j).x;
|
||||
yi = (1. - ti) * tetIR->IntPoint(j).y;
|
||||
zi = (1. - ti) * tetIR->IntPoint(j).z;
|
||||
weight = timeIR->IntPoint(i).weight * tetIR->IntPoint(j).weight * (1.-ti) *
|
||||
(1.-ti) * (1.-ti);
|
||||
#ifdef MFEM_DEBUG
|
||||
if(weight<0) mfem::out << "warning weight is negative!" << endl;
|
||||
#endif
|
||||
ir->AddPentPoint(pos, xi,yi,zi,ti,weight);
|
||||
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
#ifdef MFEM_DEBUG_INTRULES
|
||||
char str[256];
|
||||
mfem::out << "The points and weights are:" << endl;
|
||||
for (int k = 0; k < ir->Size(); ++k)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(k);
|
||||
sprintf(str, "{%.16f, {%.16f, %.16f, %.16f, %.16f}},", ip.weight, ip.x, ip.y, ip.z, ip.t);
|
||||
mfem::out << str << endl;
|
||||
}
|
||||
#endif
|
||||
// 2025 November: Don't we need "return ir;"? It was not there
|
||||
return ir;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
int i = (Order / 2) * 2 + 1; // Get closest odd # >= Order
|
||||
AllocIntRule(PentatopeIntRules, i);
|
||||
ir = new IntegrationRule;
|
||||
ir->GrundmannMollerSimplexRule(i/2,4);
|
||||
PentatopeIntRules[i-1] = PentatopeIntRules[i] = ir;
|
||||
return ir;
|
||||
}
|
||||
}
|
||||
|
||||
return PentatopeIntRules[Order];
|
||||
|
||||
}
|
||||
|
||||
IntegrationRule *IntegrationRules::TesseractIntegrationRule(int Order)
|
||||
{
|
||||
int k, l, m, n, np, index;
|
||||
int i = (Order / 2) * 2 + 1; // Get closest odd # >= Order
|
||||
|
||||
if (!HaveIntRule(SegmentIntRules, i))
|
||||
{
|
||||
SegmentIntegrationRule(i);
|
||||
}
|
||||
AllocIntRule(TesseractIntRules, i);
|
||||
np = SegmentIntRules[i] -> GetNPoints();
|
||||
TesseractIntRules[i-1] = TesseractIntRules[i] = new IntegrationRule(
|
||||
np*np*np*np);
|
||||
index = 0;
|
||||
for (k = 0; k < np; k++)
|
||||
for (l = 0; l < np; l++)
|
||||
for (m = 0; m < np; m++)
|
||||
for (n = 0; n < np; n++)
|
||||
{
|
||||
// index = ((k*np+l)*np+m)*np + n;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).x =
|
||||
SegmentIntRules[i] -> IntPoint(n).x;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).y =
|
||||
SegmentIntRules[i] -> IntPoint(m).x;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).z =
|
||||
SegmentIntRules[i] -> IntPoint(l).x;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).t =
|
||||
SegmentIntRules[i] -> IntPoint(k).x;
|
||||
|
||||
TesseractIntRules[i] -> IntPoint(index).weight =
|
||||
SegmentIntRules[i] -> IntPoint(k).weight *
|
||||
SegmentIntRules[i] -> IntPoint(l).weight *
|
||||
SegmentIntRules[i] -> IntPoint(m).weight *
|
||||
SegmentIntRules[i] -> IntPoint(n).weight;
|
||||
|
||||
index++;
|
||||
}
|
||||
TesseractIntRules[i]->SetOrder(i);
|
||||
return TesseractIntRules[i];
|
||||
}
|
||||
|
||||
IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
|
||||
const int patch, const int *ijk,
|
||||
Array<const KnotVector*> const& kv,
|
||||
|
||||
+124
-4
@@ -34,18 +34,18 @@ class Mesh;
|
||||
class IntegrationPoint
|
||||
{
|
||||
public:
|
||||
real_t x, y, z, weight;
|
||||
real_t x, y, z, t, weight;
|
||||
int index;
|
||||
|
||||
void Init(int const i)
|
||||
{
|
||||
x = y = z = weight = 0.0;
|
||||
x = y = z = t = weight = 0.0;
|
||||
index = i;
|
||||
}
|
||||
|
||||
void Set(const real_t *p, const int dim)
|
||||
{
|
||||
MFEM_ASSERT(1 <= dim && dim <= 3, "invalid dim: " << dim);
|
||||
MFEM_ASSERT(1 <= dim && dim <= 4, "invalid dim: " << dim);
|
||||
x = p[0];
|
||||
if (dim > 1)
|
||||
{
|
||||
@@ -53,13 +53,17 @@ public:
|
||||
if (dim > 2)
|
||||
{
|
||||
z = p[2];
|
||||
if (dim > 3)
|
||||
{
|
||||
t = p[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Get(real_t *p, const int dim) const
|
||||
{
|
||||
MFEM_ASSERT(1 <= dim && dim <= 3, "invalid dim: " << dim);
|
||||
MFEM_ASSERT(1 <= dim && dim <= 4, "invalid dim: " << dim);
|
||||
p[0] = x;
|
||||
if (dim > 1)
|
||||
{
|
||||
@@ -67,6 +71,10 @@ public:
|
||||
if (dim > 2)
|
||||
{
|
||||
p[2] = z;
|
||||
if (dim > 3)
|
||||
{
|
||||
p[3] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +82,17 @@ public:
|
||||
void Set(const real_t x1, const real_t x2, const real_t x3, const real_t w)
|
||||
{ x = x1; y = x2; z = x3; weight = w; }
|
||||
|
||||
void Set4w(const real_t *p) { x = p[0]; y = p[1]; z = p[2]; t = p[3]; weight = p[4]; }
|
||||
|
||||
void Set4w(const real_t x1, const real_t x2, const real_t x3, const real_t x4,
|
||||
const real_t w)
|
||||
{ x = x1; y = x2; z = x3; t = x4; weight = w; }
|
||||
|
||||
void Set4(const real_t *p) { x = p[0]; y = p[1]; z = p[2]; t = p[3]; }
|
||||
|
||||
void Set4(const real_t x1, const real_t x2, const real_t x3, const real_t x4)
|
||||
{ x = x1; y = x2; z = x3; t = x4; }
|
||||
|
||||
void Set3w(const real_t *p) { x = p[0]; y = p[1]; z = p[2]; weight = p[3]; }
|
||||
|
||||
void Set3(const real_t x1, const real_t x2, const real_t x3)
|
||||
@@ -219,6 +238,103 @@ private:
|
||||
AddTetPoints6(off + 6, a, b, c, weight);
|
||||
}
|
||||
|
||||
void AddPentMidPoint(const int off, const double weight)
|
||||
{ IntPoint(off).Set4w(0.2, 0.2, 0.2, 0.2, weight); }
|
||||
|
||||
void AddPentPoint(const int off, const double x, const double y, const double z,
|
||||
const double t, double weight)
|
||||
{
|
||||
IntPoint(off).Set4w(x, y, z, t, weight);
|
||||
}
|
||||
|
||||
// given (a), add the permuations of (a,a,a,a,b), b = 1 - 4*a
|
||||
void AddPentPoints5(const int off, const double a,
|
||||
double weight)
|
||||
{
|
||||
const double b = 1. - 4 * a;
|
||||
IntPoint(off + 0).Set4w(a, a, a, a, weight);
|
||||
IntPoint(off + 1).Set4w(b, a, a, a, weight);
|
||||
IntPoint(off + 2).Set4w(a, b, a, a, weight);
|
||||
IntPoint(off + 3).Set4w(a, a, b, a, weight);
|
||||
IntPoint(off + 4).Set4w(a, a, a, b, weight);
|
||||
}
|
||||
|
||||
// given (a,b), add the permuations of (a,a,a,b,b)
|
||||
void AddPentPoints10(const int off, const double a, const double b, double weight)
|
||||
{
|
||||
IntPoint(off + 0).Set4w(a, a, a, b, weight);
|
||||
IntPoint(off + 1).Set4w(a, a, b, a, weight);
|
||||
IntPoint(off + 2).Set4w(a, a, b, b, weight);
|
||||
IntPoint(off + 3).Set4w(a, b, a, a, weight);
|
||||
IntPoint(off + 4).Set4w(a, b, a, b, weight);
|
||||
IntPoint(off + 5).Set4w(a, b, b, a, weight);
|
||||
IntPoint(off + 6).Set4w(b, a, a, a, weight);
|
||||
IntPoint(off + 7).Set4w(b, a, a, b, weight);
|
||||
IntPoint(off + 8).Set4w(b, a, b, a, weight);
|
||||
IntPoint(off + 9).Set4w(b, b, a, a, weight);
|
||||
}
|
||||
|
||||
// given (a,b,c), add the permuations of (a,a,a,b,c), c = 1 - 3 a - b
|
||||
void AddPentPoints20(const int off, const double a, const double b, double weight)
|
||||
{
|
||||
const double c = 1. - 3. * a - b;
|
||||
IntPoint(off + 0).Set4w(a, a, a, b, weight);
|
||||
IntPoint(off + 1).Set4w(a, a, a, c, weight);
|
||||
IntPoint(off + 2).Set4w(a, a, b, a, weight);
|
||||
IntPoint(off + 3).Set4w(a, a, b, c, weight);
|
||||
IntPoint(off + 4).Set4w(a, a, c, a, weight);
|
||||
IntPoint(off + 5).Set4w(a, a, c, b, weight);
|
||||
IntPoint(off + 6).Set4w(a, b, a, a, weight);
|
||||
IntPoint(off + 7).Set4w(a, b, a, c, weight);
|
||||
IntPoint(off + 8).Set4w(a, b, c, a, weight);
|
||||
IntPoint(off + 9).Set4w(a, c, a, a, weight);
|
||||
IntPoint(off + 10).Set4w(a, c, a, b, weight);
|
||||
IntPoint(off + 11).Set4w(a, c, b, a, weight);
|
||||
IntPoint(off + 12).Set4w(b, a, a, a, weight);
|
||||
IntPoint(off + 13).Set4w(b, a, a, c, weight);
|
||||
IntPoint(off + 14).Set4w(b, a, c, a, weight);
|
||||
IntPoint(off + 15).Set4w(b, c, a, a, weight);
|
||||
IntPoint(off + 16).Set4w(c, a, a, a, weight);
|
||||
IntPoint(off + 17).Set4w(c, a, a, b, weight);
|
||||
IntPoint(off + 18).Set4w(c, a, b, a, weight);
|
||||
IntPoint(off + 19).Set4w(c, b, a, a, weight);
|
||||
}
|
||||
// given (a,b,c), add the permutations of (a,a,b,b,c), c = 1 - 2 a - 2 b
|
||||
void AddPentPoints30(const int off, const double a, const double b, double weight)
|
||||
{
|
||||
double c = 1. - 2. * a - 2. * b;
|
||||
IntPoint(off + 0).Set4w(a, a, b, b, weight);
|
||||
IntPoint(off + 1).Set4w(a, a, b, c, weight);
|
||||
IntPoint(off + 2).Set4w(a, a, c, b, weight);
|
||||
IntPoint(off + 3).Set4w(a, b, a, b, weight);
|
||||
IntPoint(off + 4).Set4w(a, b, a, c, weight);
|
||||
IntPoint(off + 5).Set4w(a, b, b, a, weight);
|
||||
IntPoint(off + 6).Set4w(a, b, b, c, weight);
|
||||
IntPoint(off + 7).Set4w(a, b, c, a, weight);
|
||||
IntPoint(off + 8).Set4w(a, b, c, b, weight);
|
||||
IntPoint(off + 9).Set4w(a, c, a, b, weight);
|
||||
IntPoint(off + 10).Set4w(a, c, b, a, weight);
|
||||
IntPoint(off + 11).Set4w(a, c, b, b, weight);
|
||||
IntPoint(off + 12).Set4w(b, a, a, b, weight);
|
||||
IntPoint(off + 13).Set4w(b, a, a, c, weight);
|
||||
IntPoint(off + 14).Set4w(b, a, b, a, weight);
|
||||
IntPoint(off + 15).Set4w(b, a, b, c, weight);
|
||||
IntPoint(off + 16).Set4w(b, a, c, a, weight);
|
||||
IntPoint(off + 17).Set4w(b, a, c, b, weight);
|
||||
IntPoint(off + 18).Set4w(b, b, a, a, weight);
|
||||
IntPoint(off + 19).Set4w(b, b, a, c, weight);
|
||||
IntPoint(off + 20).Set4w(b, b, c, a, weight);
|
||||
IntPoint(off + 21).Set4w(b, c, a, a, weight);
|
||||
IntPoint(off + 22).Set4w(b, c, a, b, weight);
|
||||
IntPoint(off + 23).Set4w(b, c, b, a, weight);
|
||||
IntPoint(off + 24).Set4w(c, a, a, b, weight);
|
||||
IntPoint(off + 25).Set4w(c, a, b, a, weight);
|
||||
IntPoint(off + 26).Set4w(c, a, b, b, weight);
|
||||
IntPoint(off + 27).Set4w(c, b, a, a, weight);
|
||||
IntPoint(off + 28).Set4w(c, b, a, b, weight);
|
||||
IntPoint(off + 29).Set4w(c, b, b, a, weight);
|
||||
}
|
||||
|
||||
public:
|
||||
IntegrationRule() :
|
||||
Array<IntegrationPoint>() { }
|
||||
@@ -430,6 +546,8 @@ private:
|
||||
Array<IntegrationRule *> PyramidIntRules;
|
||||
Array<IntegrationRule *> PrismIntRules;
|
||||
Array<IntegrationRule *> CubeIntRules;
|
||||
Array<IntegrationRule *> PentatopeIntRules;
|
||||
Array<IntegrationRule *> TesseractIntRules;
|
||||
|
||||
#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
|
||||
Array<omp_lock_t> IntRuleLocks;
|
||||
@@ -464,6 +582,8 @@ private:
|
||||
IntegrationRule *PyramidIntegrationRule(int Order);
|
||||
IntegrationRule *PrismIntegrationRule(int Order);
|
||||
IntegrationRule *CubeIntegrationRule(int Order);
|
||||
IntegrationRule *PentatopeIntegrationRule(int Order);
|
||||
IntegrationRule *TesseractIntegrationRule(int Order);
|
||||
|
||||
public:
|
||||
/// Sets initial sizes for the integration rule arrays, but rules
|
||||
|
||||
@@ -249,6 +249,12 @@ public:
|
||||
FiniteElementSpace #fes. */
|
||||
LinearForm &operator=(const Vector &v);
|
||||
|
||||
/// Change ownership of linear form integrators.
|
||||
void SetIntegratorOwnership(int _extern_lfs)
|
||||
{
|
||||
extern_lfs = _extern_lfs;
|
||||
}
|
||||
|
||||
/// Destroys linear form.
|
||||
~LinearForm();
|
||||
};
|
||||
|
||||
+51
-1
@@ -174,7 +174,6 @@ public:
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
|
||||
/// Class for boundary integration $ L(v) := (g, v) $
|
||||
class BoundaryLFIntegrator : public LinearFormIntegrator
|
||||
{
|
||||
@@ -782,6 +781,57 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MatFEDomainLFIntegrator : public LinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
MatrixCoefficient &QF;
|
||||
DenseMatrix vshape;
|
||||
DenseMatrix mat;
|
||||
Vector matToVec;
|
||||
|
||||
public:
|
||||
MatFEDomainLFIntegrator (MatrixCoefficient &F) : QF(F) { }
|
||||
|
||||
virtual void AssembleRHSElementVect(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
Vector &elvect)
|
||||
{
|
||||
int dof = el.GetDof();
|
||||
int dim = el.GetDim();
|
||||
|
||||
vshape.SetSize(dof,dim*dim);
|
||||
mat.SetSize(dim,dim);
|
||||
matToVec.SetSize(dim*dim);
|
||||
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
// int intorder = 2*el.GetOrder() - 1; // ok for O(h^{k+1}) conv. in L2
|
||||
int intorder = 2*el.GetOrder() + 2;
|
||||
ir = &IntRules.Get(el.GetGeomType(), intorder);
|
||||
}
|
||||
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
Tr.SetIntPoint (&ip);
|
||||
|
||||
el.CalcVShape(Tr, vshape);
|
||||
|
||||
QF.Eval (mat, Tr, ip);
|
||||
mat *= ip.weight * fabs(Tr.Weight());
|
||||
for (int ki=0; ki<dim; ki++) for (int kj=0; kj<dim; kj++) { matToVec(dim*ki+kj) = mat(ki,kj); }
|
||||
|
||||
vshape.AddMult(matToVec, elvect);
|
||||
}
|
||||
}
|
||||
|
||||
using LinearFormIntegrator::AssembleRHSElementVect;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -330,6 +330,18 @@ public:
|
||||
/// Compute y += a (P^t A P) x, where x and y are vectors on the true dofs
|
||||
void TrueAddMult(const Vector &x, Vector &y, const real_t a = 1.0) const;
|
||||
|
||||
using MixedBilinearForm::Update;
|
||||
virtual void Update(ParFiniteElementSpace *ntr_fes = NULL,
|
||||
ParFiniteElementSpace *nte_fes = NULL)
|
||||
{
|
||||
MixedBilinearForm::Update(ntr_fes, nte_fes);
|
||||
if (ntr_fes && nte_fes )
|
||||
{
|
||||
trial_pfes = ntr_fes;
|
||||
test_pfes = nte_fes;
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~ParMixedBilinearForm() { }
|
||||
};
|
||||
|
||||
|
||||
+269
-6
@@ -174,10 +174,11 @@ void ParFiniteElementSpace::Construct()
|
||||
ngfdofs = pncmesh->GetNGhostFaces()
|
||||
* fec->DofForGeometry(Geometry::Type::SQUARE);
|
||||
}
|
||||
ngpdofs = 0;
|
||||
|
||||
// total number of ghost DOFs. Ghost DOFs start at index 'ndofs', i.e.,
|
||||
// after all regular DOFs
|
||||
ngdofs = ngvdofs + ngedofs + ngfdofs;
|
||||
ngdofs = ngvdofs + ngedofs + ngfdofs + ngpdofs;
|
||||
|
||||
// get P and R matrices, initialize DOF offsets, etc. NOTE: in the NC
|
||||
// case this needs to be done here to get the number of true DOFs
|
||||
@@ -235,8 +236,11 @@ void ParFiniteElementSpace::GetGroupComm(
|
||||
int gr;
|
||||
int ng = pmesh->GetNGroups();
|
||||
int nvd, ned, ntd = 0, nqd = 0;
|
||||
int nted = 0;
|
||||
Array<int> dofs;
|
||||
|
||||
int dim = pmesh->Dimension();
|
||||
|
||||
int group_ldof_counter;
|
||||
Table &group_ldof = gc.GroupLDofTable();
|
||||
|
||||
@@ -253,6 +257,10 @@ void ParFiniteElementSpace::GetGroupComm(
|
||||
{
|
||||
nqd = fec->DofForGeometry(Geometry::SQUARE);
|
||||
}
|
||||
if (mesh->HasGeometry(Geometry::TETRAHEDRON) && dim > 3)
|
||||
{
|
||||
nted = fec->DofForGeometry(Geometry::TETRAHEDRON);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_ldof_sign)
|
||||
@@ -269,6 +277,11 @@ void ParFiniteElementSpace::GetGroupComm(
|
||||
group_ldof_counter += ned * pmesh->GroupNEdges(gr);
|
||||
group_ldof_counter += ntd * pmesh->GroupNTriangles(gr);
|
||||
group_ldof_counter += nqd * pmesh->GroupNQuadrilaterals(gr);
|
||||
if (dim > 3)
|
||||
{
|
||||
group_ldof_counter += nted * pmesh->GroupNTetrahedra(
|
||||
gr); // FIXME: ensure that tet-group is always build
|
||||
}
|
||||
}
|
||||
if (ldof_type)
|
||||
{
|
||||
@@ -282,13 +295,14 @@ void ParFiniteElementSpace::GetGroupComm(
|
||||
group_ldof.GetI()[0] = group_ldof.GetI()[1] = 0;
|
||||
for (gr = 1; gr < ng; gr++)
|
||||
{
|
||||
int j, k, l, m, o, nv, ne, nt, nq;
|
||||
int j, k, l, m, o, nv, ne, nt, nq, nte;
|
||||
const int *ind;
|
||||
|
||||
nv = pmesh->GroupNVertices(gr);
|
||||
ne = pmesh->GroupNEdges(gr);
|
||||
nt = pmesh->GroupNTriangles(gr);
|
||||
nq = pmesh->GroupNQuadrilaterals(gr);
|
||||
nte = (dim>3) ? pmesh->GroupNTetrahedra(gr) : 0; // FIXME
|
||||
|
||||
// vertices
|
||||
if (nvd > 0)
|
||||
@@ -362,7 +376,14 @@ void ParFiniteElementSpace::GetGroupComm(
|
||||
pmesh->GroupTriangle(gr, j, k, o);
|
||||
|
||||
dofs.SetSize(ntd);
|
||||
m = nvdofs + nedofs + FirstFaceDof(k);
|
||||
if (dim == 4)
|
||||
{
|
||||
m = nvdofs+nedofs+pdofs[k];
|
||||
}
|
||||
else
|
||||
{
|
||||
m = nvdofs + nedofs + FirstFaceDof(k);
|
||||
}
|
||||
ind = fec->DofOrderForOrientation(Geometry::TRIANGLE, o);
|
||||
for (l = 0; l < ntd; l++)
|
||||
{
|
||||
@@ -430,6 +451,45 @@ void ParFiniteElementSpace::GetGroupComm(
|
||||
}
|
||||
}
|
||||
|
||||
// tetrahedra (4D)
|
||||
if (nted > 0)
|
||||
{
|
||||
for (j = 0; j < nte; j++)
|
||||
{
|
||||
pmesh->GroupTetrahedron(gr, j, k, o);
|
||||
|
||||
dofs.SetSize(nted);
|
||||
m = nvdofs+nedofs+npdofs+ FirstFaceDof(k);
|
||||
ind = fec->DofOrderForOrientation(
|
||||
mesh->GetFaceGeometry(k), o);
|
||||
for (l = 0; l < nted; l++)
|
||||
{
|
||||
if (ind[l] < 0)
|
||||
{
|
||||
dofs[l] = m + (-1-ind[l]);
|
||||
if (g_ldof_sign)
|
||||
{
|
||||
(*g_ldof_sign)[dofs[l]] = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dofs[l] = m + ind[l];
|
||||
}
|
||||
}
|
||||
|
||||
if (ldof_type)
|
||||
{
|
||||
DofsToVDofs(dofs);
|
||||
}
|
||||
|
||||
for (l = 0; l < dofs.Size(); l++)
|
||||
{
|
||||
group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group_ldof.GetI()[gr+1] = group_ldof_counter;
|
||||
}
|
||||
|
||||
@@ -651,6 +711,30 @@ void ParFiniteElementSpace::GetSharedQuadrilateralDofs(
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetSharedTetrahedronDofs(
|
||||
int group, int fi, Array<int> &dofs) const
|
||||
{
|
||||
int l_face, ori;
|
||||
MFEM_ASSERT(0 <= fi &&
|
||||
fi < pmesh->GroupNTetrahedra(group), "invalid face index");
|
||||
pmesh->GroupTetrahedron(group, fi, l_face, ori);
|
||||
if (ori == 0)
|
||||
{
|
||||
GetFaceDofs(l_face, dofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
Array<int> rdofs;
|
||||
fec->SubDofOrder(pmesh->GetFaceGeometry(l_face), 2, ori, dofs);
|
||||
GetFaceDofs(l_face, rdofs);
|
||||
for (int i = 0; i < dofs.Size(); i++)
|
||||
{
|
||||
const int di = dofs[i];
|
||||
dofs[i] = (di >= 0) ? rdofs[di] : -1-rdofs[-1-di];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GenerateGlobalOffsets() const
|
||||
{
|
||||
MFEM_ASSERT(Conforming(), "wrong code path");
|
||||
@@ -1738,6 +1822,115 @@ void ParFiniteElementSpace::GetGhostFaceDofs(const MeshId &face_id,
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetGhostFaceDofs4D(const MeshId &face_id,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
#if 0
|
||||
MFEM_ASSERT(mesh->GetFaceBaseGeometry(0) == Geometry::TETRAHEDRON, "");
|
||||
|
||||
int nv = fec->DofForGeometry(Geometry::POINT);
|
||||
int ne = fec->DofForGeometry(Geometry::SEGMENT);
|
||||
int np = fec->DofForGeometry(Geometry::TRIANGLE);
|
||||
int nf = fec->DofForGeometry(Geometry::TETRAHEDRON);
|
||||
dofs.SetSize(4*nv + 6*ne + 4*np + nf);
|
||||
|
||||
int V[4], E[6], Eo[6], P[4], Po[4];
|
||||
pmesh->pncmesh->GetFaceVerticesEdgesPlanars(face_id, V, E, Eo, P, Po);
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int ghost = pncmesh->GetNVertices();
|
||||
int first = (V[i] < ghost) ? V[i]*nv : (ndofs + (V[i] - ghost)*nv);
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
dofs[offset++] = first + j;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
int ghost = pncmesh->GetNEdges();
|
||||
int first = (E[i] < ghost) ? nvdofs + E[i]*ne
|
||||
/* */ : ndofs + ngvdofs + (E[i] - ghost)*ne;
|
||||
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[i]);
|
||||
for (int j = 0; j < ne; j++)
|
||||
{
|
||||
dofs[offset++] = (ind[j] >= 0) ? (first + ind[j])
|
||||
/* */ : (-1 - (first + (-1 - ind[j])));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
// TODO higher order
|
||||
int ghost = pncmesh->GetNPlanars();
|
||||
int first = (P[i] < ghost) ? nvdofs + nedofs + P[i]*np
|
||||
/* */ : ndofs + ngvdofs + nedofs + ngedofs + (P[i] - ghost)*np;
|
||||
// const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[i]);
|
||||
for (int j = 0; j < np; j++)
|
||||
{
|
||||
dofs[offset++] = first + j;
|
||||
}
|
||||
}
|
||||
|
||||
int first = ndofs + ngvdofs + ngedofs +
|
||||
(face_id.index - pncmesh->GetNFaces())*nf;
|
||||
for (int j = 0; j < nf; j++)
|
||||
{
|
||||
dofs[offset++] = first + j;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetGhostPlanarDofs(const MeshId &planar_id,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
#if 0
|
||||
MFEM_ASSERT(mesh->GetPlanarBaseGeometry(0) == Geometry::TRIANGLE, "");
|
||||
|
||||
int nv = fec->DofForGeometry(Geometry::POINT);
|
||||
int ne = fec->DofForGeometry(Geometry::SEGMENT);
|
||||
int np = fec->DofForGeometry(Geometry::TRIANGLE);
|
||||
dofs.SetSize(3*nv + 3*ne + np);
|
||||
|
||||
int V[3], E[3], Eo[3];
|
||||
pmesh->pncmesh->GetPlanarVerticesEdges(planar_id, V, E, Eo);
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
int ghost = pncmesh->GetNVertices();
|
||||
int first = (V[i] < ghost) ? V[i]*nv : (ndofs + (V[i] - ghost)*nv);
|
||||
for (int j = 0; j < nv; j++)
|
||||
{
|
||||
dofs[offset++] = first + j;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
int ghost = pncmesh->GetNEdges();
|
||||
int first = (E[i] < ghost) ? nvdofs + E[i]*ne
|
||||
/* */ : ndofs + ngvdofs + (E[i] - ghost)*ne;
|
||||
const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, Eo[i]);
|
||||
for (int j = 0; j < ne; j++)
|
||||
{
|
||||
dofs[offset++] = (ind[j] >= 0) ? (first + ind[j])
|
||||
/* */ : (-1 - (first + (-1 - ind[j])));
|
||||
}
|
||||
}
|
||||
|
||||
int first = ndofs + ngvdofs + ngedofs +
|
||||
(planar_id.index - pncmesh->GetNPlanars())*np;
|
||||
for (int j = 0; j < np; j++)
|
||||
{
|
||||
dofs[offset++] = first + j;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void ParFiniteElementSpace::GetGhostDofs(int entity, const MeshId &id,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
@@ -1750,6 +1943,19 @@ void ParFiniteElementSpace::GetGhostDofs(int entity, const MeshId &id,
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetGhostDofs4D(int entity, const MeshId &id,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
// helper to get ghost vertex, ghost edge or ghost face DOFs
|
||||
switch (entity)
|
||||
{
|
||||
case 0: GetGhostVertexDofs(id, dofs); break;
|
||||
case 1: GetGhostEdgeDofs(id, dofs); break;
|
||||
case 2: GetGhostPlanarDofs(id, dofs); break;
|
||||
case 3: GetGhostFaceDofs4D(id, dofs); break;
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetBareDofs(int entity, int index,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
@@ -1800,6 +2006,55 @@ void ParFiniteElementSpace::GetBareDofs(int entity, int index,
|
||||
}
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetBareDofs4D(int entity, int index,
|
||||
Array<int> &dofs) const
|
||||
{
|
||||
#if 0
|
||||
int ned, ghost, first;
|
||||
switch (entity)
|
||||
{
|
||||
case 0:
|
||||
ned = fec->DofForGeometry(Geometry::POINT);
|
||||
ghost = pncmesh->GetNVertices();
|
||||
first = (index < ghost)
|
||||
? index*ned // regular vertex
|
||||
: ndofs + (index - ghost)*ned; // ghost vertex
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ned = fec->DofForGeometry(Geometry::SEGMENT);
|
||||
ghost = pncmesh->GetNEdges();
|
||||
first = (index < ghost)
|
||||
? nvdofs + index*ned // regular edge
|
||||
: ndofs + ngvdofs + (index - ghost)*ned; // ghost edge
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ned = fec->DofForGeometry(mesh->GetPlanarBaseGeometry(0));
|
||||
ghost = pncmesh->GetNPlanars();
|
||||
first = (index < ghost)
|
||||
? nvdofs + nedofs + index*ned
|
||||
: ndofs + ngvdofs + ngedofs + (index - ghost)*ned;
|
||||
break;
|
||||
|
||||
default:
|
||||
ned = fec->DofForGeometry(mesh->GetFaceBaseGeometry(0));
|
||||
ghost = pncmesh->GetNFaces();
|
||||
first = (index < ghost)
|
||||
? nvdofs + nedofs + npdofs + index*ned // regular face
|
||||
: ndofs + ngvdofs + ngedofs + ngpdofs + (index - ghost)*ned; // ghost
|
||||
break;
|
||||
}
|
||||
|
||||
dofs.SetSize(ned);
|
||||
for (int i = 0; i < ned; i++)
|
||||
{
|
||||
dofs[i] = first + i;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int ParFiniteElementSpace::PackDof(int entity, int index, int edof) const
|
||||
{
|
||||
// DOFs are ordered as follows:
|
||||
@@ -2406,7 +2661,7 @@ int ParFiniteElementSpace
|
||||
Array<int> *dof_tdof,
|
||||
bool partial) const
|
||||
{
|
||||
const bool dg = (nvdofs == 0 && nedofs == 0 && nfdofs == 0);
|
||||
const bool dg = (nvdofs == 0 && nedofs == 0 && nfdofs == 0 && npdofs == 0);
|
||||
|
||||
#ifdef MFEM_PMATRIX_STATS
|
||||
n_msgs_sent = n_msgs_recv = 0;
|
||||
@@ -2469,7 +2724,7 @@ int ParFiniteElementSpace
|
||||
|
||||
list.OrientedPointMatrix(sf, T.GetPointMat());
|
||||
fe->GetLocalInterpolation(T, I);
|
||||
|
||||
// mfem::out << "**************\n";
|
||||
// make each slave DOF dependent on all master DOFs
|
||||
AddDependencies(deps, master_dofs, slave_dofs, I);
|
||||
}
|
||||
@@ -2497,7 +2752,14 @@ int ParFiniteElementSpace
|
||||
GroupId owner = pncmesh->GetEntityOwnerId(entity, id.index);
|
||||
GroupId group = pncmesh->GetEntityGroupId(entity, id.index);
|
||||
|
||||
GetBareDofs(entity, id.index, dofs);
|
||||
if (pmesh->Dimension() <= 3)
|
||||
{
|
||||
GetBareDofs(entity, id.index, dofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetBareDofs4D(entity, id.index, dofs);
|
||||
}
|
||||
|
||||
for (auto dof : dofs)
|
||||
{
|
||||
@@ -2506,6 +2768,7 @@ int ParFiniteElementSpace
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// initialize dof_group[], dof_owner[] in sequence
|
||||
for (int entity : {0,1,2})
|
||||
{
|
||||
|
||||
+7
-1
@@ -45,7 +45,7 @@ private:
|
||||
mutable int ltdof_size;
|
||||
|
||||
/// Number of vertex/edge/face/total ghost DOFs (nonconforming case).
|
||||
int ngvdofs, ngedofs, ngfdofs, ngdofs;
|
||||
int ngvdofs, ngedofs, ngfdofs, ngdofs, ngpdofs;
|
||||
|
||||
/// The group of each local dof.
|
||||
Array<int> ldof_group;
|
||||
@@ -126,8 +126,13 @@ private:
|
||||
void GetGhostFaceDofs(const MeshId &face_id, Array<int> &dofs) const;
|
||||
void GetGhostDofs(int entity, const MeshId &id, Array<int> &dofs) const;
|
||||
|
||||
void GetGhostFaceDofs4D(const MeshId &face_id, Array<int> &dofs) const;
|
||||
void GetGhostPlanarDofs(const MeshId &planar_id, Array<int> &dofs) const;
|
||||
void GetGhostDofs4D(int entity, const MeshId &id, Array<int> &dofs) const;
|
||||
|
||||
/// Return the dofs associated with the interior of the given mesh entity.
|
||||
void GetBareDofs(int entity, int index, Array<int> &dofs) const;
|
||||
void GetBareDofs4D(int entity, int index, Array<int> &dofs) const;
|
||||
|
||||
int PackDof(int entity, int index, int edof) const;
|
||||
void UnpackDof(int dof, int &entity, int &index, int &edof) const;
|
||||
@@ -322,6 +327,7 @@ public:
|
||||
void GetSharedEdgeDofs(int group, int ei, Array<int> &dofs) const;
|
||||
void GetSharedTriangleDofs(int group, int fi, Array<int> &dofs) const;
|
||||
void GetSharedQuadrilateralDofs(int group, int fi, Array<int> &dofs) const;
|
||||
void GetSharedTetrahedronDofs(int group, int fi, Array<int> &dofs) const;
|
||||
|
||||
/// The true dof-to-dof interpolation matrix
|
||||
HypreParMatrix *Dof_TrueDof_Matrix() const
|
||||
|
||||
+4
-3
@@ -39,9 +39,10 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, const GridFunction *gf,
|
||||
{
|
||||
const FiniteElementSpace *glob_fes = gf->FESpace();
|
||||
// duplicate the FiniteElementCollection from 'gf'
|
||||
fec = FiniteElementCollection::New(glob_fes->FEColl()->Name());
|
||||
fec_owned = FiniteElementCollection::New(glob_fes->FEColl()->Name());
|
||||
// create a local ParFiniteElementSpace from the global one:
|
||||
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning, fec);
|
||||
fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
|
||||
fec_owned);
|
||||
SetSize(pfes->GetVSize());
|
||||
|
||||
if (partitioning)
|
||||
@@ -81,7 +82,7 @@ ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
|
||||
: GridFunction(pmesh, input)
|
||||
{
|
||||
// Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec, fes->GetVDim(),
|
||||
pfes = new ParFiniteElementSpace(pmesh, fec_owned, fes->GetVDim(),
|
||||
fes->GetOrdering());
|
||||
delete fes;
|
||||
fes = pfes;
|
||||
|
||||
@@ -39,12 +39,22 @@ struct Hashed4
|
||||
int next;
|
||||
};
|
||||
|
||||
/** A concept for items that should be used in HashTable and be accessible by
|
||||
* hashing 5 IDs. temporary workaround for 4D (need a structure where all 4 ids a stored)
|
||||
*/
|
||||
struct Hashed5
|
||||
{
|
||||
int p1, p2, p3, p4; // NOTE: p5 is not hashed nor stored
|
||||
int next;
|
||||
};
|
||||
|
||||
|
||||
/** HashTable is a container for items that require associative access through
|
||||
* pairs (or quadruples) of indices:
|
||||
*
|
||||
* (p1, p2) -> item
|
||||
* (p1, p2, p3, p4) -> item
|
||||
* (p1, p2, p3, p4, p5) -> item
|
||||
*
|
||||
* An example of this are edges and faces in a mesh. Each edge is uniquely
|
||||
* identified by two parent vertices and so can be easily accessed from
|
||||
@@ -120,6 +130,7 @@ public:
|
||||
|
||||
@warning This method should only be called if T inherits from Hashed4. */
|
||||
T* Get(int p1, int p2, int p3, int p4 = -1 /* p4 optional */);
|
||||
T* Get(int p1, int p2, int p3, int p4, int p5);
|
||||
|
||||
/// Get id of item whose parents are p1, p2... Create it if it doesn't exist.
|
||||
/** @brief Get the "id" of an item, this "id" corresponding to the index of the
|
||||
@@ -145,6 +156,7 @@ public:
|
||||
|
||||
@warning This method should only be called if T inherits from Hashed4. */
|
||||
int GetId(int p1, int p2, int p3, int p4 = -1);
|
||||
int GetId(int p1, int p2, int p3, int p4, int p5);
|
||||
|
||||
/// Find item whose parents are p1, p2... Return NULL if it doesn't exist.
|
||||
/** @brief Item accessor with key (or parents) the pair 'p1', 'p2'. Return
|
||||
@@ -169,6 +181,7 @@ public:
|
||||
|
||||
@warning This method should only be called if T inherits from Hashed4. */
|
||||
T* Find(int p1, int p2, int p3, int p4 = -1);
|
||||
T* Find(int p1, int p2, int p3, int p4, int p5);
|
||||
|
||||
/** @brief Item const accessor with key (or parents) the pair 'p1', 'p2'.
|
||||
Return nullptr if no value correspond to the requested key.
|
||||
@@ -192,6 +205,7 @@ public:
|
||||
|
||||
@warning This method should only be called if T inherits from Hashed4. */
|
||||
const T* Find(int p1, int p2, int p3, int p4 = -1) const;
|
||||
const T* Find(int p1, int p2, int p3, int p4, int p5) const;
|
||||
|
||||
/// Find id of item whose parents are p1, p2... Return -1 if it doesn't exist.
|
||||
/** @brief Find the "id" of an item, this "id" corresponding to the index of
|
||||
@@ -217,6 +231,7 @@ public:
|
||||
|
||||
@warning This method should only be called if T inherits from Hashed4. */
|
||||
int FindId(int p1, int p2, int p3, int p4 = -1) const;
|
||||
int FindId(int p1, int p2, int p3, int p4, int p5) const;
|
||||
|
||||
/// @brief Return the number of elements currently stored in the HashTable.
|
||||
int Size() const { return Base::Size() - unused.Size(); }
|
||||
@@ -283,6 +298,8 @@ public:
|
||||
|
||||
@warning This method should only be called if T inherits from Hashed4. */
|
||||
void Reparent(int id, int new_p1, int new_p2, int new_p3, int new_p4 = -1);
|
||||
void Reparent(int id, int new_p1, int new_p2, int new_p3, int new_p4,
|
||||
int new_p5);
|
||||
|
||||
/// @brief Return total size of allocated memory (tables plus items), in bytes.
|
||||
std::size_t MemoryUsage() const;
|
||||
@@ -380,6 +397,9 @@ protected:
|
||||
inline int Hash(size_t p1, size_t p2, size_t p3) const
|
||||
{ return (984120265ul*p1 + 125965121ul*p2 + 495698413ul*p3) & mask; }
|
||||
|
||||
inline int Hash(int p1, int p2, int p3, int p4) const
|
||||
{ return (984120265*p1 + 125965121*p2 + 495698413*p3 + 179424673*p4) & mask; }
|
||||
|
||||
// Delete() and Reparent() use one of these:
|
||||
/// @brief Hash function for items of type T that inherit from Hashed2.
|
||||
inline int Hash(const Hashed2& item) const
|
||||
@@ -389,6 +409,9 @@ protected:
|
||||
inline int Hash(const Hashed4& item) const
|
||||
{ return Hash(item.p1, item.p2, item.p3); }
|
||||
|
||||
inline int Hash(const Hashed5& item) const
|
||||
{ return Hash(item.p1, item.p2, item.p3, item.p4); };
|
||||
|
||||
/** @brief Search the index of the item associated to the key (p1,p2)
|
||||
starting from the item with index @a id.
|
||||
|
||||
@@ -411,6 +434,7 @@ protected:
|
||||
|
||||
@warning This method should only be called if T inherits from Hashed4. */
|
||||
int SearchList(int id, int p1, int p2, int p3) const;
|
||||
int SearchList(int id, int p1, int p2, int p3, int p4) const;
|
||||
|
||||
/** @brief Insert the item 'id' into bin 'idx'.
|
||||
|
||||
@@ -581,6 +605,17 @@ inline void sort4(int &a, int &b, int &c, int &d)
|
||||
sort3(b, c, d);
|
||||
}
|
||||
|
||||
inline void sort5(int &a, int &b, int &c, int &d, int &e)
|
||||
{
|
||||
sort4(a,b,c,d);
|
||||
sort4(b,c,d,e);
|
||||
|
||||
if (a > b)
|
||||
{
|
||||
int t = a; a = b; b = t;
|
||||
}
|
||||
}
|
||||
|
||||
inline void sort4_ext(int &a, int &b, int &c, int &d)
|
||||
{
|
||||
if (d < 0) // support optional last index
|
||||
@@ -607,6 +642,12 @@ inline T* HashTable<T>::Get(int p1, int p2, int p3, int p4)
|
||||
return &(Base::At(GetId(p1, p2, p3, p4)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* HashTable<T>::Get(int p1, int p2, int p3, int p4, int p5)
|
||||
{
|
||||
return &(Base::At(GetId(p1, p2, p3, p4, p5)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int HashTable<T>::GetId(int p1, int p2)
|
||||
{
|
||||
@@ -670,6 +711,39 @@ int HashTable<T>::GetId(int p1, int p2, int p3, int p4)
|
||||
return new_id;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int HashTable<T>::GetId(int p1, int p2, int p3, int p4, int p5)
|
||||
{
|
||||
// search for the item in the hashtable
|
||||
internal::sort5(p1, p2, p3, p4, p5);
|
||||
int idx = Hash(p1, p2, p3, p4);
|
||||
int id = SearchList(table[idx], p1, p2, p3, p4);
|
||||
if (id >= 0) { return id; }
|
||||
|
||||
// not found - use an unused item or create a new one
|
||||
int new_id;
|
||||
if (unused.Size())
|
||||
{
|
||||
new_id = unused.Last();
|
||||
unused.DeleteLast();
|
||||
}
|
||||
else
|
||||
{
|
||||
new_id = Base::Append();
|
||||
}
|
||||
T& item = Base::At(new_id);
|
||||
item.p1 = p1;
|
||||
item.p2 = p2;
|
||||
item.p3 = p3;
|
||||
item.p4 = p4;
|
||||
|
||||
// insert into hashtable
|
||||
Insert(idx, new_id, item);
|
||||
CheckRehash();
|
||||
|
||||
return new_id;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* HashTable<T>::Find(int p1, int p2)
|
||||
{
|
||||
@@ -684,6 +758,13 @@ inline T* HashTable<T>::Find(int p1, int p2, int p3, int p4)
|
||||
return (id >= 0) ? &(Base::At(id)) : NULL;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* HashTable<T>::Find(int p1, int p2, int p3, int p4, int p5)
|
||||
{
|
||||
int id = FindId(p1, p2, p3, p4, p5);
|
||||
return (id >= 0) ? &(Base::At(id)) : NULL;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* HashTable<T>::Find(int p1, int p2) const
|
||||
{
|
||||
@@ -698,6 +779,13 @@ inline const T* HashTable<T>::Find(int p1, int p2, int p3, int p4) const
|
||||
return (id >= 0) ? &(Base::At(id)) : NULL;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* HashTable<T>::Find(int p1, int p2, int p3, int p4, int p5) const
|
||||
{
|
||||
int id = FindId(p1, p2, p3, p4, p5);
|
||||
return (id >= 0) ? &(Base::At(id)) : NULL;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int HashTable<T>::FindId(int p1, int p2) const
|
||||
{
|
||||
@@ -712,6 +800,13 @@ int HashTable<T>::FindId(int p1, int p2, int p3, int p4) const
|
||||
return SearchList(table[Hash(p1, p2, p3)], p1, p2, p3);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int HashTable<T>::FindId(int p1, int p2, int p3, int p4, int p5) const
|
||||
{
|
||||
internal::sort5(p1, p2, p3, p4, p5);
|
||||
return SearchList(table[Hash(p1, p2, p3, p4)], p1, p2, p3, p4);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int HashTable<T>::SearchList(int id, int p1, int p2) const
|
||||
{
|
||||
@@ -736,6 +831,18 @@ int HashTable<T>::SearchList(int id, int p1, int p2, int p3) const
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
int HashTable<T>::SearchList(int id, int p1, int p2, int p3, int p4) const
|
||||
{
|
||||
while (id >= 0)
|
||||
{
|
||||
const T& item = Base::At(id);
|
||||
if (item.p1 == p1 && item.p2 == p2 && item.p3 == p3 && item.p4 == p4) { return id; }
|
||||
id = item.next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void HashTable<T>::CheckRehash()
|
||||
{
|
||||
@@ -877,6 +984,24 @@ void HashTable<T>::Reparent(int id,
|
||||
Insert(new_idx, id, item);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void HashTable<T>::Reparent(int id,
|
||||
int new_p1, int new_p2, int new_p3, int new_p4, int new_p5)
|
||||
{
|
||||
T& item = Base::At(id);
|
||||
Unlink(Hash(item), id);
|
||||
|
||||
internal::sort5(new_p1, new_p2, new_p3, new_p4, new_p5);
|
||||
item.p1 = new_p1;
|
||||
item.p2 = new_p2;
|
||||
item.p3 = new_p3;
|
||||
item.p4 = new_p4;
|
||||
|
||||
// reinsert under new parent IDs
|
||||
int new_idx = Hash(new_p1, new_p2, new_p3, new_p4);
|
||||
Insert(new_idx, id, item);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::size_t HashTable<T>::MemoryUsage() const
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ int isockstream::establish()
|
||||
{
|
||||
// char myname[129];
|
||||
char myname[] = "localhost";
|
||||
int sfd;
|
||||
int sfd = -1;
|
||||
struct addrinfo hints, *res, *rp;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
|
||||
+247
-30
@@ -10,6 +10,7 @@
|
||||
// CONTRIBUTING.md for details.
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include "error.hpp"
|
||||
#include "stable3d.hpp"
|
||||
|
||||
@@ -31,36 +32,6 @@ STable3D::STable3D (int nr)
|
||||
NElem = 0;
|
||||
}
|
||||
|
||||
inline void Sort3 (int &r, int &c, int &f)
|
||||
{
|
||||
int t;
|
||||
|
||||
if (r > c)
|
||||
if (c > f)
|
||||
{
|
||||
t = r; r = f; f = t; // (r,c,f) --> (f,c,r)
|
||||
}
|
||||
else if (r > f)
|
||||
{
|
||||
t = r; r = c; c = f; f = t; // (r,c,f) --> (c,f,r)
|
||||
}
|
||||
else
|
||||
{
|
||||
t = r; r = c; c = t; // (r,c,f) --> (c,r,f)
|
||||
}
|
||||
else if (c > f)
|
||||
{
|
||||
if (r > f)
|
||||
{
|
||||
t = f; f = c; c = r; r = t; // (r,c,f) --> (f,r,c)
|
||||
}
|
||||
else
|
||||
{
|
||||
t = c; c = f; f = t; // (r,c,f) --> (r,f,c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int STable3D::Push (int r, int c, int f)
|
||||
{
|
||||
STable3DNode *node;
|
||||
@@ -225,4 +196,250 @@ void STable3D::Print(std::ostream & os) const
|
||||
}
|
||||
}
|
||||
|
||||
STable4D::STable4D (int nr)
|
||||
{
|
||||
int i;
|
||||
|
||||
Size = nr;
|
||||
Rows = new STable4DNode *[nr];
|
||||
for (i = 0; i < nr; i++)
|
||||
{
|
||||
Rows[i] = NULL;
|
||||
}
|
||||
NElem = 0;
|
||||
}
|
||||
|
||||
|
||||
int STable4D::Push (int r, int c, int f, int t)
|
||||
{
|
||||
STable4DNode *node;
|
||||
|
||||
MFEM_ASSERT(r != c && c != f && f != r && r!=t && c!=t && f!=t,
|
||||
"STable4D::Push : r = " << r << ", c = " << c << ", f = " << f << ", t = " <<
|
||||
t);
|
||||
|
||||
Sort4(r, c, f, t);
|
||||
|
||||
for (node = Rows[r]; node != NULL; node = node->Prev)
|
||||
{
|
||||
if (node->Column == c)
|
||||
if (node->Floor == f)
|
||||
if (node->Trace == t)
|
||||
{
|
||||
return node->Number;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
node = NodesMem.Alloc ();
|
||||
#else
|
||||
node = new STable4DNode;
|
||||
#endif
|
||||
node->Column = c;
|
||||
node->Floor = f;
|
||||
node->Trace = t;
|
||||
node->Number = NElem;
|
||||
node->Prev = Rows[r];
|
||||
Rows[r] = node;
|
||||
|
||||
NElem++;
|
||||
return (NElem-1);
|
||||
}
|
||||
|
||||
int STable4D::operator() (int r, int c, int f, int t) const
|
||||
{
|
||||
STable4DNode *node;
|
||||
|
||||
Sort4(r, c, f, t);
|
||||
|
||||
for (node = Rows[r]; node != NULL; node = node->Prev)
|
||||
{
|
||||
if (node->Column == c)
|
||||
if (node->Floor == f)
|
||||
if (node->Trace == t)
|
||||
{
|
||||
return node->Number;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_ABORT("STable4D::operator(): (r,c,f,t) = (" << r << "," << c << "," << f <<
|
||||
"," << t <<")");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int STable4D::Index (int r, int c, int f, int t) const
|
||||
{
|
||||
STable4DNode *node;
|
||||
|
||||
Sort4(r, c, f, t);
|
||||
|
||||
for (node = Rows[r]; node != NULL; node = node->Prev)
|
||||
{
|
||||
if (node->Column == c)
|
||||
if (node->Floor == f)
|
||||
if (node->Trace == t)
|
||||
{
|
||||
return node->Number;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
STable4D::~STable4D ()
|
||||
{
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
// NodesMem.Clear(); // this is done implicitly
|
||||
#else
|
||||
for (int i = 0; i < Size; i++)
|
||||
{
|
||||
STable4DNode *aux, *node_p = Rows[i];
|
||||
while (node_p != NULL)
|
||||
{
|
||||
aux = node_p;
|
||||
node_p = node_p->Prev;
|
||||
delete aux;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
delete [] Rows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
STable5D::STable5D (int nr)
|
||||
{
|
||||
int i;
|
||||
|
||||
Size = nr;
|
||||
Rows = new STable5DNode *[nr];
|
||||
for (i = 0; i < nr; i++)
|
||||
{
|
||||
Rows[i] = NULL;
|
||||
}
|
||||
NElem = 0;
|
||||
}
|
||||
|
||||
|
||||
int STable5D::Push (int r, int c, int f, int t, int u)
|
||||
{
|
||||
STable5DNode *node;
|
||||
|
||||
MFEM_ASSERT(r != c && c != f && f != r && r!=t && c!=t && f!=t && r!=u &&
|
||||
c!=u && f!=u && t!=u,
|
||||
"STable5D::Push : r = " << r << ", c = " << c << ", f = " << f << ", t = " << t
|
||||
<< ", u = " << u);
|
||||
|
||||
Sort5(r, c, f, t, u);
|
||||
|
||||
for (node = Rows[r]; node != NULL; node = node->Prev)
|
||||
{
|
||||
if (node->Column == c)
|
||||
if (node->Floor == f)
|
||||
if (node->Trace == t)
|
||||
if (node->Next == u)
|
||||
{
|
||||
return node->Number;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
node = NodesMem.Alloc ();
|
||||
#else
|
||||
node = new STable5DNode;
|
||||
#endif
|
||||
node->Column = c;
|
||||
node->Floor = f;
|
||||
node->Trace = t;
|
||||
node->Next = u;
|
||||
node->Number = NElem;
|
||||
node->Prev = Rows[r];
|
||||
Rows[r] = node;
|
||||
|
||||
NElem++;
|
||||
return (NElem-1);
|
||||
}
|
||||
|
||||
int STable5D::operator() (int r, int c, int f, int t, int u) const
|
||||
{
|
||||
STable5DNode *node;
|
||||
|
||||
Sort5(r, c, f, t, u);
|
||||
|
||||
for (node = Rows[r]; node != NULL; node = node->Prev)
|
||||
{
|
||||
if (node->Column == c)
|
||||
if (node->Floor == f)
|
||||
if (node->Trace == t)
|
||||
if (node->Next == u)
|
||||
{
|
||||
return node->Number;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_ABORT("STable4D::operator(): (r,c,f,t,u) = (" << r << "," << c << "," << f
|
||||
<< "," << t << "," << u <<")");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int STable5D::Index (int r, int c, int f, int t, int u) const
|
||||
{
|
||||
STable5DNode *node;
|
||||
|
||||
Sort5(r, c, f, t, u);
|
||||
|
||||
for (node = Rows[r]; node != NULL; node = node->Prev)
|
||||
{
|
||||
if (node->Column == c)
|
||||
if (node->Floor == f)
|
||||
if (node->Trace == t)
|
||||
{
|
||||
return node->Number;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int STable5D::Push8 (int u1, int u2, int u3, int u4, int u5, int u6, int u7,
|
||||
int u8)
|
||||
{
|
||||
Sort8(u1, u2, u3, u4, u5, u6, u7, u8);
|
||||
|
||||
return (*this).Push(u1,u2,u3,u4,u5);
|
||||
}
|
||||
|
||||
int STable5D::operator() (int u1, int u2, int u3, int u4, int u5, int u6,
|
||||
int u7, int u8) const
|
||||
{
|
||||
Sort8(u1, u2, u3, u4, u5, u6, u7, u8);
|
||||
|
||||
return (*this)(u1,u2,u3,u4,u5);
|
||||
}
|
||||
|
||||
|
||||
STable5D::~STable5D ()
|
||||
{
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
// NodesMem.Clear(); // this is done implicitly
|
||||
#else
|
||||
for (int i = 0; i < Size; i++)
|
||||
{
|
||||
STable5DNode *aux, *node_p = Rows[i];
|
||||
while (node_p != NULL)
|
||||
{
|
||||
aux = node_p;
|
||||
node_p = node_p->Prev;
|
||||
delete aux;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
delete [] Rows;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -75,6 +75,165 @@ public:
|
||||
~STable3D ();
|
||||
};
|
||||
|
||||
|
||||
class STable4DNode
|
||||
{
|
||||
public:
|
||||
STable4DNode *Prev;
|
||||
int Column, Floor, Trace, Number;
|
||||
};
|
||||
|
||||
|
||||
/// Symmetric 4D Table
|
||||
class STable4D
|
||||
{
|
||||
private:
|
||||
int Size, NElem;
|
||||
STable4DNode **Rows;
|
||||
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
MemAlloc <STable4DNode, 1024> NodesMem;
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit STable4D (int nr);
|
||||
|
||||
int Push (int r, int c, int f, int t);
|
||||
|
||||
int operator() (int r, int c, int f, int t) const;
|
||||
|
||||
int Index (int r, int c, int f, int t) const;
|
||||
|
||||
int NumberOfElements() { return NElem; };
|
||||
|
||||
~STable4D ();
|
||||
};
|
||||
|
||||
|
||||
|
||||
class STable5DNode
|
||||
{
|
||||
public:
|
||||
STable5DNode *Prev;
|
||||
int Column, Floor, Trace, Next, Number;
|
||||
};
|
||||
|
||||
/// Symmetric 5D Table
|
||||
class STable5D
|
||||
{
|
||||
private:
|
||||
int Size, NElem;
|
||||
STable5DNode **Rows;
|
||||
|
||||
#ifdef MFEM_USE_MEMALLOC
|
||||
MemAlloc <STable5DNode, 1024> NodesMem;
|
||||
#endif
|
||||
|
||||
public:
|
||||
explicit STable5D (int nr);
|
||||
|
||||
int Push (int r, int c, int f, int t, int u);
|
||||
|
||||
int operator() (int r, int c, int f, int t, int u) const;
|
||||
|
||||
int Index (int r, int c, int f, int t, int u) const;
|
||||
|
||||
int Push8 (int u1, int u2, int u3, int u4, int u5, int u6, int u7, int u8);
|
||||
int operator() (int u1, int u2, int u3, int u4, int u5, int u6, int u7,
|
||||
int u8) const;
|
||||
|
||||
int NumberOfElements() { return NElem; };
|
||||
|
||||
~STable5D ();
|
||||
};
|
||||
|
||||
|
||||
inline void Sort3 (int &r, int &c, int &f)
|
||||
{
|
||||
int t;
|
||||
|
||||
if (r > c)
|
||||
if (c > f)
|
||||
{
|
||||
t = r; r = f; f = t; // (r,c,f) --> (f,c,r)
|
||||
}
|
||||
else if (r > f)
|
||||
{
|
||||
t = r; r = c; c = f; f = t; // (r,c,f) --> (c,f,r)
|
||||
}
|
||||
else
|
||||
{
|
||||
t = r; r = c; c = t; // (r,c,f) --> (c,r,f)
|
||||
}
|
||||
else if (c > f)
|
||||
{
|
||||
if (r > f)
|
||||
{
|
||||
t = f; f = c; c = r; r = t; // (r,c,f) --> (f,r,c)
|
||||
}
|
||||
else
|
||||
{
|
||||
t = c; c = f; f = t; // (r,c,f) --> (r,f,c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void Sort4 (int &r, int &c, int &f, int &u)
|
||||
{
|
||||
Sort3(c,f,u);
|
||||
|
||||
int t;
|
||||
|
||||
if (r > c)
|
||||
{
|
||||
if (r <= f) //(r, c, f, u) --> (c, r, f, u)
|
||||
{
|
||||
t = r; r = c; c = t;
|
||||
}
|
||||
else if (r <= u) //(r, c, f, u) --> (c, f, r, u)
|
||||
{
|
||||
t = r; r = c; c = t;
|
||||
t = c; c = f; f = t;
|
||||
}
|
||||
else if (r > u) //(r, c, f, u) --> (c, f, u, r)
|
||||
{
|
||||
t = r; r = c; c = t;
|
||||
t = c; c = f; f = t;
|
||||
t = f; f = u; u = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void Sort5 (int &r, int &c, int &f, int &u, int &v)
|
||||
{
|
||||
Sort4(r,c,f,u);
|
||||
Sort4(c,f,u,v);
|
||||
|
||||
if (r > c)
|
||||
{
|
||||
int t = r; r = c; c = t;
|
||||
}
|
||||
}
|
||||
|
||||
//should be optimized
|
||||
inline void Sort8 (int &u1, int &u2, int &u3, int &u4, int &u5, int &u6,
|
||||
int &u7, int &u8)
|
||||
{
|
||||
Sort5(u1,u2,u3,u4,u5);
|
||||
Sort5(u4,u5,u6,u7,u8);
|
||||
|
||||
Sort5(u1,u2,u3,u4,u5);
|
||||
Sort5(u4,u5,u6,u7,u8);
|
||||
|
||||
Sort5(u1,u2,u3,u4,u5);
|
||||
Sort5(u4,u5,u6,u7,u8);
|
||||
|
||||
Sort5(u1,u2,u3,u4,u5);
|
||||
Sort5(u4,u5,u6,u7,u8);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+103
-10
@@ -647,6 +647,7 @@ real_t DenseMatrix::Det() const
|
||||
DenseMatrixInverse lu_factors(*this);
|
||||
|
||||
return lu_factors.Det();
|
||||
|
||||
}
|
||||
}
|
||||
// not reachable
|
||||
@@ -675,6 +676,24 @@ real_t DenseMatrix::Weight() const
|
||||
real_t F = d[0] * d[3] + d[1] * d[4] + d[2] * d[5];
|
||||
return sqrt(E * G - F * F);
|
||||
}
|
||||
else if ((Height() == 4) && (Width() == 1))
|
||||
{
|
||||
return sqrt(data[0] * data[0] + data[1] * data[1] + data[2] * data[2]
|
||||
+ data[3] * data[3]);
|
||||
}
|
||||
else if ((Height() == 4) && (Width() == 3))
|
||||
{
|
||||
const double *d = data;
|
||||
double A = d[0]*d[0] + d[1]*d[1] + d[2]*d[2] + d[3]*d[3];
|
||||
double B = d[0]*d[4] + d[1]*d[5] + d[2]*d[6] + d[3]*d[7];
|
||||
double C = d[0]*d[8] + d[1]*d[9] + d[2]*d[10] + d[3]*d[11];
|
||||
double D = d[4]*d[4] + d[5]*d[5] + d[6]*d[6] + d[7]*d[7];
|
||||
double E = d[4]*d[8] + d[5]*d[9] + d[6]*d[10] + d[7]*d[11];
|
||||
double F = d[8]*d[8] + d[9]*d[9] + d[10]*d[10] + d[11]*d[11];
|
||||
|
||||
|
||||
return sqrt( C *( 2*B*E - C*D ) - A*E*E + F * ( A * D - B * B) );
|
||||
}
|
||||
mfem_error("DenseMatrix::Weight(): mismatched or unsupported dimensions");
|
||||
return 0.0;
|
||||
}
|
||||
@@ -1442,7 +1461,7 @@ int DenseMatrix::Rank(real_t tol) const
|
||||
|
||||
real_t DenseMatrix::CalcSingularvalue(const int i) const
|
||||
{
|
||||
MFEM_ASSERT(Height() == Width() && Height() > 0 && Height() < 4,
|
||||
MFEM_ASSERT(Height() == Width() && Height() > 0 && Height() < 5,
|
||||
"The matrix must be square and sized 1, 2, or 3 to compute the"
|
||||
" singular values."
|
||||
<< " Height() = " << Height()
|
||||
@@ -1459,10 +1478,16 @@ real_t DenseMatrix::CalcSingularvalue(const int i) const
|
||||
{
|
||||
return kernels::CalcSingularvalue<2>(d,i);
|
||||
}
|
||||
else
|
||||
else if (n == 3)
|
||||
{
|
||||
return kernels::CalcSingularvalue<3>(d,i);
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector sv(n);
|
||||
SingularValues(sv);
|
||||
return sv(i);
|
||||
}
|
||||
}
|
||||
|
||||
void DenseMatrix::CalcEigenvalues(real_t *lambda, real_t *vec) const
|
||||
@@ -2670,7 +2695,7 @@ void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
|
||||
void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja)
|
||||
{
|
||||
#ifdef MFEM_DEBUG
|
||||
if (a.Width() > a.Height() || a.Width() < 1 || a.Height() > 3)
|
||||
if (a.Width() > a.Height() || a.Width() < 1 || a.Height() > 4)
|
||||
{
|
||||
mfem_error("CalcAdjugate(...): unsupported dimensions");
|
||||
}
|
||||
@@ -2723,7 +2748,7 @@ void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja)
|
||||
adja(1,0) = -a(1,0);
|
||||
adja(1,1) = a(0,0);
|
||||
}
|
||||
else
|
||||
else if (a.Width() == 3)
|
||||
{
|
||||
adja(0,0) = a(1,1)*a(2,2)-a(1,2)*a(2,1);
|
||||
adja(0,1) = a(0,2)*a(2,1)-a(0,1)*a(2,2);
|
||||
@@ -2737,13 +2762,51 @@ void CalcAdjugate(const DenseMatrix &a, DenseMatrix &adja)
|
||||
adja(2,1) = a(0,1)*a(2,0)-a(0,0)*a(2,1);
|
||||
adja(2,2) = a(0,0)*a(1,1)-a(0,1)*a(1,0);
|
||||
}
|
||||
else if (a.Width() == 4)
|
||||
{
|
||||
adja(0,0) = -a(1,3)*a(2,2)*a(3,1)+a(1,2)*a(2,3)*a(3,1)+a(1,3)*a(2,1)*a(3,2)-a(1,
|
||||
1)*a(2,3)*a(3,2)-a(1,2)*a(2,1)*a(3,3)+a(1,1)*a(2,2)*a(3,3);
|
||||
adja(0,1) = a(0,3)*a(2,2)*a(3,1)-a(0,2)*a(2,3)*a(3,1)-a(0,3)*a(2,1)*a(3,2)+a(0,
|
||||
1)*a(2,3)*a(3,2)+a(0,2)*a(2,1)*a(3,3)-a(0,1)*a(2,2)*a(3,3);
|
||||
adja(0,2) = -a(0,3)*a(1,2)*a(3,1)+a(0,2)*a(1,3)*a(3,1)+a(0,3)*a(1,1)*a(3,2)-a(0,
|
||||
1)*a(1,3)*a(3,2)-a(0,2)*a(1,1)*a(3,3)+a(0,1)*a(1,2)*a(3,3);
|
||||
adja(0,3) = a(0,3)*a(1,2)*a(2,1)-a(0,2)*a(1,3)*a(2,1)-a(0,3)*a(1,1)*a(2,2)+a(0,
|
||||
1)*a(1,3)*a(2,2)+a(0,2)*a(1,1)*a(2,3)-a(0,1)*a(1,2)*a(2,3);
|
||||
|
||||
adja(1,0) = a(1,3)*a(2,2)*a(3,0)-a(1,2)*a(2,3)*a(3,0)-a(1,3)*a(2,0)*a(3,2)+a(1,
|
||||
0)*a(2,3)*a(3,2)+a(1,2)*a(2,0)*a(3,3)-a(1,0)*a(2,2)*a(3,3);
|
||||
adja(1,1) = -a(0,3)*a(2,2)*a(3,0)+a(0,2)*a(2,3)*a(3,0)+a(0,3)*a(2,0)*a(3,2)-a(0,
|
||||
0)*a(2,3)*a(3,2)-a(0,2)*a(2,0)*a(3,3)+a(0,0)*a(2,2)*a(3,3);
|
||||
adja(1,2) = a(0,3)*a(1,2)*a(3,0)-a(0,2)*a(1,3)*a(3,0)-a(0,3)*a(1,0)*a(3,2)+a(0,
|
||||
0)*a(1,3)*a(3,2)+a(0,2)*a(1,0)*a(3,3)-a(0,0)*a(1,2)*a(3,3);
|
||||
adja(1,3) = -a(0,3)*a(1,2)*a(2,0)+a(0,2)*a(1,3)*a(2,0)+a(0,3)*a(1,0)*a(2,2)-a(0,
|
||||
0)*a(1,3)*a(2,2)-a(0,2)*a(1,0)*a(2,3)+a(0,0)*a(1,2)*a(2,3);
|
||||
|
||||
adja(2,0) = -a(1,3)*a(2,1)*a(3,0)+a(1,1)*a(2,3)*a(3,0)+a(1,3)*a(2,0)*a(3,1)-a(1,
|
||||
0)*a(2,3)*a(3,1)-a(1,1)*a(2,0)*a(3,3)+a(1,0)*a(2,1)*a(3,3);
|
||||
adja(2,1) = a(0,3)*a(2,1)*a(3,0)-a(0,1)*a(2,3)*a(3,0)-a(0,3)*a(2,0)*a(3,1)+a(0,
|
||||
0)*a(2,3)*a(3,1)+a(0,1)*a(2,0)*a(3,3)-a(0,0)*a(2,1)*a(3,3);
|
||||
adja(2,2) = -a(0,3)*a(1,1)*a(3,0)+a(0,1)*a(1,3)*a(3,0)+a(0,3)*a(1,0)*a(3,1)-a(0,
|
||||
0)*a(1,3)*a(3,1)-a(0,1)*a(1,0)*a(3,3)+a(0,0)*a(1,1)*a(3,3);
|
||||
adja(2,3) = a(0,3)*a(1,1)*a(2,0)-a(0,1)*a(1,3)*a(2,0)-a(0,3)*a(1,0)*a(2,1)+a(0,
|
||||
0)*a(1,3)*a(2,1)+a(0,1)*a(1,0)*a(2,3)-a(0,0)*a(1,1)*a(2,3);
|
||||
|
||||
adja(3,0) = a(1,2)*a(2,1)*a(3,0)-a(1,1)*a(2,2)*a(3,0)-a(1,2)*a(2,0)*a(3,1)+a(1,
|
||||
0)*a(2,2)*a(3,1)+a(1,1)*a(2,0)*a(3,2)-a(1,0)*a(2,1)*a(3,2);
|
||||
adja(3,1) = -a(0,2)*a(2,1)*a(3,0)+a(0,1)*a(2,2)*a(3,0)+a(0,2)*a(2,0)*a(3,1)-a(0,
|
||||
0)*a(2,2)*a(3,1)-a(0,1)*a(2,0)*a(3,2)+a(0,0)*a(2,1)*a(3,2);
|
||||
adja(3,2) = a(0,2)*a(1,1)*a(3,0)-a(0,1)*a(1,2)*a(3,0)-a(0,2)*a(1,0)*a(3,1)+a(0,
|
||||
0)*a(1,2)*a(3,1)+a(0,1)*a(1,0)*a(3,2)-a(0,0)*a(1,1)*a(3,2);
|
||||
adja(3,3) = -a(0,2)*a(1,1)*a(2,0)+a(0,1)*a(1,2)*a(2,0)+a(0,2)*a(1,0)*a(2,1)-a(0,
|
||||
0)*a(1,2)*a(2,1)-a(0,1)*a(1,0)*a(2,2)+a(0,0)*a(1,1)*a(2,2);
|
||||
}
|
||||
}
|
||||
|
||||
void CalcAdjugateTranspose(const DenseMatrix &a, DenseMatrix &adjat)
|
||||
{
|
||||
#ifdef MFEM_DEBUG
|
||||
if (a.Height() != a.Width() || adjat.Height() != adjat.Width() ||
|
||||
a.Width() != adjat.Width() || a.Width() < 1 || a.Width() > 3)
|
||||
a.Width() != adjat.Width() || a.Width() < 1 || a.Width() > 4)
|
||||
{
|
||||
mfem_error("CalcAdjugateTranspose(...): dimension mismatch");
|
||||
}
|
||||
@@ -2759,7 +2822,7 @@ void CalcAdjugateTranspose(const DenseMatrix &a, DenseMatrix &adjat)
|
||||
adjat(0,1) = -a(1,0);
|
||||
adjat(1,1) = a(0,0);
|
||||
}
|
||||
else
|
||||
else if (a.Width() == 3)
|
||||
{
|
||||
adjat(0,0) = a(1,1)*a(2,2)-a(1,2)*a(2,1);
|
||||
adjat(1,0) = a(0,2)*a(2,1)-a(0,1)*a(2,2);
|
||||
@@ -2773,11 +2836,17 @@ void CalcAdjugateTranspose(const DenseMatrix &a, DenseMatrix &adjat)
|
||||
adjat(1,2) = a(0,1)*a(2,0)-a(0,0)*a(2,1);
|
||||
adjat(2,2) = a(0,0)*a(1,1)-a(0,1)*a(1,0);
|
||||
}
|
||||
else if (a.Width() == 4)
|
||||
{
|
||||
CalcAdjugate(a, adjat);
|
||||
adjat.Transpose();
|
||||
// mfem_error("CalcAdjugateTranspose(...) - please implement the case for d = 4");
|
||||
}
|
||||
}
|
||||
|
||||
void CalcInverse(const DenseMatrix &a, DenseMatrix &inva)
|
||||
{
|
||||
MFEM_ASSERT(a.Width() <= a.Height() && a.Width() >= 1 && a.Height() <= 3, "");
|
||||
MFEM_ASSERT(a.Width() <= a.Height() && a.Width() >= 1 && a.Height() <= 4, "");
|
||||
MFEM_ASSERT(inva.Height() == a.Width(), "incorrect dimensions");
|
||||
MFEM_ASSERT(inva.Width() == a.Height(), "incorrect dimensions");
|
||||
|
||||
@@ -2820,6 +2889,12 @@ void CalcInverse(const DenseMatrix &a, DenseMatrix &inva)
|
||||
case 3:
|
||||
kernels::CalcInverse<3>(a.Data(), inva.Data());
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
CalcAdjugate(a, inva);
|
||||
inva *= 1./a.Det();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2859,15 +2934,22 @@ void CalcInverseTranspose(const DenseMatrix &a, DenseMatrix &inva)
|
||||
inva(1,2) = (a(0,1)*a(2,0)-a(0,0)*a(2,1))*t;
|
||||
inva(2,2) = (a(0,0)*a(1,1)-a(0,1)*a(1,0))*t;
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
CalcAdjugateTranspose(a, inva);
|
||||
inva *= t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CalcOrtho(const DenseMatrix &J, Vector &n)
|
||||
{
|
||||
MFEM_ASSERT( ((J.Height() == 2 && J.Width() == 1)
|
||||
|| (J.Height() == 3 && J.Width() == 2))
|
||||
|| (J.Height() == 3 && J.Width() == 2)
|
||||
|| (J.Height() == 4 && J.Width() == 3))
|
||||
&& (J.Height() == n.Size()),
|
||||
"Matrix must be 3x2 or 2x1, "
|
||||
"Matrix must be 4x3, 3x2 or 2x1, "
|
||||
<< "and the Vector must be sized with the rows. "
|
||||
<< " J.Height() = " << J.Height()
|
||||
<< ", J.Width() = " << J.Width()
|
||||
@@ -2880,12 +2962,23 @@ void CalcOrtho(const DenseMatrix &J, Vector &n)
|
||||
n(0) = d[1];
|
||||
n(1) = -d[0];
|
||||
}
|
||||
else
|
||||
else if (J.Height() == 3)
|
||||
{
|
||||
n(0) = d[1]*d[5] - d[2]*d[4];
|
||||
n(1) = d[2]*d[3] - d[0]*d[5];
|
||||
n(2) = d[0]*d[4] - d[1]*d[3];
|
||||
}
|
||||
else if (J.Height() == 4)
|
||||
{
|
||||
n(0) = -d[3]*d[6]*d[9]+d[2]*d[7]*d[9]+d[3]*d[5]*d[10]-d[1]*d[7]*d[10]
|
||||
-d[2]*d[5]*d[11]+d[1]*d[6]*d[11];
|
||||
n(1) = d[3]*d[6]*d[8]-d[2]*d[7]*d[8]-d[3]*d[4]*d[10]+d[0]*d[7]*d[10]
|
||||
+d[2]*d[4]*d[11]-d[0]*d[6]*d[11];
|
||||
n(2) = -d[3]*d[5]*d[8]+d[1]*d[7]*d[8]+d[3]*d[4]*d[9]-d[0]*d[7]*d[9]
|
||||
-d[1]*d[4]*d[11]+d[0]*d[5]*d[11];
|
||||
n(3) = d[2]*d[5]*d[8]-d[1]*d[6]*d[8]-d[2]*d[4]*d[9]+d[0]*d[6]*d[9]
|
||||
+d[1]*d[4]*d[10]-d[0]*d[5]*d[10];
|
||||
}
|
||||
}
|
||||
|
||||
void MultAAt(const DenseMatrix &a, DenseMatrix &aat)
|
||||
|
||||
@@ -3513,6 +3513,7 @@ HypreSmoother::HypreSmoother() : Solver()
|
||||
omega = 1.0;
|
||||
poly_order = 2;
|
||||
poly_fraction = .3;
|
||||
poly_iter = 10;
|
||||
lambda = 0.5;
|
||||
mu = -0.5;
|
||||
taubin_iter = 40;
|
||||
|
||||
@@ -1049,6 +1049,8 @@ protected:
|
||||
real_t poly_fraction;
|
||||
/// Apply the polynomial smoother to A or D^{-1/2} A D^{-1/2}
|
||||
int poly_scale;
|
||||
/// Number of CG iterations to determine eigenvalue estimates, 0 means the max norm
|
||||
int poly_iter;
|
||||
|
||||
/// Taubin's lambda-mu method parameters
|
||||
real_t lambda;
|
||||
|
||||
+5
-1
@@ -30,6 +30,8 @@ set(SRCS
|
||||
vertex.cpp
|
||||
vtk.cpp
|
||||
wedge.cpp
|
||||
pentatope.cpp
|
||||
tesseract.cpp
|
||||
submesh/submesh.cpp
|
||||
submesh/submesh_utils.cpp
|
||||
submesh/transfermap.cpp
|
||||
@@ -57,11 +59,13 @@ set(HDRS
|
||||
vertex.hpp
|
||||
vtk.hpp
|
||||
wedge.hpp
|
||||
pentatope.hpp
|
||||
tesseract.hpp
|
||||
submesh/submesh.hpp
|
||||
submesh/submesh_utils.hpp
|
||||
submesh/transfer_category.hpp
|
||||
submesh/transfermap.hpp
|
||||
)
|
||||
)
|
||||
|
||||
if (MFEM_USE_MPI)
|
||||
list(APPEND SRCS
|
||||
|
||||
+16
-1
@@ -39,7 +39,8 @@ public:
|
||||
|
||||
/// Constants for the classes derived from Element.
|
||||
enum Type { POINT, SEGMENT, TRIANGLE, QUADRILATERAL,
|
||||
TETRAHEDRON, HEXAHEDRON, WEDGE, PYRAMID
|
||||
TETRAHEDRON, HEXAHEDRON, WEDGE, PYRAMID,
|
||||
PENTATOPE, TESSERACT
|
||||
};
|
||||
|
||||
/// Default element constructor.
|
||||
@@ -76,8 +77,22 @@ public:
|
||||
|
||||
virtual int GetNEdges() const = 0;
|
||||
|
||||
virtual int GetNPlanars() const
|
||||
{
|
||||
mfem_error ("Element::GetNPlanars(...)\n"
|
||||
" is not implemented for this class!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual const int *GetEdgeVertices(int) const = 0;
|
||||
|
||||
virtual const int *GetPlanarsVertices(int) const
|
||||
{
|
||||
mfem_error ("Element::GetPlanarsVertices(...)\n"
|
||||
" is not implemented for this class!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// @deprecated Use GetNFaces(void) and GetNFaceVertices(int) instead.
|
||||
MFEM_DEPRECATED virtual int GetNFaces(int &nFaceVertices) const = 0;
|
||||
|
||||
|
||||
+2214
-32
File diff suppressed because it is too large
Load Diff
+155
-1
@@ -70,6 +70,7 @@ protected:
|
||||
|
||||
int NumOfVertices, NumOfElements, NumOfBdrElements;
|
||||
int NumOfEdges, NumOfFaces;
|
||||
int NumOfPlanars;
|
||||
/** These variables store the number of Interior and Boundary faces. Calling
|
||||
fes->GetMesh()->GetNBE() doesn't return the expected value in 3D because
|
||||
periodic meshes in 3D have some of their faces marked as boundary for
|
||||
@@ -97,6 +98,13 @@ protected:
|
||||
Array<Vertex> vertices;
|
||||
Array<Element *> boundary;
|
||||
Array<Element *> faces;
|
||||
Array<Element *> planars; //only for 4d meshes
|
||||
|
||||
Array<bool> swappedFaces; //only for 4d meshes
|
||||
Array<bool> swappedBdr; //only for 4d meshes
|
||||
|
||||
// Flag to indicate if two neighbours are reflected neighbours (4D)
|
||||
bool is_reflected;
|
||||
|
||||
/** @brief This structure stores the low level information necessary to
|
||||
interpret the configuration of elements on a specific face. This
|
||||
@@ -226,10 +234,12 @@ protected:
|
||||
|
||||
Table *el_to_edge;
|
||||
Table *el_to_face;
|
||||
Table *el_to_planar; // for 4D
|
||||
Table *el_to_el;
|
||||
Array<int> be_to_face; // faces = vertices (1D), edges (2D), faces (3D)
|
||||
|
||||
Table *bel_to_edge; // for 3D only
|
||||
Table *bel_to_planar; // for 4D only
|
||||
|
||||
// Note that the following tables are owned by this class and should not be
|
||||
// deleted by the caller. Of these three tables, only face_edge and
|
||||
@@ -238,9 +248,13 @@ protected:
|
||||
mutable Table *face_edge; // Returned by GetFaceEdgeTable().
|
||||
mutable Table *edge_vertex; // Returned by GetEdgeVertexTable().
|
||||
|
||||
mutable Table *face_planar; // for 4D
|
||||
mutable Table *planar_edge; // for 4D
|
||||
|
||||
IsoparametricTransformation Transformation, Transformation2;
|
||||
IsoparametricTransformation BdrTransformation;
|
||||
IsoparametricTransformation FaceTransformation, EdgeTransformation;
|
||||
IsoparametricTransformation FaceTransformation, PlanarTransformation,
|
||||
EdgeTransformation;
|
||||
FaceElementTransformations FaceElemTr;
|
||||
|
||||
// refinement embeddings for forward compatibility with NCMesh
|
||||
@@ -273,6 +287,8 @@ public:
|
||||
typedef Geometry::Constants<Geometry::CUBE> hex_t;
|
||||
typedef Geometry::Constants<Geometry::PRISM> pri_t;
|
||||
typedef Geometry::Constants<Geometry::PYRAMID> pyr_t;
|
||||
typedef Geometry::Constants<Geometry::PENTATOPE> pent_t;
|
||||
typedef Geometry::Constants<Geometry::TESSERACT> tess_t;
|
||||
|
||||
enum Operation { NONE, REFINE, DEREFINE, REBALANCE };
|
||||
|
||||
@@ -355,6 +371,10 @@ protected:
|
||||
void GetEdgeOrdering(const DSTable &v_to_v, Array<int> &order);
|
||||
virtual void MarkTetMeshForRefinement(const DSTable &v_to_v);
|
||||
|
||||
// Removed 2025 November
|
||||
// virtual void MarkTetMeshForRefinement(DSTable &v_to_v);
|
||||
virtual void MakeReflectedPentMesh();
|
||||
|
||||
// Methods used to prepare and apply permutation of the mesh nodes assuming
|
||||
// that the mesh elements may be rotated (e.g. to mark triangle or tet edges
|
||||
// for refinement) between the two calls - PrepareNodeReorder() and
|
||||
@@ -365,6 +385,8 @@ protected:
|
||||
|
||||
STable3D *GetFacesTable();
|
||||
STable3D *GetElementToFaceTable(int ret_ftbl = 0);
|
||||
STable4D *GetElementToFaceTable4D(int ret_ftbl = 0);
|
||||
STable3D *GetElementToPlanarTable(int ret_ftbl = 0);
|
||||
|
||||
/** Red refinement. Element with index i is refined. The default
|
||||
red refinement for now is Uniform. */
|
||||
@@ -387,6 +409,9 @@ protected:
|
||||
/// Bisect a boundary triangle: boundary element with index @a i is bisected.
|
||||
void BdrBisection(int i, const HashTable<Hashed2> &);
|
||||
|
||||
void RedRefinementPentatope(int i, HashTable<Hashed2> & v_to_v);
|
||||
void RedRefinementBoundaryTet(int i, HashTable<Hashed2> & v_to_v);
|
||||
|
||||
/** Uniform Refinement. Element with index i is refined uniformly. */
|
||||
void UniformRefinement(int i, const DSTable &, int *, int *, int *);
|
||||
|
||||
@@ -476,6 +501,8 @@ protected:
|
||||
int i) const;
|
||||
void GetLocalQuadToPyrTransformation(IsoparametricTransformation &loc,
|
||||
int i) const;
|
||||
void GetLocalTetToPentTransformation(IsoparametricTransformation &loc,
|
||||
int i) const;
|
||||
|
||||
/** Used in GetFaceElementTransformations to account for the fact that a
|
||||
slave face occupies only a portion of its master face. */
|
||||
@@ -513,6 +540,8 @@ protected:
|
||||
/// Returns the orientation of "test" relative to "base"
|
||||
static int GetTetOrientation(const int *base, const int *test);
|
||||
|
||||
static int GetHexOrientation(const int * base, const int * test);
|
||||
|
||||
static void GetElementArrayEdgeTable(const Array<Element*> &elem_array,
|
||||
const DSTable &v_to_v,
|
||||
Table &el_to_edge);
|
||||
@@ -534,6 +563,15 @@ protected:
|
||||
|
||||
void AddQuadFaceElement (int lf, int gf, int el,
|
||||
int v0, int v1, int v2, int v3);
|
||||
|
||||
void AddTetrahedralFaceElement(int lf, int gf, int el,
|
||||
int v0, int v1, int v2, int v3);
|
||||
|
||||
void AddHexahedralFaceElement(int lf, int gf, int el,
|
||||
int v0, int v1, int v2, int v3,
|
||||
int v4, int v5, int v6, int v7);
|
||||
|
||||
|
||||
/** For a serial Mesh, return true if the face is interior. For a parallel
|
||||
ParMesh return true if the face is interior or shared. In parallel, this
|
||||
method only works if the face neighbor data is exchanged. */
|
||||
@@ -542,10 +580,14 @@ protected:
|
||||
return FaceIsInterior(FaceNo) || (faces_info[FaceNo].Elem2Inf >= 0);
|
||||
}
|
||||
|
||||
//swap first two entries of *a
|
||||
inline void Swap(int *a) const;
|
||||
|
||||
void FreeElement(Element *E);
|
||||
|
||||
void GenerateFaces();
|
||||
void GenerateNCFaceInfo();
|
||||
void GeneratePlanars();
|
||||
|
||||
/// Begin construction of a mesh
|
||||
void InitMesh(int Dim_, int spaceDim_, int NVert, int NElem, int NBdrElem);
|
||||
@@ -565,6 +607,16 @@ protected:
|
||||
std::string section_delimiter = "",
|
||||
const std::string &comments = "") const;
|
||||
|
||||
/** Creates mesh for the hyper-prism spatial_mesh x[0,st], divided into
|
||||
4*nt*spatial_mesh.NumElem pentatopes. */
|
||||
void Make4D(Mesh* spatial_mesh, int nt, Element::Type type, double st);
|
||||
|
||||
/** Creates mesh for the 4-parallelotope [0,sx]x[0,sy]x[0,sz]x[0,st], divided into
|
||||
nx*ny*nz*nt tesseracts if type=TESSERACT or into 24*nx*ny*nz*nt pentatopes if
|
||||
type=PENTATOPE. */
|
||||
void Make4D(int nx, int ny, int nz, int nt, Element::Type type, double sx,
|
||||
double sy, double sz, double st);
|
||||
|
||||
/// @brief Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz],
|
||||
/// divided into nx*ny*nz hexahedra if @a type = HEXAHEDRON or into
|
||||
/// 6*nx*ny*nz tetrahedrons if @a type = TETRAHEDRON.
|
||||
@@ -930,6 +982,11 @@ public:
|
||||
/// 8 vertices @a vi.
|
||||
void AddHexAsPyramids(const int *vi, int attr = 1);
|
||||
|
||||
int AddPent(const int *vi, int attr = 1);
|
||||
int AddTes(const int *vi, int attr = 1);
|
||||
void AddTesAsPentatopes(const int *vi, int attr = 1);
|
||||
void AddHyperPrismAsPentatopes(const int *vi, int attr = 1);
|
||||
|
||||
/// @brief Adds 24 tetrahedrons to the mesh by splitting a hexahedron.
|
||||
///
|
||||
/// @a vi are the 8 vertices of the hexahedron, @a hex_face_verts has the
|
||||
@@ -971,6 +1028,10 @@ public:
|
||||
int AddBdrQuad(int v1, int v2, int v3, int v4, int attr = 1);
|
||||
int AddBdrQuad(const int *vi, int attr = 1);
|
||||
void AddBdrQuadAsTriangles(const int *vi, int attr = 1);
|
||||
int AddBdrTet(const int *vi, int attr = 1);
|
||||
int AddBdrHex(const int *vi, int attr = 1);
|
||||
void AddBdrHexAsTets(const int *vi, int perm, int attr = 1);
|
||||
void AddBdrPrismAsTets(const int *vi, int attr = 1);
|
||||
|
||||
int AddBdrPoint(int v, int attr = 1);
|
||||
|
||||
@@ -990,6 +1051,8 @@ public:
|
||||
/// Finalize the construction of a hexahedral Mesh.
|
||||
void FinalizeHexMesh(int generate_edges = 0, int refine = 0,
|
||||
bool fix_orientation = true);
|
||||
void FinalizeTesMesh(int generate_edges = 0, int refine = 0,
|
||||
bool fix_orientation = true);
|
||||
/// Finalize the construction of any type of Mesh.
|
||||
/** This method calls FinalizeTopology() and Finalize(). */
|
||||
void FinalizeMesh(int refine = 0, bool fix_orientation = true);
|
||||
@@ -1155,6 +1218,32 @@ public:
|
||||
|
||||
/// @}
|
||||
|
||||
/** Creates mesh for the hyper-prism spatial_mesh x[0,st], divided into
|
||||
4*nt*spatial_mesh.NumElem pentatopes. If refine = true (default) the
|
||||
mesh is made conforming for the bisection algorithm, i.e., each
|
||||
pentatope is again subdivided into 60 sub-pentatopes. */
|
||||
Mesh(Mesh* spatial_mesh, int nt, Element::Type type, bool refine = true, double st = 1.0)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
|
||||
Make4D(spatial_mesh, nt, type, st);
|
||||
Finalize(refine, true);
|
||||
}
|
||||
|
||||
/** Creates mesh for the 4-parallelotope [0,sx]x[0,sy]x[0,sz]x[0,st], divided into
|
||||
nx*ny*nz*nt tesseracts if type=TESSERACT or into 24*nx*ny*nz*nt pentatopes if
|
||||
type=PENTATOPE. If refine = true (default) the mesh is made conforming
|
||||
for the bisection algorithm, i.e., each pentatope is again subdivided
|
||||
into 60 sub-pentatopes. */
|
||||
Mesh(int nx, int ny, int nz, int nt, Element::Type type, bool refine = true,
|
||||
double sx = 1.0, double sy = 1.0, double sz = 1.0, double st = 1.0)
|
||||
: attribute_sets(attributes), bdr_attribute_sets(bdr_attributes)
|
||||
{
|
||||
Make4D(nx, ny, nz, nt, type, sx, sy, sz, st);
|
||||
Finalize(refine,true);
|
||||
}
|
||||
|
||||
|
||||
/// @name Information about the mesh as a whole
|
||||
/// @{
|
||||
|
||||
@@ -1171,6 +1260,9 @@ public:
|
||||
inline int EulerNumber2D() const
|
||||
{ return NumOfVertices - NumOfEdges + NumOfElements; }
|
||||
|
||||
inline int EulerNumber4D() const
|
||||
{ return NumOfVertices - NumOfEdges + NumOfPlanars - NumOfFaces + NumOfElements;}
|
||||
|
||||
/** @brief Get the mesh generator/type.
|
||||
|
||||
The purpose of this is to be able to quickly tell what type of elements
|
||||
@@ -1236,6 +1328,9 @@ public:
|
||||
/// Return the number of faces in a 3D mesh.
|
||||
inline int GetNFaces() const { return NumOfFaces; }
|
||||
|
||||
/// Return the number of planars in a 4D mesh.
|
||||
inline int GetNPlanars() const { return NumOfPlanars; }
|
||||
|
||||
/// Return the number of faces (3D), edges (2D) or vertices (1D).
|
||||
int GetNumFaces() const;
|
||||
|
||||
@@ -1291,6 +1386,11 @@ public:
|
||||
/// the Element object itself should not be deleted by the caller.
|
||||
Element *GetElement(int i) { return elements[i]; }
|
||||
|
||||
bool getSwappedElementInfo(int i) const { return false; }
|
||||
bool getSwappedFaceElementInfo(int i) const { return swappedFaces[i]; }
|
||||
bool getSwappedBdrElementInfo(int i) const { return swappedBdr[i]; }
|
||||
|
||||
|
||||
/// @brief Return pointer to the i'th boundary element object
|
||||
///
|
||||
/// The index @a i should be in the range [0, Mesh::GetNBE())
|
||||
@@ -1370,6 +1470,14 @@ public:
|
||||
/// Return the Geometry::Type associated with face @a i.
|
||||
Geometry::Type GetFaceGeometry(int i) const;
|
||||
|
||||
const Element *GetPlanar(int i) const
|
||||
{ return planars[i]; }
|
||||
|
||||
Geometry::Type GetPlanarBaseGeometry(int i) const
|
||||
{
|
||||
return planars[i]->GetGeometryType();
|
||||
}
|
||||
|
||||
Geometry::Type GetElementGeometry(int i) const
|
||||
{
|
||||
return elements[i]->GetGeometryType();
|
||||
@@ -1380,6 +1488,8 @@ public:
|
||||
return boundary[i]->GetGeometryType();
|
||||
}
|
||||
|
||||
Geometry::Type GetBdrPlanarBaseGeometry(int i) const;
|
||||
|
||||
/// Deprecated in favor of Mesh::GetFaceGeometry
|
||||
MFEM_DEPRECATED Geometry::Type GetFaceBaseGeometry(int i) const
|
||||
{ return GetFaceGeometry(i); }
|
||||
@@ -1450,10 +1560,21 @@ public:
|
||||
/// Return the indices and the orientations of all edges of bdr element i.
|
||||
void GetBdrElementEdges(int i, Array<int> &edges, Array<int> &cor) const;
|
||||
|
||||
/// Return the indices and the orientations of all planars of element i.
|
||||
void GetBdrElementPlanars(int i, Array<int> &pls, Array<int> &cor) const;
|
||||
|
||||
/** Return the indices and the orientations of all edges of face i.
|
||||
Works for both 2D (face=edge) and 3D faces. */
|
||||
void GetFaceEdges(int i, Array<int> &edges, Array<int> &o) const;
|
||||
|
||||
/** Return the indices and the orientations of all edges of planar i.
|
||||
Works only in 4D. */
|
||||
void GetPlanarEdges(int i, Array<int> &, Array<int> &) const;
|
||||
|
||||
/** Return the indices and the orientations of all planars of face i.
|
||||
Works for 4D faces. */
|
||||
void GetFacePlanars(int i, Array<int> &, Array<int> &) const;
|
||||
|
||||
/// Returns the indices of the vertices of face i.
|
||||
void GetFaceVertices(int i, Array<int> &vert) const
|
||||
{
|
||||
@@ -1470,6 +1591,9 @@ public:
|
||||
/// Returns the indices of the vertices of edge i.
|
||||
void GetEdgeVertices(int i, Array<int> &vert) const;
|
||||
|
||||
/// Returns the indices of the vertices of planar i.
|
||||
void GetPlanVertices(int i, Array<int> &vert) const;
|
||||
|
||||
/// Return the indices and the orientations of all faces of element i.
|
||||
void GetElementFaces(int i, Array<int> &faces, Array<int> &ori) const;
|
||||
|
||||
@@ -1485,6 +1609,9 @@ public:
|
||||
GetElementEdges/GetBdrElementEdges. */
|
||||
void GetBdrElementFace(int i, int *f, int *o) const;
|
||||
|
||||
/// Return the indices and the orientations of all planars of element i.
|
||||
void GetElementPlanars(int i, Array<int> &pls, Array<int> &cor) const;
|
||||
|
||||
/** @brief For the given boundary element, bdr_el, return its adjacent
|
||||
element and its info, i.e. 64*local_bdr_index+bdr_orientation.
|
||||
|
||||
@@ -1553,6 +1680,15 @@ public:
|
||||
/// @note The returned object should NOT be deleted by the caller.
|
||||
Table *GetEdgeVertexTable() const;
|
||||
|
||||
Table *GetFacePlanarTable() const;
|
||||
|
||||
/// Returns the planar-to-edge Table (4D)
|
||||
///
|
||||
/// @note The returned object should NOT be deleted by the caller.
|
||||
Table *GetPlanarEdgeTable() const;
|
||||
|
||||
|
||||
|
||||
/** Return vertex to vertex table. The connections stored in the table
|
||||
are from smaller to bigger vertex index, i.e. if i<j and (i, j) is
|
||||
in the table, then (j, i) is not stored.
|
||||
@@ -1682,6 +1818,13 @@ public:
|
||||
/// Also, the returned object should NOT be deleted by the caller.
|
||||
ElementTransformation *GetEdgeTransformation(int EdgeNo);
|
||||
|
||||
/** Returns the transformation defining the given planar element.
|
||||
The transformation is stored in a user-defined variable. */
|
||||
void GetPlanarTransformation(int i, IsoparametricTransformation *PlTr);
|
||||
|
||||
/// Returns the transformation defining the given face element
|
||||
ElementTransformation *GetPlanarTransformation(int PlanarNo);
|
||||
|
||||
/// Returns (a pointer to an object containing) the following data:
|
||||
///
|
||||
/// 1) Elem1No - the index of the first element that contains this face this
|
||||
@@ -2014,6 +2157,10 @@ public:
|
||||
|
||||
/// @}
|
||||
|
||||
const Table &ElementToPlanTable() const;
|
||||
|
||||
void ReplaceBoundaryFromFaces();
|
||||
|
||||
/// @name Methods related to mesh partitioning
|
||||
/// @{
|
||||
|
||||
@@ -2917,6 +3064,13 @@ Mesh *Extrude1D(Mesh *mesh, const int ny, const real_t sy,
|
||||
/// Extrude a 2D mesh
|
||||
Mesh *Extrude2D(Mesh *mesh, const int nz, const real_t sz);
|
||||
|
||||
inline void Mesh::Swap(int *a) const
|
||||
{
|
||||
int temp = a[0];
|
||||
a[0] = a[1];
|
||||
a[1] = temp;
|
||||
}
|
||||
|
||||
// shift cyclically 3 integers left-to-right
|
||||
inline void ShiftRight(int &a, int &b, int &c)
|
||||
{
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "quadrilateral.hpp"
|
||||
#include "hexahedron.hpp"
|
||||
#include "tetrahedron.hpp"
|
||||
#include "pentatope.hpp"
|
||||
#include "tesseract.hpp"
|
||||
#include "ncmesh.hpp"
|
||||
#include "mesh.hpp"
|
||||
#include "mesh_operators.hpp"
|
||||
|
||||
+1
-1
@@ -2452,7 +2452,7 @@ const real_t* NCMesh::CalcVertexPos(int node) const
|
||||
const real_t* pos1 = CalcVertexPos(nd.p1);
|
||||
const real_t* pos2 = CalcVertexPos(nd.p2);
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int i = 0; i < Dim; i++) // TODO check if any memory violations occur
|
||||
{
|
||||
tv.pos[i] = (pos1[i] + pos2[i]) * 0.5;
|
||||
}
|
||||
|
||||
+9
-4
@@ -935,7 +935,7 @@ protected: // implementation
|
||||
struct Point
|
||||
{
|
||||
int dim;
|
||||
real_t coord[3];
|
||||
real_t coord[4];
|
||||
|
||||
Point() { dim = 0; }
|
||||
|
||||
@@ -950,6 +950,9 @@ protected: // implementation
|
||||
Point(real_t x, real_t y, real_t z)
|
||||
{ dim = 3; coord[0] = x; coord[1] = y; coord[2] = z; }
|
||||
|
||||
Point(double x, double y, double z, double t)
|
||||
{ dim = 4; coord[0] = x; coord[1] = y; coord[2] = z; coord[3] = t; }
|
||||
|
||||
Point(const Point& p0, const Point& p1)
|
||||
{
|
||||
dim = p0.dim;
|
||||
@@ -1010,13 +1013,14 @@ protected: // implementation
|
||||
PointMatrix(const Point& p0, const Point& p1, const Point& p2, const Point& p3)
|
||||
{ np = 4; points[0] = p0; points[1] = p1; points[2] = p2; points[3] = p3; }
|
||||
|
||||
PointMatrix(const Point& p0, const Point& p1, const Point& p2,
|
||||
const Point& p3, const Point& p4)
|
||||
PointMatrix(const Point& p0, const Point& p1, const Point& p2, const Point& p3,
|
||||
const Point& p4)
|
||||
{
|
||||
np = 5;
|
||||
points[0] = p0; points[1] = p1; points[2] = p2;
|
||||
points[3] = p3; points[4] = p4;
|
||||
}
|
||||
|
||||
PointMatrix(const Point& p0, const Point& p1, const Point& p2,
|
||||
const Point& p3, const Point& p4, const Point& p5)
|
||||
{
|
||||
@@ -1024,6 +1028,7 @@ protected: // implementation
|
||||
points[0] = p0; points[1] = p1; points[2] = p2;
|
||||
points[3] = p3; points[4] = p4; points[5] = p5;
|
||||
}
|
||||
|
||||
PointMatrix(const Point& p0, const Point& p1, const Point& p2,
|
||||
const Point& p3, const Point& p4, const Point& p5,
|
||||
const Point& p6, const Point& p7)
|
||||
@@ -1072,7 +1077,7 @@ protected: // implementation
|
||||
struct TmpVertex
|
||||
{
|
||||
bool valid, visited;
|
||||
real_t pos[3];
|
||||
real_t pos[4];
|
||||
TmpVertex() : valid(false), visited(false) {}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.googlecode.com.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
// Implementation of class Pentatope
|
||||
|
||||
|
||||
#include "mesh_headers.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
|
||||
Pentatope::Pentatope(const int *ind, int attr, unsigned char f)
|
||||
: Element(Geometry::PENTATOPE)
|
||||
{
|
||||
attribute = attr;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
indices[i] = ind[i];
|
||||
}
|
||||
|
||||
transform = 0;
|
||||
flag = f;
|
||||
}
|
||||
|
||||
Pentatope::Pentatope(int ind1, int ind2, int ind3, int ind4, int ind5, int attr, unsigned char f)
|
||||
: Element(Geometry::PENTATOPE)
|
||||
{
|
||||
attribute = attr;
|
||||
indices[0] = ind1;
|
||||
indices[1] = ind2;
|
||||
indices[2] = ind3;
|
||||
indices[3] = ind4;
|
||||
indices[4] = ind5;
|
||||
|
||||
transform = 0;
|
||||
flag = f;
|
||||
}
|
||||
|
||||
// Cancelled and added new version at the end of the file (2025 November)
|
||||
// void Pentatope::GetVertices(Array<int> &v) const
|
||||
// {
|
||||
// v.SetSize(5);
|
||||
// for (int i = 0; i < 5; i++)
|
||||
// {
|
||||
// v[i] = indices[i];
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void Pentatope::SetVertices(const int *ind)
|
||||
// {
|
||||
// for (int i = 0; i < 5; i++)
|
||||
// {
|
||||
// indices[i] = ind[i];
|
||||
// }
|
||||
// }
|
||||
|
||||
//static method
|
||||
void Pentatope::GetPointMatrix(unsigned transform, DenseMatrix &pm) // FIXME for bisection
|
||||
{
|
||||
double* a = &pm(0,0), *b = &pm(0,1), *c = &pm(0,2), *d = &pm(0,3), *e = &pm(0,
|
||||
4);
|
||||
|
||||
// initialize to identity
|
||||
a[0] = 0.0, a[1] = 0.0, a[2] = 0.0, a[3] = 0.0;
|
||||
b[0] = 1.0, b[1] = 0.0, b[2] = 0.0, b[3] = 0.0;
|
||||
c[0] = 0.0, c[1] = 1.0, c[2] = 0.0, c[3] = 0.0;
|
||||
d[0] = 0.0, d[1] = 0.0, d[2] = 1.0, d[3] = 0.0;
|
||||
e[0] = 0.0, e[1] = 0.0, e[2] = 0.0, e[3] = 1.0;
|
||||
|
||||
int chain[12], n = 0;
|
||||
bool swapped[12];
|
||||
while (transform)
|
||||
{
|
||||
chain[n++] = (transform & 15) - 1;
|
||||
swapped[n-1] = ( (transform & 31) / 16 == 1);
|
||||
transform >>= 5;
|
||||
}
|
||||
|
||||
#define ASGN(a, b) (a[0] = b[0], a[1] = b[1], a[2] = b[2], a[3] = b[3])
|
||||
#define SWAP(a, b) for (int i = 0; i < 4; i++) { std::swap(a[i], b[i]); }
|
||||
#define AVG(a, b, c) for (int i = 0; i < 4; i++) { a[i] = (b[i]+c[i])*0.5; }
|
||||
|
||||
double f[4];
|
||||
while (n)
|
||||
{
|
||||
switch (chain[--n])
|
||||
{
|
||||
case 0:
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
AVG(f,a,e); ASGN(e,d); ASGN(d,c); ASGN(c,b); ASGN(b,f);
|
||||
if (!swapped[n]) SWAP(a,e);
|
||||
break; // chilTesseractd 1, tag 0 parent
|
||||
case 1:
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
AVG(f,a,e); ASGN(e,d); ASGN(d,c); ASGN(c,b); ASGN(b,f);
|
||||
if (!swapped[n]) SWAP(a,e);
|
||||
break; // child 1, tag 1 parent
|
||||
case 2:
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
AVG(f,a,e); ASGN(e,d); ASGN(d,c); ASGN(c,b); ASGN(b,f);
|
||||
if (!swapped[n]) SWAP(a,e);
|
||||
break; // child 1, tag 2 parent
|
||||
case 3:
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
AVG(f,a,e); ASGN(e,d); ASGN(d,c); ASGN(c,b); ASGN(b,f);
|
||||
if (!swapped[n]) SWAP(a,e);
|
||||
break; // child 1, tag 3 parent
|
||||
case 10:
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
AVG(f,a,e); ASGN(a,e); ASGN(e,b); SWAP(c,d); ASGN(b,f);
|
||||
if (!swapped[n]) SWAP(a,e);
|
||||
break; // child 2, tag 0 parent
|
||||
case 11:
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
AVG(f,a,e); ASGN(a,e); ASGN(e,c); ASGN(c,b); ASGN(b,f);
|
||||
if (!swapped[n]) SWAP(a,e);
|
||||
break; // child 2, tag 1 parent
|
||||
case 12:
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
AVG(f,a,e); ASGN(a,e); ASGN(e,d); ASGN(d,c); ASGN(c,b); ASGN(b,f);
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
break; // child 2, tag 2 parent
|
||||
case 13:
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
AVG(f,a,e); ASGN(a,e); ASGN(e,d); ASGN(d,c); ASGN(c,b); ASGN(b,f);
|
||||
if (swapped[n]) SWAP(a,e);
|
||||
break; // child 2, tag 3 parent
|
||||
#if 0 // Freudenthal
|
||||
case 0 : AVG(b,a,b); AVG(c,a,c); AVG(d,a,d); AVG(e,a,e); break; // 1,6,7,8,9
|
||||
case 1 : AVG(a,a,b); AVG(c,b,c); AVG(d,b,d); AVG(e,b,e); break; // 6,2,10,11,12
|
||||
case 2 : AVG(a,a,c); AVG(b,b,c); AVG(d,c,d); AVG(e,c,e); break; // 7,10,3,13,14
|
||||
case 3 : AVG(a,a,d); AVG(b,b,d); AVG(c,c,d); AVG(e,d,e); break; // 8,11,13,4,15
|
||||
case 4 : AVG(a,a,e); AVG(b,b,e); AVG(c,c,e); AVG(d,d,e); break; // 9,12,14,15,5
|
||||
case 5 : ASGN(f,e); AVG(e,d,e); AVG(d,c,d); ASGN(g,b); AVG(c,b,c); AVG(b,a,f);
|
||||
AVG(a,a,g); break; // 6,9,10,13,15
|
||||
case 6 : ASGN(f,a); AVG(a,a,b); AVG(b,f,d); ASGN(g,c); AVG(c,f,e); AVG(e,d,e);
|
||||
AVG(d,g,d); break; // 6,8,9,13,15
|
||||
case 7 : ASGN(f,e); AVG(e,d,e); AVG(d,b,d); ASGN(g,c); AVG(c,b,c); AVG(b,a,f);
|
||||
AVG(a,a,g); break; // 7,9,10,11,13
|
||||
case 8 : ASGN(f,a); AVG(a,a,b); AVG(b,f,c); ASGN(g,e); AVG(e,c,d); AVG(c,f,d);
|
||||
AVG(d,f,g); break; // 6,7,8,9,13
|
||||
case 9 : ASGN(f,e); AVG(a,a,e); AVG(e,f,d); ASGN(g,c); AVG(b,b,c); AVG(c,c,d);
|
||||
AVG(d,f,g); break; // 9,10,13,14,15
|
||||
case 10: ASGN(f,a); AVG(a,a,b); AVG(c,b,c); ASGN(g,e); AVG(e,d,e); AVG(d,b,g);
|
||||
AVG(b,f,g); break; // 6,9,10,12,15
|
||||
case 11: ASGN(f,d); AVG(d,c,d); AVG(e,d,e); ASGN(g,a); AVG(a,a,b); AVG(c,b,f);
|
||||
AVG(b,g,f); break; // 6,8,11,13,15
|
||||
case 12: ASGN(f,b); AVG(a,a,b); AVG(b,b,c); ASGN(g,e); AVG(e,d,e); AVG(c,f,d);
|
||||
AVG(d,f,g); break; // 6,10,11,12,15
|
||||
case 13: ASGN(f,c); AVG(c,a,e); AVG(e,c,d); ASGN(g,a); AVG(a,a,b); AVG(d,b,f);
|
||||
AVG(b,f,g); break; // 6,7,9,10,13
|
||||
case 14: ASGN(f,b); AVG(b,b,c); AVG(a,a,e); ASGN(g,e); AVG(e,d,e); AVG(d,c,g);
|
||||
AVG(c,f,g); break; // 9,10,12,14,15
|
||||
case 15: ASGN(f,d); AVG(d,c,d); AVG(a,a,b); ASGN(g,b); AVG(b,b,c); AVG(e,f,e);
|
||||
AVG(c,g,f); break; // 6,10,11,13,15
|
||||
#endif
|
||||
default:
|
||||
MFEM_ABORT("Invalid transform.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Element *Pentatope::Duplicate(Mesh *m) const
|
||||
{
|
||||
Pentatope *pent = new Pentatope;
|
||||
pent->SetVertices(indices);
|
||||
pent->SetAttribute(attribute);
|
||||
pent->SetFlag(flag);
|
||||
return pent;
|
||||
}
|
||||
|
||||
int Pentatope::NeedRefinement(HashTable<Hashed2> &v_to_v) const
|
||||
{
|
||||
if (v_to_v.FindId(indices[0], indices[1]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[1], indices[2]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[2], indices[0]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[0], indices[3]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[1], indices[3]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[2], indices[3]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[0], indices[4]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[1], indices[4]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[2], indices[4]) != -1) { return 1; }
|
||||
if (v_to_v.FindId(indices[4], indices[3]) != -1) { return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Pentatope::CreateFlag(char t, bool swap)
|
||||
{
|
||||
flag = t;
|
||||
flag <<= 1;
|
||||
flag |= swap;
|
||||
}
|
||||
|
||||
void Pentatope::ParseFlag(char& t, bool& swap)
|
||||
{
|
||||
unsigned char f = flag;
|
||||
|
||||
swap = (f & 1);
|
||||
f >>= 1;
|
||||
t = (f & 3);
|
||||
}
|
||||
|
||||
void Pentatope::GetFace(int fi, int *fv)
|
||||
{
|
||||
// const int faces[5][4] = { {0, 1, 2, 3}, {0, 1, 2, 4},
|
||||
// {0, 1, 3, 4}, {0, 2, 3, 4},
|
||||
// {1, 2, 3, 4}};
|
||||
const int *v = geom_p::FaceVert[fi];
|
||||
for (int k = 0; k < 4; ++k)
|
||||
{
|
||||
fv[k] = indices[v[k]];
|
||||
}
|
||||
|
||||
// if (fi % 2 == 1)
|
||||
// std::swap(fv[1], fv[2]);
|
||||
}
|
||||
|
||||
void Pentatope::GetVertices(Array<int> &v) const
|
||||
{
|
||||
v.SetSize(5);
|
||||
std::copy(indices, indices + 5, v.begin());
|
||||
}
|
||||
|
||||
void Pentatope::SetVertices(const Array<int> &v)
|
||||
{
|
||||
MFEM_ASSERT(v.Size() == 5, "!");
|
||||
std::copy(v.begin(), v.end(), indices);
|
||||
}
|
||||
|
||||
void Pentatope::SetVertices(const int *ind)
|
||||
{
|
||||
std::copy(ind, ind + 5, indices);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.googlecode.com.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
|
||||
#ifndef MFEM_PENTATOPE
|
||||
#define MFEM_PENTATOPE
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "../fem/fe.hpp"
|
||||
#include "element.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Data type pentatope element
|
||||
class Pentatope : public Element
|
||||
{
|
||||
protected:
|
||||
int indices[5];
|
||||
|
||||
unsigned transform;
|
||||
|
||||
/* Flag holds currently
|
||||
* One bit indicating if the element has been swapped.
|
||||
* Two bits indicating the tag of the simplex (0, 1, 2, 3)
|
||||
*/
|
||||
unsigned char flag;
|
||||
|
||||
public:
|
||||
|
||||
typedef Geometry::Constants<Geometry::PENTATOPE> geom_p;
|
||||
|
||||
Pentatope() : Element(Geometry::PENTATOPE) { transform = 0; flag = 0;};
|
||||
|
||||
/// Constructs pentatope by specifying the indices and the attribute.
|
||||
Pentatope(const int *ind, int attr = 1, unsigned char type = 0);
|
||||
|
||||
/// Constructs pentatope by specifying the indices and the attribute.
|
||||
Pentatope(int ind1, int ind2, int ind3, int ind4, int ind5, int attr = 1, unsigned char type = 0);
|
||||
|
||||
|
||||
virtual int GetRefinementFlag()
|
||||
{ MFEM_ABORT("PENTATOPE:: GetRefinementFlag not implemented"); return 0; }
|
||||
|
||||
|
||||
/// Return 1 if the element needs refinement in order to get conforming mesh.
|
||||
virtual int NeedRefinement(HashTable<Hashed2> &v_to_v) const;
|
||||
|
||||
/// Mark the longest edge by assuming/changing the order of the vertices.
|
||||
virtual void MarkEdge(DenseMatrix &pmat)
|
||||
{ MFEM_ABORT("PENTATOPE:: MarkEdge not implemented"); }
|
||||
|
||||
/** Reorder the vertices so that the longest edge is from vertex 0
|
||||
to vertex 1. If called it should be once from the mesh constructor,
|
||||
because the order may be used later for setting the edges. **/
|
||||
virtual void MarkEdge(const DSTable &v_to_v, const int *length)
|
||||
{ MFEM_ABORT("PENTATOPE:: MarkEdge not implemented"); }
|
||||
|
||||
virtual void GetFace(int fi, int *fv);
|
||||
|
||||
/// Return element's type.
|
||||
virtual Type GetType() const { return Element::PENTATOPE; }
|
||||
|
||||
virtual void CreateFlag(char t, bool swap);
|
||||
virtual void ParseFlag(char &t, bool &swap);
|
||||
|
||||
virtual void SetFlag(const unsigned char t) { flag = t; }
|
||||
|
||||
/// Return flag of element.
|
||||
virtual unsigned char GetFlag() const { return flag; }
|
||||
|
||||
// Cancelled and added new version at the end of the file (2025 November)
|
||||
// /// Set the vertices according to the given input.
|
||||
// virtual void SetVertices(const int *ind);
|
||||
//
|
||||
// /// Returns the indices of the element's vertices.
|
||||
// virtual void GetVertices(Array<int> &v) const;
|
||||
//
|
||||
// virtual int *GetVertices() { return indices; }
|
||||
|
||||
virtual int GetNVertices() const { return 5; }
|
||||
|
||||
virtual int GetNEdges() const { return 10; }
|
||||
|
||||
virtual int GetNPlanars() const { return 10; }
|
||||
|
||||
virtual const int *GetEdgeVertices(int ei) const { return (geom_p::Edges[ei]); }
|
||||
|
||||
virtual const int *GetPlanarsVertices(int pi) const { return (geom_p::PlanarVert[pi]); }
|
||||
|
||||
MFEM_DEPRECATED virtual int GetNFaces(int &nFaceVertices) const
|
||||
{ nFaceVertices = 4; return 5; }
|
||||
|
||||
virtual int GetNFaces() const { return 5; };
|
||||
|
||||
virtual int GetNFaceVertices(int fi) const { return 4; };
|
||||
|
||||
virtual const int *GetFaceVertices(int fi) const
|
||||
{ return geom_p::FaceVert[fi]; }
|
||||
|
||||
/// Calculate point matrix corresponding to a chain of transformations.
|
||||
static void GetPointMatrix(unsigned transform, DenseMatrix &pm);
|
||||
|
||||
virtual void ResetTransform(int tr) { transform = tr; }
|
||||
virtual unsigned GetTransform() const { return transform; }
|
||||
|
||||
virtual void PushTransform(int tr)
|
||||
{ transform = (transform << 5) | (tr + 1); }
|
||||
|
||||
virtual Element *Duplicate(Mesh *m) const;
|
||||
|
||||
/// Get the indices defining the vertices.
|
||||
void GetVertices(Array<int> &v) const override;
|
||||
|
||||
/// Set the indices defining the vertices.
|
||||
void SetVertices(const Array<int> &v) override;
|
||||
|
||||
/// @note The returned array should NOT be deleted by the caller.
|
||||
int * GetVertices () override { return indices; }
|
||||
|
||||
/// Set the indices defining the vertices.
|
||||
void SetVertices(const int *ind) override;
|
||||
|
||||
virtual ~Pentatope() { }
|
||||
|
||||
};
|
||||
|
||||
extern MFEM_EXPORT Linear4DFiniteElement PentatopeFE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
+1729
-43
File diff suppressed because it is too large
Load Diff
+64
-1
@@ -63,26 +63,48 @@ protected:
|
||||
void Set(int v0, int v1, int v2, int v3)
|
||||
{ v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; }
|
||||
void Set(const int *w)
|
||||
{ v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; v[3] = w[3]; }
|
||||
{ v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; v[3] = w[3];}
|
||||
};
|
||||
|
||||
struct Vert4_tag
|
||||
{
|
||||
int v[4];
|
||||
char tag;
|
||||
|
||||
Vert4_tag() = default;
|
||||
Vert4_tag(int v0, int v1, int v2, int v3, char _tag = 0)
|
||||
{
|
||||
v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; tag = _tag;
|
||||
}
|
||||
void Set(int v0, int v1, int v2, int v3, char _tag = 0)
|
||||
{ v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; tag = _tag; }
|
||||
void Set(const int *w, char _tag = 0)
|
||||
{ v[0] = w[0]; v[1] = w[1]; v[2] = w[2]; v[3] = w[3]; tag = _tag; }
|
||||
};
|
||||
|
||||
Array<Element *> shared_edges;
|
||||
// shared face id 'i' is:
|
||||
// * triangle id 'i', if i < shared_trias.Size()
|
||||
// * quad id 'i-shared_trias.Size()', otherwise
|
||||
Array<Vert3> shared_trias;
|
||||
Array<Vert4> shared_quads;
|
||||
Array<Vert4_tag> shared_tetra;
|
||||
// Array<Element *> shared_planars;
|
||||
|
||||
/// Shared objects in each group.
|
||||
Table group_svert;
|
||||
Table group_sedge;
|
||||
Table group_stria; // contains shared triangle indices
|
||||
Table group_squad; // contains shared quadrilateral indices
|
||||
Table group_stetr;
|
||||
// Table group_splan;
|
||||
|
||||
/// Shared to local index mapping.
|
||||
Array<int> svert_lvert;
|
||||
Array<int> sedge_ledge;
|
||||
Array<int> splan_lplan;
|
||||
// sface ids: all triangles first, then all quads
|
||||
// in 4D, just all tetrahedra
|
||||
Array<int> sface_lface;
|
||||
|
||||
/// Table that maps from face neighbor element number, to the face numbers of
|
||||
@@ -122,6 +144,18 @@ protected:
|
||||
bool DecodeFaceSplittings(HashTable<Hashed2> &v_to_v, const int *v,
|
||||
const Array<unsigned> &codes, int &pos);
|
||||
|
||||
void GetFaceSplittings4D(const Vert4_tag &f, const HashTable<Hashed2> &v_to_v,
|
||||
const DSTable &edges, Array<unsigned> &codes);
|
||||
|
||||
bool DecodeFaceSplittings4D(HashTable<Hashed2> &v_to_v, const Vert4_tag &v,
|
||||
const Array<unsigned> &codes, int &pos);
|
||||
|
||||
void GetFaceSplittings4D_old(const Vert4_tag &f, const HashTable<Hashed2> &v_to_v,
|
||||
Array<unsigned> &codes);
|
||||
|
||||
bool DecodeFaceSplittings4D_old(HashTable<Hashed2> &v_to_v, const Vert4_tag &v,
|
||||
const Array<unsigned> &codes, int &pos);
|
||||
|
||||
// Given a completed FacesTable and SharedFacesTable, construct a table that
|
||||
// maps from face neighbor element number, to the set of faces of that
|
||||
// element. Store the resulting data in the member variable
|
||||
@@ -166,6 +200,9 @@ protected:
|
||||
/// Update the groups after tetrahedron refinement
|
||||
void RefineGroups(int old_nv, const HashTable<Hashed2> &v_to_v);
|
||||
|
||||
void RefineGroups4D(int old_nv, const HashTable<Hashed2> &v_to_v);
|
||||
void UniformRefineGroups4D_Freudenthal(int old_nv, const HashTable<Hashed2> &v_to_v);
|
||||
|
||||
void UniformRefineGroups2D(int old_nv);
|
||||
|
||||
// f2qf can be NULL if all faces are quads or there are no quad faces
|
||||
@@ -226,6 +263,9 @@ protected:
|
||||
Array<int>& face_group,
|
||||
ListOfIntegerSets& groups);
|
||||
|
||||
int FindSharedPlanars(const Mesh &mesh, const int* partition,
|
||||
Table* &plan_element, ListOfIntegerSets &groups);
|
||||
|
||||
int FindSharedEdges(const Mesh &mesh, const int* partition,
|
||||
Table* &edge_element, ListOfIntegerSets& groups);
|
||||
|
||||
@@ -236,6 +276,13 @@ protected:
|
||||
const Array<int>& face_group,
|
||||
int &nstria, int &nsquad);
|
||||
|
||||
void BuildFaceGroup4D(int ngroups, const Mesh &mesh,
|
||||
const Array<int>& face_group,
|
||||
int &nstetr, int &nshexa);
|
||||
|
||||
void BuildPlanarGroup(int ngroups, const Mesh &mesh,const Table& plan_element,
|
||||
int &nstria, int &nsquad);
|
||||
|
||||
void BuildEdgeGroup(int ngroups, const Table& edge_element);
|
||||
|
||||
void BuildVertexGroup(int ngroups, const Table& vert_element);
|
||||
@@ -246,6 +293,17 @@ protected:
|
||||
const Array<int> &face_group,
|
||||
const Array<int> &vert_global_local);
|
||||
|
||||
void BuildSharedFaceElems4D(int ntet_faces, int nhex_faces,
|
||||
const Mesh &mesh, int *partitioning,
|
||||
const STable4D *faces_tbl_4d,
|
||||
const Array<int> &face_group,
|
||||
const Array<int> &vert_global_local,
|
||||
const std::map<int,char> &vert_to_type);
|
||||
|
||||
void BuildSharedPlanarElems(int ntri_planars, int nquad_planars,
|
||||
const Mesh &mesh, const Array<int>& vert_global_local,
|
||||
const STable3D *planar_tbl, const Table* plan_element);
|
||||
|
||||
void BuildSharedEdgeElems(int nedges, Mesh &mesh,
|
||||
const Array<int> &vert_global_local,
|
||||
const Table *edge_element);
|
||||
@@ -447,12 +505,17 @@ public:
|
||||
int GroupNEdges(int group) const { return group_sedge.RowSize(group-1); }
|
||||
int GroupNTriangles(int group) const { return group_stria.RowSize(group-1); }
|
||||
int GroupNQuadrilaterals(int group) const { return group_squad.RowSize(group-1); }
|
||||
// int GroupNPlanars(int group) const { return group_splan.RowSize(group-1); }
|
||||
int GroupNTetrahedra(int group) const { return group_stetr.RowSize(group-1); }
|
||||
|
||||
int GroupVertex(int group, int i) const
|
||||
{ return svert_lvert[group_svert.GetRow(group-1)[i]]; }
|
||||
|
||||
void GroupEdge(int group, int i, int &edge, int &o) const;
|
||||
void GroupTriangle(int group, int i, int &face, int &o) const;
|
||||
void GroupQuadrilateral(int group, int i, int &face, int &o) const;
|
||||
void GroupTetrahedron(int group, int i, int &face, int &o) const;
|
||||
|
||||
///@}
|
||||
|
||||
/**
|
||||
|
||||
+3
-3
@@ -819,7 +819,7 @@ ParPumiMesh::ParPumiMesh(MPI_Comm comm, apf::Mesh2* apf_mesh,
|
||||
apf::Downward verts;
|
||||
apf_mesh->getDownward(ent,0,verts);
|
||||
|
||||
int *v, nv = 0;
|
||||
int *v = nullptr, nv = 0;
|
||||
apf::Mesh::Type ftype = apf_mesh->getType(ent);
|
||||
if (ftype == apf::Mesh::TRIANGLE)
|
||||
{
|
||||
@@ -890,9 +890,9 @@ GridFunctionPumi::GridFunctionPumi(Mesh* m, apf::Mesh2* PumiM,
|
||||
{
|
||||
int spDim = m->SpaceDimension();
|
||||
// Note: default BasisType for 'fec' is GaussLobatto.
|
||||
fec = new H1_FECollection(mesh_order, m->Dimension());
|
||||
fec_owned = new H1_FECollection(mesh_order, m->Dimension());
|
||||
int ordering = Ordering::byVDIM; // x1y1z1/x2y2z2/...
|
||||
fes = new FiniteElementSpace(m, fec, spDim, ordering);
|
||||
fes = new FiniteElementSpace(m, fec_owned, spDim, ordering);
|
||||
int data_size = fes->GetVSize();
|
||||
|
||||
// Read PUMI mesh data
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.googlecode.com.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
|
||||
#include "mesh_headers.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
const int Tesseract::edges[32][2] =
|
||||
{
|
||||
{0, 1}, {1, 2}, {3, 2}, {0, 3},
|
||||
{4, 5}, {5, 6}, {7, 6}, {4, 7},
|
||||
{0, 4}, {1, 5}, {2, 6}, {3, 7},
|
||||
{8, 9}, {9, 10}, {11, 10}, {8, 11},
|
||||
{12, 13}, {13, 14}, {15, 14}, {12, 15},
|
||||
{8, 12}, {9, 13}, {10, 14}, {11, 15},
|
||||
{0, 8}, {1, 9}, {2, 10}, {3, 11},
|
||||
{4, 12}, {5, 13}, {6, 14}, {7, 15}
|
||||
};
|
||||
|
||||
// same as Mesh::hex_faces
|
||||
const int Tesseract::faces[8][8] =
|
||||
{
|
||||
// {8,11,12,15,0,3,4,7}, //x bottom
|
||||
// {1,2,6,5,9,10,14,13}, //x top
|
||||
// {0,1,5,4,8,9,13,12}, //y bottom
|
||||
// {2,3,7,6,10,11,15,14}, //y top
|
||||
// {8,9,10,11,0,1,2,3}, // z bottom
|
||||
// {4,5,6,7,12,13,14,15}, //z top
|
||||
// {0,1,2,3,4,5,6,7}, //t botom
|
||||
// {12,13,14,15,8,9,10,11} //t top
|
||||
{8,11,15,12,0,3,7,4}, //x bottom
|
||||
{1,2,6,5,9,10,14,13}, //x top
|
||||
{0,1,5,4,8,9,13,12}, //y bottom
|
||||
{2,3,7,6,10,11,15,14}, //y top
|
||||
{8,9,10,11,0,1,2,3}, // z bottom
|
||||
{4,5,6,7,12,13,14,15}, //z top
|
||||
{0,1,2,3,4,5,6,7}, //t botom
|
||||
{12,13,14,15,8,9,10,11} //t top
|
||||
};
|
||||
|
||||
|
||||
Tesseract::Tesseract(const int *ind, int attr)
|
||||
: Element(Geometry::TESSERACT)
|
||||
{
|
||||
attribute = attr;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
indices[i] = ind[i];
|
||||
}
|
||||
}
|
||||
|
||||
Tesseract::Tesseract(int ind1, int ind2, int ind3, int ind4,
|
||||
int ind5, int ind6, int ind7, int ind8,
|
||||
int ind9, int ind10, int ind11, int ind12,
|
||||
int ind13, int ind14, int ind15, int ind16,
|
||||
int attr) : Element(Geometry::TESSERACT)
|
||||
{
|
||||
attribute = attr;
|
||||
indices[0] = ind1;
|
||||
indices[1] = ind2;
|
||||
indices[2] = ind3;
|
||||
indices[3] = ind4;
|
||||
indices[4] = ind5;
|
||||
indices[5] = ind6;
|
||||
indices[6] = ind7;
|
||||
indices[7] = ind8;
|
||||
indices[8] = ind9;
|
||||
indices[9] = ind10;
|
||||
indices[10] = ind11;
|
||||
indices[11] = ind12;
|
||||
indices[12] = ind13;
|
||||
indices[13] = ind14;
|
||||
indices[14] = ind15;
|
||||
indices[15] = ind16;
|
||||
}
|
||||
|
||||
// Cancelled and added new version at the end of the file (2025 November)
|
||||
/*void Tesseract::GetVertices(Array<int> &v) const
|
||||
{
|
||||
v.SetSize(16);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
v[i] = indices[i];
|
||||
}
|
||||
}*/
|
||||
|
||||
void Tesseract::GetVertices(Array<int> &v) const
|
||||
{
|
||||
v.SetSize(16);
|
||||
std::copy(indices, indices + 16, v.begin());
|
||||
}
|
||||
|
||||
void Tesseract::SetVertices(const Array<int> &v)
|
||||
{
|
||||
MFEM_ASSERT(v.Size() == 16, "!");
|
||||
std::copy(v.begin(), v.end(), indices);
|
||||
}
|
||||
|
||||
void Tesseract::SetVertices(const int *ind)
|
||||
{
|
||||
std::copy(ind, ind + 16, indices);
|
||||
}
|
||||
|
||||
QuadLinear4DFiniteElement TesseractFE;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
|
||||
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
|
||||
// reserved. See file COPYRIGHT for details.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability see http://mfem.googlecode.com.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the GNU Lesser General Public License (as published by the Free
|
||||
// Software Foundation) version 2.1 dated February 1999.
|
||||
|
||||
#ifndef MFEM_TESSERACT
|
||||
#define MFEM_TESSERACT
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "element.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Data type tesseract element
|
||||
class Tesseract : public Element
|
||||
{
|
||||
protected:
|
||||
int indices[16];
|
||||
|
||||
public:
|
||||
static const int edges[32][2];
|
||||
static const int faces[8][8]; // same as Mesh::tes_faces
|
||||
|
||||
Tesseract() : Element(Geometry::TESSERACT) { }
|
||||
|
||||
/// Constructs hexahedron by specifying the indices and the attribute.
|
||||
Tesseract(const int *ind, int attr = 1);
|
||||
|
||||
/// Constructs hexahedron by specifying the indices and the attribute.
|
||||
Tesseract(int ind1, int ind2, int ind3, int ind4,
|
||||
int ind5, int ind6, int ind7, int ind8,
|
||||
int ind9, int ind10, int ind11, int ind12,
|
||||
int ind13, int ind14, int ind15, int ind16, int attr = 1);
|
||||
|
||||
/// Return element's type
|
||||
Type GetType() const { return Element::TESSERACT; }
|
||||
|
||||
// Cancelled and added new version at the end of the file (2025 November)
|
||||
// /// Returns the indices of the element's vertices.
|
||||
// virtual void GetVertices(Array<int> &v) const;
|
||||
//
|
||||
// virtual int *GetVertices() { return indices; }
|
||||
|
||||
virtual int GetNVertices() const { return 16; }
|
||||
|
||||
virtual int GetNEdges() const { return 32; }
|
||||
|
||||
virtual int GetNFaces() const { return 8; }
|
||||
|
||||
virtual int GetNFaceVertices(int fi) const { return 8; }
|
||||
|
||||
virtual const int *GetEdgeVertices(int ei) const
|
||||
{ return edges[ei]; }
|
||||
|
||||
virtual int GetNFaces(int &nFaceVertices) const
|
||||
{ nFaceVertices = 8; return 8; }
|
||||
|
||||
virtual const int *GetFaceVertices(int fi) const
|
||||
{ return faces[fi]; }
|
||||
|
||||
virtual Element *Duplicate(Mesh *m) const
|
||||
{ return new Tesseract(indices, attribute); }
|
||||
|
||||
/// Get the indices defining the vertices.
|
||||
void GetVertices(Array<int> &v) const override;
|
||||
|
||||
/// Set the indices defining the vertices.
|
||||
void SetVertices(const Array<int> &v) override;
|
||||
|
||||
/// @note The returned array should NOT be deleted by the caller.
|
||||
int * GetVertices () override { return indices; }
|
||||
|
||||
/// Set the indices defining the vertices.
|
||||
void SetVertices(const int *ind) override;
|
||||
|
||||
virtual ~Tesseract() { }
|
||||
};
|
||||
|
||||
extern QuadLinear4DFiniteElement TesseractFE;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+7
-6
@@ -22,17 +22,18 @@ namespace mfem
|
||||
class Vertex
|
||||
{
|
||||
protected:
|
||||
real_t coord[3];
|
||||
real_t coord[4];
|
||||
|
||||
public:
|
||||
Vertex() = default;
|
||||
|
||||
// Trivial copy constructor and trivial copy assignment operator
|
||||
|
||||
Vertex(real_t *xx, int dim);
|
||||
Vertex(real_t x, real_t y) { coord[0] = x; coord[1] = y; coord[2] = 0.; }
|
||||
Vertex(real_t x, real_t y) { coord[0] = x; coord[1] = y; coord[2] = 0.; coord[3] = 0.;}
|
||||
Vertex(real_t x, real_t y, real_t z)
|
||||
{ coord[0] = x; coord[1] = y; coord[2] = z; }
|
||||
{ coord[0] = x; coord[1] = y; coord[2] = z; coord[3] = 0.;}
|
||||
Vertex(real_t x, real_t y, real_t z, real_t t)
|
||||
{ coord[0] = x; coord[1] = y; coord[2] = z; coord[3] = t;}
|
||||
|
||||
/// Returns pointer to the coordinates of the vertex.
|
||||
inline real_t * operator() () const { return (real_t*)coord; }
|
||||
@@ -45,8 +46,8 @@ public:
|
||||
|
||||
/// (DEPRECATED) Set the coordinates of the Vertex.
|
||||
/** @deprecated This old version of SetCoords is not always memory safe. */
|
||||
MFEM_DEPRECATED void SetCoords(const real_t *p)
|
||||
{ coord[0] = p[0]; coord[1] = p[1]; coord[2] = p[2]; }
|
||||
MFEM_DEPRECATED void SetCoords(const double *p)
|
||||
{ coord[0] = p[0]; coord[1] = p[1]; coord[2] = p[2]; coord[3] = p[3]; }
|
||||
|
||||
/// Sets vertex location based on given point p
|
||||
void SetCoords(int dim, const real_t *p)
|
||||
|
||||
@@ -1,637 +0,0 @@
|
||||
// Parallel contact example
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 1 -testno 4
|
||||
// CG iteration numbers = 105 114 116 115 113 109 113 108 107 114 206 236 268 435 987
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 5
|
||||
// CG iteration numbers = 106 116 116 116 115 113 107 107 128 131 531 1437 1318
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 6
|
||||
// CG iteration numbers = 18 18 18 18 18 17 17 21 22 46 52 53
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "ipsolver/ParIPsolver.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
double GetBdrElementVolume(int i, Mesh & mesh)
|
||||
{
|
||||
ElementTransformation *et = mesh.GetBdrElementTransformation(i);
|
||||
const IntegrationRule &ir = IntRules.Get(mesh.GetBdrElementGeometry(i),
|
||||
et->OrderJ());
|
||||
double volume = 0.0;
|
||||
for (int j = 0; j < ir.GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(j);
|
||||
et->SetIntPoint(&ip);
|
||||
volume += ip.weight * et->Weight();
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
|
||||
double GetBdrArea(int bdrattr, Mesh&mesh)
|
||||
{
|
||||
double area = 0.0;
|
||||
for (int i = 0; i<mesh.GetNBE(); i++)
|
||||
{
|
||||
if (mesh.GetBdrAttribute(i) == bdrattr)
|
||||
{
|
||||
area += GetBdrElementVolume(i,mesh);
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Allreduce(MPI_IN_PLACE,&area,1, MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD);
|
||||
return area;
|
||||
}
|
||||
|
||||
void OutputData(ostringstream & file_name, double E0, double Ef, int dofs, int constr, int optit, const Array<int> & iters)
|
||||
{
|
||||
file_name << ".csv";
|
||||
std::ofstream outputfile(file_name.str().c_str());
|
||||
//if (!outputfile.is_open())
|
||||
//{
|
||||
// MFEM_ABORT("Failed to open file for writing.\n");
|
||||
//}
|
||||
outputfile << "Initial Energy objective = " << E0 << endl;
|
||||
outputfile << "Final Energy objective = " << Ef << endl;
|
||||
outputfile << "Global number of dofs = " << dofs << endl;
|
||||
outputfile << "Global number of constraints = " << constr << endl;
|
||||
outputfile << "Optimizer number of iterations = " << optit << endl;
|
||||
outputfile << "CG iteration numbers = "; iters.Print(outputfile, iters.Size());
|
||||
outputfile << "OptimizerIteration,CGIterations" << endl;
|
||||
for (int i = 0; i< iters.Size(); i++)
|
||||
{
|
||||
outputfile << i+1 <<","<< iters[i] << endl;
|
||||
}
|
||||
outputfile.close();
|
||||
std::cout << " Data has been written to " << file_name.str().c_str() << endl;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Mpi::Init();
|
||||
int myid = Mpi::WorldRank();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
Hypre::Init();
|
||||
|
||||
int order = 1;
|
||||
int sref = 1;
|
||||
int pref = 0;
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
bool visualization = true;
|
||||
bool paraview = false;
|
||||
int paraview_plot_every = 1;
|
||||
int SQPrepeat = 1;
|
||||
double linsolverrtol = 1e-10;
|
||||
double linsolveratol = 1e-12;
|
||||
int relax_type = 8;
|
||||
double optimizer_tol = 1e-6;
|
||||
int optimizer_maxit = 20;
|
||||
int linsolver = 2; // PCG - AMG
|
||||
bool elast = false;
|
||||
bool nocontact = false;
|
||||
int testNo = -1; // 0-6
|
||||
int nsteps = 1;
|
||||
bool outputfiles = false;
|
||||
bool doublepass = false;
|
||||
// 1. Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&testNo, "-testno", "--test-number",
|
||||
"Choice of test problem:"
|
||||
"-1: default (original 2 block problem)"
|
||||
"0: not implemented yet"
|
||||
"1: not implemented yet"
|
||||
"2: not implemented yet"
|
||||
"3: not implemented yet"
|
||||
"4: two block problem - diablo"
|
||||
"41: two block problem - twisted"
|
||||
"5: ironing problem"
|
||||
"51: ironing problem extended"
|
||||
"6: nested spheres problem");
|
||||
args.AddOption(&attr, "-at", "--attributes-surf",
|
||||
"Attributes of boundary faces on contact surface for mesh 2.");
|
||||
args.AddOption(&sref, "-sr", "--serial-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&nsteps, "-nsteps", "--nsteps",
|
||||
"Number of steps.");
|
||||
args.AddOption(&pref, "-pr", "--parallel-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&linsolverrtol, "-srtol", "--solver-rel-tol",
|
||||
"Linear Solver Relative Tolerance.");
|
||||
args.AddOption(&linsolveratol, "-satol", "--solver-abs-tol",
|
||||
"Linear Solver Abs Tolerance.");
|
||||
args.AddOption(&elast, "-elast", "--elast", "-no-elast",
|
||||
"--no-elast",
|
||||
"Enable or disable AMG Elasticity options.");
|
||||
args.AddOption(&nocontact, "-nocontact", "--nocontact", "-no-nocontact",
|
||||
"--no-nocontact",
|
||||
"Enable or disable AMG solve with no contact for testing.");
|
||||
args.AddOption(&doublepass, "-doublepass", "--double-pass", "-singlepass",
|
||||
"--single-pass",
|
||||
"Enable or disable double pass for contact constraints.");
|
||||
args.AddOption(&optimizer_tol, "-otol", "--optimizer-tol",
|
||||
"Interior Point Solver Tolerance.");
|
||||
args.AddOption(&optimizer_maxit, "-omaxit", "--optimizer-maxit",
|
||||
"Interior Point Solver maximum number of iterations.");
|
||||
args.AddOption(&relax_type, "-rt", "--relax-type",
|
||||
"Selection of Smoother for AMG");
|
||||
args.AddOption(&linsolver, "-ls", "--linear-solver",
|
||||
"Selection of inner linear solver:"
|
||||
"0: mumps,"
|
||||
"1: mumps-reduced,"
|
||||
"2: PCG-AMG-reduced,"
|
||||
"3: PCG- with block-diag(AMG,direct solver)"
|
||||
"4: with static cond of contact dofs");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(¶view, "-paraview", "--paraview", "-no-paraview",
|
||||
"--no-paraview",
|
||||
"Enable or disable ParaView visualization.");
|
||||
args.AddOption(¶view_plot_every, "-plot_every", "--plot-every",
|
||||
"Output every plot_every pseudotimesteps as a paraview file");
|
||||
args.AddOption(&SQPrepeat, "-nSQPrepeat", "--nSQP-repeats", "Number of times to relinearize and resolve the SQP before incremenetally updating forcing and boundary terms");
|
||||
args.AddOption(&outputfiles, "-out", "--output", "-no-out",
|
||||
"--no-ouput",
|
||||
"Enable or disable ouput to files.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
mfem::out << "Solving test problem number: " << testNo << endl;
|
||||
}
|
||||
|
||||
const char *mesh_file = nullptr;
|
||||
|
||||
switch (testNo)
|
||||
{
|
||||
case -1:
|
||||
mesh_file = "meshes/two-block.mesh";
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
MFEM_ABORT("Problem not implemented yet");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
mesh_file = "meshes/Test4.mesh";
|
||||
break;
|
||||
case 40:
|
||||
mesh_file = "meshes/Test40.mesh";
|
||||
break;
|
||||
case 41:
|
||||
mesh_file = "meshes/Test41.mesh";
|
||||
break;
|
||||
case 42:
|
||||
mesh_file = "meshes/Test42.mesh";
|
||||
break;
|
||||
case 5:
|
||||
mesh_file = "meshes/Test5.mesh";
|
||||
break;
|
||||
case 51:
|
||||
mesh_file = "meshes/Test51.mesh";
|
||||
break;
|
||||
case 6:
|
||||
mesh_file = "meshes/Test6.mesh";
|
||||
break;
|
||||
case 61:
|
||||
// Something wrong with this mesh
|
||||
mesh_file = "meshes/Test61.mesh";
|
||||
break;
|
||||
case 62:
|
||||
mesh_file = "meshes/Test62.mesh";
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Should be unreachable");
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh * mesh = new Mesh(mesh_file,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
ParMesh * pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
|
||||
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
Array<int> ess_bdr_attr;
|
||||
Array<int> ess_bdr_attr_comp;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(1);
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(2);
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 62)
|
||||
{
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 40)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(10); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(6); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
ParElasticityProblem * prob = new ParElasticityProblem(pmesh,
|
||||
ess_bdr_attr,ess_bdr_attr_comp,
|
||||
order);
|
||||
Vector lambda(prob->GetMesh()->attributes.Max());
|
||||
Vector mu(prob->GetMesh()->attributes.Max());
|
||||
|
||||
if (testNo == -1 )
|
||||
{
|
||||
lambda = 57.6923076923;
|
||||
mu = 38.4615384615;
|
||||
}
|
||||
else if (testNo == 6 || testNo == 61 || testNo == 62)
|
||||
{
|
||||
lambda = (1000*0.3)/(1.3*0.4);
|
||||
mu = 500/(1.3);
|
||||
}
|
||||
else
|
||||
{
|
||||
//lambda = 57.6923076923;
|
||||
//mu = 38.4615384615;
|
||||
//lambda = 0.499 / (1.499 * 0.002);
|
||||
//mu = 1. / (2. * 1.499);
|
||||
lambda[0] = 0.499/(1.499*0.002);
|
||||
lambda[1] = 0.0;
|
||||
mu[0] = 1. / (2. * 1.499);
|
||||
mu[1] = 500.;
|
||||
}
|
||||
|
||||
prob->SetLambda(lambda); prob->SetMu(mu);
|
||||
|
||||
int dim = pmesh->Dimension();
|
||||
Vector ess_values(dim);
|
||||
int essbdr_attr;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
|
||||
ess_values = 0.0;
|
||||
|
||||
|
||||
double area = GetBdrArea(3,*mesh);
|
||||
|
||||
// ConstantCoefficient one(-area);
|
||||
ConstantCoefficient one(-1.0);
|
||||
|
||||
std::set<int> mortar_attr;
|
||||
std::set<int> nonmortar_attr;
|
||||
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[0] = 1;
|
||||
ess_bdr[1] = 1;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else if(testNo == 62)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
prob->SetNeumanData(0,3,-2.0);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (testNo == -1 || testNo == 41)
|
||||
{
|
||||
ess_values[0] = 0.1/nsteps;
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_values[2] = 1.0 / 1.4 / nsteps;
|
||||
//ess_values[2] = 0.25 / nsteps;//1.0/1.4/nsteps;
|
||||
// ess_values[0] = -2.0/nsteps;
|
||||
}
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = (testNo == 40) ? 10 : 6;
|
||||
ess_values = 0.0; ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
if (testNo == 40)
|
||||
{
|
||||
mortar_attr.insert(4);
|
||||
nonmortar_attr.insert(7);
|
||||
}
|
||||
else
|
||||
{
|
||||
mortar_attr.insert(3);
|
||||
nonmortar_attr.insert(4);
|
||||
}
|
||||
}
|
||||
|
||||
ParFiniteElementSpace * fes = prob->GetFESpace();
|
||||
ParGridFunction x_gf(fes); x_gf = 0.0;
|
||||
ParGridFunction xnew(fes); xnew = 0.0;
|
||||
ParaViewDataCollection * paraview_dc = nullptr;
|
||||
ParMesh pmesh_copy(*pmesh);
|
||||
ParFiniteElementSpace fes_copy(*fes,pmesh_copy);
|
||||
ParGridFunction xcopy_gf(&fes_copy); xcopy_gf = 0.0;
|
||||
|
||||
if (paraview)
|
||||
{
|
||||
std::ostringstream paraview_file_name;
|
||||
paraview_file_name << "QPContact-Test_" << testNo
|
||||
<< "_par_ref_" << pref
|
||||
<< "_ser_ref_" << sref;
|
||||
paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &pmesh_copy);
|
||||
paraview_dc->SetPrefixPath("ParaView");
|
||||
paraview_dc->SetLevelsOfDetail(1);
|
||||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc->SetHighOrderOutput(true);
|
||||
// paraview_dc->RegisterField("u", &x_gf);
|
||||
paraview_dc->RegisterField("u", &xcopy_gf);
|
||||
paraview_dc->SetCycle(0);
|
||||
paraview_dc->SetTime(double(0));
|
||||
paraview_dc->Save();
|
||||
}
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
sol_sock.open(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
// ParGridFunction coords(prob->GetFESpace());
|
||||
ParGridFunction ref_coords(prob->GetFESpace());
|
||||
ParGridFunction new_coords(prob->GetFESpace());
|
||||
pmesh->GetNodes(new_coords);
|
||||
pmesh->GetNodes(ref_coords);
|
||||
|
||||
Vector xref(x_gf.GetTrueVector().Size());
|
||||
|
||||
HypreParMatrix *dgdu;
|
||||
double p = 1;
|
||||
ConstantCoefficient f(p);
|
||||
|
||||
// SQPrepeat solves on same problem (forcing/boundary conditions)
|
||||
int Nsteps = nsteps * SQPrepeat;
|
||||
|
||||
double pseudotime = 0.0;
|
||||
double pseudotimestep = 1.0 / ((double) nsteps);
|
||||
double paraview_time = 0.0;
|
||||
double paraview_subtimestep = pseudotimestep / ((double) SQPrepeat);
|
||||
int paraview_cycle = 1;
|
||||
|
||||
bool QPConverged;
|
||||
|
||||
std::ofstream numConstraintsStream;
|
||||
std::ostringstream numConstraints_file_name;
|
||||
numConstraints_file_name << "data/numConstraints_ref" << sref << ".dat";
|
||||
if (Mpi::Root)
|
||||
{
|
||||
numConstraintsStream.open(numConstraints_file_name.str(), ios::out | ios::trunc);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nsteps; i++)
|
||||
{
|
||||
pseudotime = ((double) (i + 1)) / ((double) nsteps);
|
||||
for (int j = 0; j < SQPrepeat; j++)
|
||||
{
|
||||
paraview_time = pseudotime + j * paraview_subtimestep;
|
||||
if (testNo == 6)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
f.constant = -p * pseudotime;
|
||||
prob->SetNeumanPressureData(f,ess_bdr);
|
||||
// prob->SetNeumanData(0,3,-p*(i+1)/nsteps);
|
||||
}
|
||||
else if (testNo == 4 || testNo == 40 || testNo == 5 || testNo == 51)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
ess_values = 0.0;
|
||||
//ess_values[2] = 4.0 / 7.0 * pseudotime;
|
||||
//ess_values[2] = 0.25 * pseudotime; //1.0/1.4 * pseudotime;
|
||||
ess_values[2] = 1.0 / 1.4 * pseudotime;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
else if (testNo == 41)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_values[0] = 0.5 * pseudotime; //0.5/nsteps*(i+1);
|
||||
// ess_values[0] = 0.0;
|
||||
essbdr_attr = 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = 6;
|
||||
ess_values = 0.0;
|
||||
// ess_values[0] = -0.5/nsteps*(i+1);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "ess_values[0] = " << ess_values[0] << endl;
|
||||
}
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
|
||||
//xref.Set(1.0, x_gf.GetTrueVector());
|
||||
xref = 0.0;
|
||||
ParContactProblem contact(prob, mortar_attr, nonmortar_attr, &new_coords, doublepass);
|
||||
QPOptParContactProblem qpopt(&contact, xref);
|
||||
int numconstr = contact.GetGlobalNumConstraints();
|
||||
ParInteriorPointSolver optimizer(&qpopt);
|
||||
optimizer.SetTol(optimizer_tol);
|
||||
optimizer.SetMaxIter(optimizer_maxit);
|
||||
optimizer.SetLinearSolver(linsolver);
|
||||
optimizer.SetLinearSolveRelTol(linsolverrtol);
|
||||
optimizer.SetLinearSolveAbsTol(linsolveratol);
|
||||
optimizer.SetLinearSolveRelaxType(relax_type);
|
||||
if (nocontact)
|
||||
{
|
||||
optimizer.EnableNoContactSolve();
|
||||
}
|
||||
if (elast)
|
||||
{
|
||||
optimizer.SetElasticityOptions(prob->GetFESpace());
|
||||
}
|
||||
// ParGridFunction x = prob->GetDisplacementGridFunction();
|
||||
// x.SetTrueVector();
|
||||
// Vector x0 = x.GetTrueVector();
|
||||
|
||||
x_gf.SetTrueVector();
|
||||
|
||||
|
||||
Vector x0 = x_gf.GetTrueVector();
|
||||
int ndofs = x0.Size();
|
||||
Vector xf(ndofs); xf = 0.0;
|
||||
optimizer.Mult(x0, xf);
|
||||
QPConverged = optimizer.GetConverged();
|
||||
|
||||
/* exit if not converged */
|
||||
MFEM_VERIFY(QPConverged, "IPM not converged on QP contact problem");
|
||||
|
||||
|
||||
double Einitial = contact.E(x0);
|
||||
double Efinal = contact.E(xf);
|
||||
Array<int> & CGiterations = optimizer.GetCGIterNumbers();
|
||||
int gndofs = prob->GetGlobalNumDofs();
|
||||
int gnconstraints = contact.GetGlobalNumConstraints();
|
||||
|
||||
//std::ofstream xfStream;
|
||||
//std::ostringstream xf_file_name;
|
||||
//xf_file_name << "data/xf_" << i << ".dat";
|
||||
//if (Mpi::Root())
|
||||
//{
|
||||
// xfStream.open(xf_file_name.str(), ios::out | ios::trunc);
|
||||
// for (int ii = 0; ii < xf.Size(); ii++)
|
||||
// {
|
||||
// xfStream << xf(ii) << "\n";
|
||||
// }
|
||||
// xfStream.close();
|
||||
//}
|
||||
//if (Mpi::Root)
|
||||
//{
|
||||
// numConstraintsStream.open(numConstraints_file_name.str(), ios::out | ios::trunc);
|
||||
//}
|
||||
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
|
||||
mfem::out << endl;
|
||||
mfem::out << " Initial Energy objective = " << Einitial << endl;
|
||||
mfem::out << " Final Energy objective = " << Efinal << endl;
|
||||
mfem::out << " Global number of dofs = " << gndofs << endl;
|
||||
mfem::out << " Global number of constraints = " << numconstr << endl;
|
||||
mfem::out << " Optimizer number of iterations = " <<
|
||||
optimizer.GetNumIterations() << endl;
|
||||
if (linsolver == 2 || linsolver == 3 || linsolver == 4)
|
||||
{
|
||||
mfem::out << " CG iteration numbers = " ;
|
||||
CGiterations.Print(mfem::out, CGiterations.Size());
|
||||
}
|
||||
if (nocontact)
|
||||
{
|
||||
Array<int> & CGNoContactIterations = optimizer.GetCGNoContactIterNumbers();
|
||||
mfem::out << " CG no Contact iteration numbers = " ;
|
||||
CGNoContactIterations.Print(mfem::out, CGNoContactIterations.Size());
|
||||
}
|
||||
if (outputfiles)
|
||||
{
|
||||
ostringstream file_name;
|
||||
file_name << "output/Testno-"<<testNo<<"-ref-"<<sref+pref << "-step-" << i;
|
||||
OutputData(file_name, Einitial, Efinal, gndofs,numconstr, optimizer.GetNumIterations(), CGiterations);
|
||||
}
|
||||
numConstraintsStream << gnconstraints << endl;
|
||||
}
|
||||
|
||||
// Vector X_new(xf.GetData(),fes->GetTrueVSize());
|
||||
// xnew.SetFromTrueDofs(X_new);
|
||||
// x_gf = xnew;
|
||||
x_gf.SetFromTrueDofs(xf);
|
||||
// mfem::out << "x_gf norm = " << x_gf.Norml2() << endl;
|
||||
// cin.get();
|
||||
// pmesh->MoveNodes(xnew);
|
||||
// pmesh_copy.MoveNodes(xnew);
|
||||
// pmesh_copy.MoveNodes(xnew);
|
||||
add(ref_coords,x_gf,new_coords);
|
||||
// mfem::out << " ref_coords norm " << ref_coords.Norml2() << endl;
|
||||
// mfem::out << " x_gf norm " << x_gf.Norml2() << endl;
|
||||
// mfem::out << " new_coords norm " << new_coords.Norml2() << endl;
|
||||
// pmesh_copy.SetNodes(new_coords);
|
||||
pmesh_copy.SetNodes(new_coords);
|
||||
xcopy_gf = x_gf;
|
||||
// pmesh_copy.MoveNodes(x_gf);
|
||||
// pmesh_copy.SetNodes(x_gf);
|
||||
if (paraview && ((i+1) % paraview_plot_every == 0 ))
|
||||
{
|
||||
paraview_cycle += 1;
|
||||
paraview_dc->SetCycle(paraview_cycle) ;
|
||||
paraview_dc->SetTime(paraview_time);
|
||||
paraview_dc->Save();
|
||||
}
|
||||
|
||||
if (visualization)
|
||||
{
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n"
|
||||
<< "solution\n" << pmesh_copy << x_gf << flush;
|
||||
|
||||
if (i == nsteps - 1 && j == SQPrepeat - 1)
|
||||
{
|
||||
pmesh->MoveNodes(x_gf);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock1(vishost, visport);
|
||||
sol_sock1 << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock1.precision(8);
|
||||
sol_sock1 << "solution\n" << *pmesh << x_gf << flush;
|
||||
}
|
||||
}
|
||||
if (i == nsteps - 1 && j == SQPrepeat) break;
|
||||
|
||||
prob->UpdateStep();
|
||||
if (testNo == 6 )
|
||||
{
|
||||
double area_new = GetBdrArea(3,*pmesh);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "New area = " << area_new << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Mpi::Root)
|
||||
{
|
||||
numConstraintsStream.close();
|
||||
}
|
||||
delete prob;
|
||||
delete pmesh;
|
||||
delete mesh;
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,114 +0,0 @@
|
||||
#include "mfem.hpp"
|
||||
#include "../problems/parproblems.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
|
||||
#ifndef PARIPSOLVER
|
||||
#define PARIPSOLVER
|
||||
|
||||
class ParInteriorPointSolver
|
||||
{
|
||||
protected:
|
||||
QPOptParContactProblem* problem = nullptr;
|
||||
double OptTol;
|
||||
int max_iter;
|
||||
int iter=0;
|
||||
double mu_k; // \mu_k
|
||||
Vector lk, zlk;
|
||||
|
||||
double sMax, kSig, tauMin, eta, thetaMin, delta, sTheta, sPhi, kMu, thetaMu;
|
||||
double thetaMax, kSoc, gTheta, gPhi, kEps;
|
||||
|
||||
// filter
|
||||
Array<double> F1, F2;
|
||||
|
||||
// quantities computed in lineSearch
|
||||
double alpha, alphaz;
|
||||
double thx0, thxtrial;
|
||||
double phx0, phxtrial;
|
||||
bool descentDirection, switchCondition, sufficientDecrease, lineSearchSuccess, inFilterRegion;
|
||||
double Dxphi0_xhat;
|
||||
|
||||
int dimU, dimM, dimC;
|
||||
int gdimU, gdimM, gdimC;
|
||||
Array<int> block_offsetsumlz, block_offsetsuml, block_offsetsx;
|
||||
Vector ml;
|
||||
|
||||
Vector ckSoc;
|
||||
HypreParMatrix * Huu = nullptr;
|
||||
HypreParMatrix * Hum = nullptr;
|
||||
HypreParMatrix * Hmu = nullptr;
|
||||
HypreParMatrix * Hmm = nullptr;
|
||||
HypreParMatrix * Wmm = nullptr;
|
||||
HypreParMatrix * Ju = nullptr;
|
||||
HypreParMatrix * Jm = nullptr;
|
||||
HypreParMatrix * JuT = nullptr;
|
||||
HypreParMatrix * JmT = nullptr;
|
||||
|
||||
Array<int> cgnum_iterations;
|
||||
Array<int> cgnum_iterations_nocontact;
|
||||
ParFiniteElementSpace *pfes = nullptr;
|
||||
|
||||
int jOpt;
|
||||
bool converged;
|
||||
|
||||
int MyRank;
|
||||
bool iAmRoot;
|
||||
|
||||
bool saveLogBarrierIterates = false;
|
||||
|
||||
int linSolver=0;
|
||||
double linSolveAbsTol = 1e-12;
|
||||
double linSolveRelTol = 1e-6;
|
||||
int relax_type = 8;
|
||||
bool nocontact = false;
|
||||
public:
|
||||
ParInteriorPointSolver(QPOptParContactProblem*);
|
||||
double MaxStepSize(Vector& , Vector& , Vector& , double);
|
||||
double MaxStepSize(Vector& , Vector& , double);
|
||||
void Mult(const BlockVector& , BlockVector&);
|
||||
void Mult(const Vector&, Vector &);
|
||||
void FormIPNewtonMat(BlockVector& , Vector& , Vector& , BlockOperator &);
|
||||
void IPNewtonSolve(BlockVector& , Vector& , Vector& , Vector&, BlockVector& , double, bool);
|
||||
void lineSearch(BlockVector& , BlockVector& , double);
|
||||
void projectZ(const Vector & , Vector &, double);
|
||||
void filterCheck(double, double);
|
||||
double E(const BlockVector &, const Vector &, const Vector &, double, bool);
|
||||
double E(const BlockVector &, const Vector &, const Vector &, bool);
|
||||
bool GetConverged() const;
|
||||
Array<int> & GetCGIterNumbers() {return cgnum_iterations;}
|
||||
Array<int> & GetCGNoContactIterNumbers() {return cgnum_iterations_nocontact;}
|
||||
int GetNumIterations() {return iter;}
|
||||
// TO DO: include Hessian of Lagrangian
|
||||
double theta(const BlockVector &);
|
||||
double phi(const BlockVector &, double);
|
||||
void Dxphi(const BlockVector &, double, BlockVector &);
|
||||
double L(const BlockVector &, const Vector &, const Vector &);
|
||||
void DxL(const BlockVector &, const Vector &, const Vector &, BlockVector &);
|
||||
void SetTol(double);
|
||||
void SetMaxIter(int);
|
||||
void SetBarrierParameter(double);
|
||||
void SaveLogBarrierHessianIterates(bool);
|
||||
void SaveLambda(int);
|
||||
void SaveZl(int);
|
||||
void SetLinearSolver(int);
|
||||
void SetLinearSolveAbsTol(double);
|
||||
void SetLinearSolveRelTol(double);
|
||||
void SetLinearSolveRelaxType(int);
|
||||
|
||||
void SetElasticityOptions(ParFiniteElementSpace * pfes_)
|
||||
{
|
||||
pfes = pfes_;
|
||||
}
|
||||
void EnableNoContactSolve()
|
||||
{
|
||||
nocontact = true;
|
||||
}
|
||||
virtual ~ParInteriorPointSolver();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,109 +0,0 @@
|
||||
# Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced
|
||||
# at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
# LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
#
|
||||
# This file is part of the MFEM library. For more information and source code
|
||||
# availability visit https://mfem.org.
|
||||
#
|
||||
# MFEM is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
# CONTRIBUTING.md for details.
|
||||
|
||||
# Use the MFEM build directory
|
||||
MFEM_DIR ?= ../..
|
||||
MFEM_BUILD_DIR ?= ../..
|
||||
SRC = $(if $(MFEM_DIR:../..=),$(MFEM_DIR)/miniapps/contact/,)
|
||||
CONFIG_MK = $(MFEM_BUILD_DIR)/config/config.mk
|
||||
|
||||
# Include defaults.mk to get XLINKER
|
||||
#DEFAULTS_MK = $(MFEM_DIR)/config/defaults.mk
|
||||
#include $(DEFAULTS_MK)
|
||||
|
||||
MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
FRAMEWORK_SRC = ipsolver/ParIPsolver.cpp problems/parproblems.cpp problems/parproblems_util.cpp
|
||||
CONTACT_SRC = contact.cpp $(FRAMEWORK_SRC)
|
||||
CONTACT_OBJ = $(CONTACT_SRC:.cpp=.o)
|
||||
|
||||
CONTACT_FDCHECK_SRC = contactFDcheck.cpp $(FRAMEWORK_SRC)
|
||||
CONTACT_FDCHECK_OBJ = $(CONTACT_FDCHECK_SRC:.cpp=.o)
|
||||
|
||||
SCRATCH_SRC = scratch.cpp $(FRAMEWORK_SRC)
|
||||
SCRATCH_OBJ = $(SCRATCH_SRC:.cpp=.o)
|
||||
|
||||
|
||||
SEQ_MINIAPPS =
|
||||
PAR_MINIAPPS = scratch contact contactFDcheck
|
||||
|
||||
ifeq ($(MFEM_USE_MPI),NO)
|
||||
MINIAPPS = $(SEQ_MINIAPPS)
|
||||
else
|
||||
MINIAPPS = $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
|
||||
endif
|
||||
|
||||
COMMON_LIB = -L$(MFEM_BUILD_DIR)/miniapps/common -lmfem-common
|
||||
|
||||
# If MFEM_SHARED is set, add the ../common rpath
|
||||
COMMON_LIB += $(if $(MFEM_SHARED:YES=),,\
|
||||
$(if $(MFEM_USE_CUDA:YES=),$(CXX_XLINKER),$(CUDA_XLINKER))-rpath,$(abspath\
|
||||
$(MFEM_BUILD_DIR)/miniapps/common))
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .o .cpp .mk
|
||||
.PHONY: all lib-common clean clean-build clean-exec
|
||||
|
||||
# Remove built-in rule
|
||||
%: %.cpp
|
||||
%.o: %.cpp
|
||||
|
||||
%.o: $(SRC)%.cpp $(wildcard $(SRC)%.hpp) $(MFEM_LIB_FILE)\
|
||||
$(CONFIG_MK) | lib-common
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
|
||||
|
||||
problems/%.o: $(SRC)problems/%.cpp $(wildcard $(SRC)problems/%.hpp) $(MFEM_LIB_FILE)\
|
||||
$(CONFIG_MK) | lib-common
|
||||
mkdir -p $(@D)
|
||||
$(MFEM_CXX) $(MFEM_FLAGS) -c $< -o $@
|
||||
|
||||
|
||||
all: $(MINIAPPS)
|
||||
|
||||
contact: $(CONTACT_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(CONTACT_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
contactFDcheck: $(CONTACT_FDCHECK_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(CONTACT_FDCHECK_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
scratch: $(SCRATCH_OBJ)
|
||||
$(MFEM_CXX) $(MFEM_LINK_FLAGS) -o $@ $(SCRATCH_OBJ) $(COMMON_LIB) $(MFEM_LIBS) \
|
||||
-l$(patsubst lib%,%,$(basename $(notdir $(MFEM_LIB_FILE))))
|
||||
|
||||
|
||||
# Rule for building lib-common
|
||||
lib-common:
|
||||
$(MAKE) -C $(MFEM_BUILD_DIR)/miniapps/common
|
||||
|
||||
MFEM_TESTS = MINIAPPS
|
||||
include $(MFEM_TEST_MK)
|
||||
|
||||
# Testing: Specific execution options
|
||||
RUN_MPI = $(MFEM_MPIEXEC) $(MFEM_MPIEXEC_NP) $(MFEM_MPI_NP)
|
||||
contact-test-par: contact
|
||||
@$(call mfem-test,$<, $(RUN_MPI), pcontact miniapp,)
|
||||
|
||||
# Generate an error message if the MFEM library is not built and exit
|
||||
$(MFEM_LIB_FILE):
|
||||
$(error The MFEM library is not built)
|
||||
|
||||
clean: clean-build clean-exec
|
||||
|
||||
clean-build:
|
||||
rm -f *.o *~ $(PAR_MINIAPPS) $(SEQ_MINIAPPS)
|
||||
rm -f $(CONTACT_OBJ)
|
||||
rm -rf *.dSYM *.TVD.*breakpoints
|
||||
|
||||
clean-exec:
|
||||
@rm -rf ParaView
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,453 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
89
|
||||
1 5 0 1 5 4 40 41 45 44
|
||||
1 5 40 41 45 44 80 81 85 84
|
||||
1 5 44 45 49 48 84 85 89 88
|
||||
1 5 4 5 9 8 44 45 49 48
|
||||
1 5 5 6 10 9 45 46 50 49
|
||||
1 5 45 46 50 49 85 86 90 89
|
||||
1 5 41 42 46 45 81 82 86 85
|
||||
1 5 1 2 6 5 41 42 46 45
|
||||
1 5 2 3 7 6 42 43 47 46
|
||||
1 5 42 43 47 46 82 83 87 86
|
||||
1 5 6 7 11 10 46 47 51 50
|
||||
1 5 46 47 51 50 86 87 91 90
|
||||
1 5 86 87 91 90 126 127 131 130
|
||||
1 5 82 83 87 86 122 123 127 126
|
||||
1 5 81 82 86 85 121 122 126 125
|
||||
1 5 80 81 85 84 120 121 125 124
|
||||
1 5 84 85 89 88 124 125 129 128
|
||||
1 5 85 86 90 89 125 126 130 129
|
||||
1 5 89 90 94 93 129 130 134 133
|
||||
1 5 88 89 93 92 128 129 133 132
|
||||
1 5 92 93 97 96 132 133 137 136
|
||||
1 5 93 94 98 97 133 134 138 137
|
||||
1 5 94 95 99 98 134 135 139 138
|
||||
1 5 54 55 59 58 94 95 99 98
|
||||
1 5 90 91 95 94 130 131 135 134
|
||||
1 5 50 51 55 54 90 91 95 94
|
||||
1 5 10 11 15 14 50 51 55 54
|
||||
1 5 14 15 19 18 54 55 59 58
|
||||
1 5 13 14 18 17 53 54 58 57
|
||||
1 5 53 54 58 57 93 94 98 97
|
||||
1 5 49 50 54 53 89 90 94 93
|
||||
1 5 9 10 14 13 49 50 54 53
|
||||
1 5 8 9 13 12 48 49 53 52
|
||||
1 5 48 49 53 52 88 89 93 92
|
||||
1 5 52 53 57 56 92 93 97 96
|
||||
1 5 12 13 17 16 52 53 57 56
|
||||
1 5 16 17 21 20 56 57 61 60
|
||||
1 5 56 57 61 60 96 97 101 100
|
||||
1 5 57 58 62 61 97 98 102 101
|
||||
1 5 17 18 22 21 57 58 62 61
|
||||
1 5 18 19 23 22 58 59 63 62
|
||||
1 5 58 59 63 62 98 99 103 102
|
||||
1 5 98 99 103 102 138 139 143 142
|
||||
1 5 97 98 102 101 137 138 142 141
|
||||
1 5 96 97 101 100 136 137 141 140
|
||||
1 5 100 101 105 104 140 141 145 144
|
||||
1 5 101 102 106 105 141 142 146 145
|
||||
1 5 102 103 107 106 142 143 147 146
|
||||
1 5 62 63 67 66 102 103 107 106
|
||||
1 5 22 23 27 26 62 63 67 66
|
||||
1 5 21 22 26 25 61 62 66 65
|
||||
1 5 61 62 66 65 101 102 106 105
|
||||
1 5 60 61 65 64 100 101 105 104
|
||||
1 5 20 21 25 24 60 61 65 64
|
||||
1 5 24 25 29 28 64 65 69 68
|
||||
1 5 64 65 69 68 104 105 109 108
|
||||
1 5 68 69 73 72 108 109 113 112
|
||||
1 5 28 29 33 32 68 69 73 72
|
||||
1 5 29 30 34 33 69 70 74 73
|
||||
1 5 69 70 74 73 109 110 114 113
|
||||
1 5 65 66 70 69 105 106 110 109
|
||||
1 5 25 26 30 29 65 66 70 69
|
||||
1 5 26 27 31 30 66 67 71 70
|
||||
1 5 66 67 71 70 106 107 111 110
|
||||
1 5 30 31 35 34 70 71 75 74
|
||||
1 5 70 71 75 74 110 111 115 114
|
||||
1 5 110 111 115 114 150 151 155 154
|
||||
1 5 106 107 111 110 146 147 151 150
|
||||
1 5 105 106 110 109 145 146 150 149
|
||||
1 5 109 110 114 113 149 150 154 153
|
||||
1 5 104 105 109 108 144 145 149 148
|
||||
1 5 108 109 113 112 148 149 153 152
|
||||
1 5 112 113 117 116 152 153 157 156
|
||||
1 5 113 114 118 117 153 154 158 157
|
||||
1 5 114 115 119 118 154 155 159 158
|
||||
1 5 74 75 79 78 114 115 119 118
|
||||
1 5 34 35 39 38 74 75 79 78
|
||||
1 5 33 34 38 37 73 74 78 77
|
||||
1 5 73 74 78 77 113 114 118 117
|
||||
1 5 72 73 77 76 112 113 117 116
|
||||
1 5 32 33 37 36 72 73 77 76
|
||||
2 5 160 161 164 163 169 170 173 172
|
||||
2 5 163 164 167 166 172 173 176 175
|
||||
2 5 172 173 176 175 181 182 185 184
|
||||
2 5 169 170 173 172 178 179 182 181
|
||||
2 5 170 171 174 173 179 180 183 182
|
||||
2 5 173 174 177 176 182 183 186 185
|
||||
2 5 164 165 168 167 173 174 177 176
|
||||
2 5 161 162 165 164 170 171 174 173
|
||||
|
||||
boundary
|
||||
150
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 12 16 17 13
|
||||
1 3 13 17 18 14
|
||||
1 3 14 18 19 15
|
||||
1 3 16 20 21 17
|
||||
1 3 17 21 22 18
|
||||
1 3 18 22 23 19
|
||||
1 3 20 24 25 21
|
||||
1 3 21 25 26 22
|
||||
1 3 22 26 27 23
|
||||
1 3 24 28 29 25
|
||||
1 3 25 29 30 26
|
||||
1 3 26 30 31 27
|
||||
1 3 28 32 33 29
|
||||
1 3 29 33 34 30
|
||||
1 3 30 34 35 31
|
||||
1 3 32 36 37 33
|
||||
1 3 33 37 38 34
|
||||
1 3 34 38 39 35
|
||||
1 3 120 121 125 124
|
||||
1 3 121 122 126 125
|
||||
1 3 122 123 127 126
|
||||
1 3 124 125 129 128
|
||||
1 3 125 126 130 129
|
||||
1 3 126 127 131 130
|
||||
1 3 128 129 133 132
|
||||
1 3 129 130 134 133
|
||||
1 3 130 131 135 134
|
||||
1 3 132 133 137 136
|
||||
1 3 133 134 138 137
|
||||
1 3 134 135 139 138
|
||||
1 3 136 137 141 140
|
||||
1 3 137 138 142 141
|
||||
1 3 138 139 143 142
|
||||
1 3 140 141 145 144
|
||||
1 3 141 142 146 145
|
||||
1 3 142 143 147 146
|
||||
1 3 144 145 149 148
|
||||
1 3 145 146 150 149
|
||||
1 3 146 147 151 150
|
||||
1 3 148 149 153 152
|
||||
1 3 149 150 154 153
|
||||
1 3 150 151 155 154
|
||||
1 3 152 153 157 156
|
||||
1 3 153 154 158 157
|
||||
1 3 154 155 159 158
|
||||
2 3 0 40 44 4
|
||||
2 3 4 44 48 8
|
||||
2 3 8 48 52 12
|
||||
2 3 12 52 56 16
|
||||
2 3 16 56 60 20
|
||||
2 3 20 60 64 24
|
||||
2 3 24 64 68 28
|
||||
2 3 28 68 72 32
|
||||
2 3 32 72 76 36
|
||||
2 3 40 80 84 44
|
||||
2 3 44 84 88 48
|
||||
2 3 48 88 92 52
|
||||
2 3 52 92 96 56
|
||||
2 3 56 96 100 60
|
||||
2 3 60 100 104 64
|
||||
2 3 64 104 108 68
|
||||
2 3 68 108 112 72
|
||||
2 3 72 112 116 76
|
||||
2 3 80 120 124 84
|
||||
2 3 84 124 128 88
|
||||
2 3 88 128 132 92
|
||||
2 3 92 132 136 96
|
||||
2 3 96 136 140 100
|
||||
2 3 100 140 144 104
|
||||
2 3 104 144 148 108
|
||||
2 3 108 148 152 112
|
||||
2 3 112 152 156 116
|
||||
3 3 3 7 47 43
|
||||
3 3 7 11 51 47
|
||||
3 3 11 15 55 51
|
||||
3 3 15 19 59 55
|
||||
3 3 19 23 63 59
|
||||
3 3 23 27 67 63
|
||||
3 3 27 31 71 67
|
||||
3 3 31 35 75 71
|
||||
3 3 35 39 79 75
|
||||
3 3 43 47 87 83
|
||||
3 3 47 51 91 87
|
||||
3 3 51 55 95 91
|
||||
3 3 55 59 99 95
|
||||
3 3 59 63 103 99
|
||||
3 3 63 67 107 103
|
||||
3 3 67 71 111 107
|
||||
3 3 71 75 115 111
|
||||
3 3 75 79 119 115
|
||||
3 3 83 87 127 123
|
||||
3 3 87 91 131 127
|
||||
3 3 91 95 135 131
|
||||
3 3 95 99 139 135
|
||||
3 3 99 103 143 139
|
||||
3 3 103 107 147 143
|
||||
3 3 107 111 151 147
|
||||
3 3 111 115 155 151
|
||||
3 3 115 119 159 155
|
||||
1 3 0 1 41 40
|
||||
1 3 40 41 81 80
|
||||
1 3 80 81 121 120
|
||||
1 3 1 2 42 41
|
||||
1 3 41 42 82 81
|
||||
1 3 81 82 122 121
|
||||
1 3 2 3 43 42
|
||||
1 3 42 43 83 82
|
||||
1 3 82 83 123 122
|
||||
1 3 36 76 77 37
|
||||
1 3 76 116 117 77
|
||||
1 3 116 156 157 117
|
||||
1 3 37 77 78 38
|
||||
1 3 77 117 118 78
|
||||
1 3 117 157 158 118
|
||||
1 3 38 78 79 39
|
||||
1 3 78 118 119 79
|
||||
1 3 118 158 159 119
|
||||
5 3 160 163 164 161
|
||||
5 3 161 164 165 162
|
||||
5 3 163 166 167 164
|
||||
5 3 164 167 168 165
|
||||
5 3 178 179 182 181
|
||||
5 3 179 180 183 182
|
||||
5 3 181 182 185 184
|
||||
5 3 182 183 186 185
|
||||
4 3 160 169 172 163
|
||||
4 3 163 172 175 166
|
||||
4 3 169 178 181 172
|
||||
4 3 172 181 184 175
|
||||
6 3 162 165 174 171
|
||||
6 3 165 168 177 174
|
||||
6 3 171 174 183 180
|
||||
6 3 174 177 186 183
|
||||
5 3 160 161 170 169
|
||||
5 3 169 170 179 178
|
||||
5 3 161 162 171 170
|
||||
5 3 170 171 180 179
|
||||
5 3 166 175 176 167
|
||||
5 3 175 184 185 176
|
||||
5 3 167 176 177 168
|
||||
5 3 176 185 186 177
|
||||
|
||||
vertices
|
||||
187
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 1.3333333 0
|
||||
-0.66666667 1.3333333 0
|
||||
-0.33333333 1.3333333 0
|
||||
0 1.3333333 0
|
||||
-1 1.6666667 0
|
||||
-0.66666667 1.6666667 0
|
||||
-0.33333333 1.6666667 0
|
||||
0 1.6666667 0
|
||||
-1 2 0
|
||||
-0.66666667 2 0
|
||||
-0.33333333 2 0
|
||||
0 2 0
|
||||
-1 2.3333333 0
|
||||
-0.66666667 2.3333333 0
|
||||
-0.33333333 2.3333333 0
|
||||
0 2.3333333 0
|
||||
-1 2.6666667 0
|
||||
-0.66666667 2.6666667 0
|
||||
-0.33333333 2.6666667 0
|
||||
0 2.6666667 0
|
||||
-1 3 0
|
||||
-0.66666667 3 0
|
||||
-0.33333333 3 0
|
||||
0 3 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 1.3333333 0.33333333
|
||||
-0.66666667 1.3333333 0.33333333
|
||||
-0.33333333 1.3333333 0.33333333
|
||||
0 1.3333333 0.33333333
|
||||
-1 1.6666667 0.33333333
|
||||
-0.66666667 1.6666667 0.33333333
|
||||
-0.33333333 1.6666667 0.33333333
|
||||
0 1.6666667 0.33333333
|
||||
-1 2 0.33333333
|
||||
-0.66666667 2 0.33333333
|
||||
-0.33333333 2 0.33333333
|
||||
0 2 0.33333333
|
||||
-1 2.3333333 0.33333333
|
||||
-0.66666667 2.3333333 0.33333333
|
||||
-0.33333333 2.3333333 0.33333333
|
||||
0 2.3333333 0.33333333
|
||||
-1 2.6666667 0.33333333
|
||||
-0.66666667 2.6666667 0.33333333
|
||||
-0.33333333 2.6666667 0.33333333
|
||||
0 2.6666667 0.33333333
|
||||
-1 3 0.33333333
|
||||
-0.66666667 3 0.33333333
|
||||
-0.33333333 3 0.33333333
|
||||
0 3 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 1.3333333 0.66666667
|
||||
-0.66666667 1.3333333 0.66666667
|
||||
-0.33333333 1.3333333 0.66666667
|
||||
0 1.3333333 0.66666667
|
||||
-1 1.6666667 0.66666667
|
||||
-0.66666667 1.6666667 0.66666667
|
||||
-0.33333333 1.6666667 0.66666667
|
||||
0 1.6666667 0.66666667
|
||||
-1 2 0.66666667
|
||||
-0.66666667 2 0.66666667
|
||||
-0.33333333 2 0.66666667
|
||||
0 2 0.66666667
|
||||
-1 2.3333333 0.66666667
|
||||
-0.66666667 2.3333333 0.66666667
|
||||
-0.33333333 2.3333333 0.66666667
|
||||
0 2.3333333 0.66666667
|
||||
-1 2.6666667 0.66666667
|
||||
-0.66666667 2.6666667 0.66666667
|
||||
-0.33333333 2.6666667 0.66666667
|
||||
0 2.6666667 0.66666667
|
||||
-1 3 0.66666667
|
||||
-0.66666667 3 0.66666667
|
||||
-0.33333333 3 0.66666667
|
||||
0 3 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
-1 1.3333333 1
|
||||
-0.66666667 1.3333333 1
|
||||
-0.33333333 1.3333333 1
|
||||
0 1.3333333 1
|
||||
-1 1.6666667 1
|
||||
-0.66666667 1.6666667 1
|
||||
-0.33333333 1.6666667 1
|
||||
0 1.6666667 1
|
||||
-1 2 1
|
||||
-0.66666667 2 1
|
||||
-0.33333333 2 1
|
||||
0 2 1
|
||||
-1 2.3333333 1
|
||||
-0.66666667 2.3333333 1
|
||||
-0.33333333 2.3333333 1
|
||||
0 2.3333333 1
|
||||
-1 2.6666667 1
|
||||
-0.66666667 2.6666667 1
|
||||
-0.33333333 2.6666667 1
|
||||
0 2.6666667 1
|
||||
-1 3 1
|
||||
-0.66666667 3 1
|
||||
-0.33333333 3 1
|
||||
0 3 1
|
||||
0 1.5 0.25251263
|
||||
0.175 1.5 0.25251263
|
||||
0.35 1.5 0.25251263
|
||||
0 1.6237437 0.37625631
|
||||
0.175 1.6237437 0.37625631
|
||||
0.35 1.6237437 0.37625631
|
||||
0 1.7474874 0.5
|
||||
0.175 1.7474874 0.5
|
||||
0.35 1.7474874 0.5
|
||||
0 1.3762563 0.37625631
|
||||
0.175 1.3762563 0.37625631
|
||||
0.35 1.3762563 0.37625631
|
||||
0 1.5 0.5
|
||||
0.175 1.5 0.5
|
||||
0.35 1.5 0.5
|
||||
0 1.6237437 0.62374369
|
||||
0.175 1.6237437 0.62374369
|
||||
0.35 1.6237437 0.62374369
|
||||
0 1.2525126 0.5
|
||||
0.175 1.2525126 0.5
|
||||
0.35 1.2525126 0.5
|
||||
0 1.3762563 0.62374369
|
||||
0.175 1.3762563 0.62374369
|
||||
0.35 1.3762563 0.62374369
|
||||
0 1.5 0.74748737
|
||||
0.175 1.5 0.74748737
|
||||
0.35 1.5 0.74748737
|
||||
@@ -1,453 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
89
|
||||
1 5 0 1 5 4 40 41 45 44
|
||||
1 5 40 41 45 44 80 81 85 84
|
||||
1 5 44 45 49 48 84 85 89 88
|
||||
1 5 4 5 9 8 44 45 49 48
|
||||
1 5 5 6 10 9 45 46 50 49
|
||||
1 5 45 46 50 49 85 86 90 89
|
||||
1 5 41 42 46 45 81 82 86 85
|
||||
1 5 1 2 6 5 41 42 46 45
|
||||
1 5 2 3 7 6 42 43 47 46
|
||||
1 5 42 43 47 46 82 83 87 86
|
||||
1 5 6 7 11 10 46 47 51 50
|
||||
1 5 46 47 51 50 86 87 91 90
|
||||
1 5 86 87 91 90 126 127 131 130
|
||||
1 5 82 83 87 86 122 123 127 126
|
||||
1 5 81 82 86 85 121 122 126 125
|
||||
1 5 80 81 85 84 120 121 125 124
|
||||
1 5 84 85 89 88 124 125 129 128
|
||||
1 5 85 86 90 89 125 126 130 129
|
||||
1 5 89 90 94 93 129 130 134 133
|
||||
1 5 88 89 93 92 128 129 133 132
|
||||
1 5 92 93 97 96 132 133 137 136
|
||||
1 5 93 94 98 97 133 134 138 137
|
||||
1 5 94 95 99 98 134 135 139 138
|
||||
1 5 54 55 59 58 94 95 99 98
|
||||
1 5 90 91 95 94 130 131 135 134
|
||||
1 5 50 51 55 54 90 91 95 94
|
||||
1 5 10 11 15 14 50 51 55 54
|
||||
1 5 14 15 19 18 54 55 59 58
|
||||
1 5 13 14 18 17 53 54 58 57
|
||||
1 5 53 54 58 57 93 94 98 97
|
||||
1 5 49 50 54 53 89 90 94 93
|
||||
1 5 9 10 14 13 49 50 54 53
|
||||
1 5 8 9 13 12 48 49 53 52
|
||||
1 5 48 49 53 52 88 89 93 92
|
||||
1 5 52 53 57 56 92 93 97 96
|
||||
1 5 12 13 17 16 52 53 57 56
|
||||
1 5 16 17 21 20 56 57 61 60
|
||||
1 5 56 57 61 60 96 97 101 100
|
||||
1 5 57 58 62 61 97 98 102 101
|
||||
1 5 17 18 22 21 57 58 62 61
|
||||
1 5 18 19 23 22 58 59 63 62
|
||||
1 5 58 59 63 62 98 99 103 102
|
||||
1 5 98 99 103 102 138 139 143 142
|
||||
1 5 97 98 102 101 137 138 142 141
|
||||
1 5 96 97 101 100 136 137 141 140
|
||||
1 5 100 101 105 104 140 141 145 144
|
||||
1 5 101 102 106 105 141 142 146 145
|
||||
1 5 102 103 107 106 142 143 147 146
|
||||
1 5 62 63 67 66 102 103 107 106
|
||||
1 5 22 23 27 26 62 63 67 66
|
||||
1 5 21 22 26 25 61 62 66 65
|
||||
1 5 61 62 66 65 101 102 106 105
|
||||
1 5 60 61 65 64 100 101 105 104
|
||||
1 5 20 21 25 24 60 61 65 64
|
||||
1 5 24 25 29 28 64 65 69 68
|
||||
1 5 64 65 69 68 104 105 109 108
|
||||
1 5 68 69 73 72 108 109 113 112
|
||||
1 5 28 29 33 32 68 69 73 72
|
||||
1 5 29 30 34 33 69 70 74 73
|
||||
1 5 69 70 74 73 109 110 114 113
|
||||
1 5 65 66 70 69 105 106 110 109
|
||||
1 5 25 26 30 29 65 66 70 69
|
||||
1 5 26 27 31 30 66 67 71 70
|
||||
1 5 66 67 71 70 106 107 111 110
|
||||
1 5 30 31 35 34 70 71 75 74
|
||||
1 5 70 71 75 74 110 111 115 114
|
||||
1 5 110 111 115 114 150 151 155 154
|
||||
1 5 106 107 111 110 146 147 151 150
|
||||
1 5 105 106 110 109 145 146 150 149
|
||||
1 5 109 110 114 113 149 150 154 153
|
||||
1 5 104 105 109 108 144 145 149 148
|
||||
1 5 108 109 113 112 148 149 153 152
|
||||
1 5 112 113 117 116 152 153 157 156
|
||||
1 5 113 114 118 117 153 154 158 157
|
||||
1 5 114 115 119 118 154 155 159 158
|
||||
1 5 74 75 79 78 114 115 119 118
|
||||
1 5 34 35 39 38 74 75 79 78
|
||||
1 5 33 34 38 37 73 74 78 77
|
||||
1 5 73 74 78 77 113 114 118 117
|
||||
1 5 72 73 77 76 112 113 117 116
|
||||
1 5 32 33 37 36 72 73 77 76
|
||||
2 5 160 161 164 163 169 170 173 172
|
||||
2 5 163 164 167 166 172 173 176 175
|
||||
2 5 172 173 176 175 181 182 185 184
|
||||
2 5 169 170 173 172 178 179 182 181
|
||||
2 5 170 171 174 173 179 180 183 182
|
||||
2 5 173 174 177 176 182 183 186 185
|
||||
2 5 164 165 168 167 173 174 177 176
|
||||
2 5 161 162 165 164 170 171 174 173
|
||||
|
||||
boundary
|
||||
150
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 12 16 17 13
|
||||
1 3 13 17 18 14
|
||||
1 3 14 18 19 15
|
||||
1 3 16 20 21 17
|
||||
1 3 17 21 22 18
|
||||
1 3 18 22 23 19
|
||||
1 3 20 24 25 21
|
||||
1 3 21 25 26 22
|
||||
1 3 22 26 27 23
|
||||
1 3 24 28 29 25
|
||||
1 3 25 29 30 26
|
||||
1 3 26 30 31 27
|
||||
1 3 28 32 33 29
|
||||
1 3 29 33 34 30
|
||||
1 3 30 34 35 31
|
||||
1 3 32 36 37 33
|
||||
1 3 33 37 38 34
|
||||
1 3 34 38 39 35
|
||||
1 3 120 121 125 124
|
||||
1 3 121 122 126 125
|
||||
1 3 122 123 127 126
|
||||
1 3 124 125 129 128
|
||||
1 3 125 126 130 129
|
||||
1 3 126 127 131 130
|
||||
1 3 128 129 133 132
|
||||
1 3 129 130 134 133
|
||||
1 3 130 131 135 134
|
||||
1 3 132 133 137 136
|
||||
1 3 133 134 138 137
|
||||
1 3 134 135 139 138
|
||||
1 3 136 137 141 140
|
||||
1 3 137 138 142 141
|
||||
1 3 138 139 143 142
|
||||
1 3 140 141 145 144
|
||||
1 3 141 142 146 145
|
||||
1 3 142 143 147 146
|
||||
1 3 144 145 149 148
|
||||
1 3 145 146 150 149
|
||||
1 3 146 147 151 150
|
||||
1 3 148 149 153 152
|
||||
1 3 149 150 154 153
|
||||
1 3 150 151 155 154
|
||||
1 3 152 153 157 156
|
||||
1 3 153 154 158 157
|
||||
1 3 154 155 159 158
|
||||
2 3 0 40 44 4
|
||||
2 3 4 44 48 8
|
||||
2 3 8 48 52 12
|
||||
2 3 12 52 56 16
|
||||
2 3 16 56 60 20
|
||||
2 3 20 60 64 24
|
||||
2 3 24 64 68 28
|
||||
2 3 28 68 72 32
|
||||
2 3 32 72 76 36
|
||||
2 3 40 80 84 44
|
||||
2 3 44 84 88 48
|
||||
2 3 48 88 92 52
|
||||
2 3 52 92 96 56
|
||||
2 3 56 96 100 60
|
||||
2 3 60 100 104 64
|
||||
2 3 64 104 108 68
|
||||
2 3 68 108 112 72
|
||||
2 3 72 112 116 76
|
||||
2 3 80 120 124 84
|
||||
2 3 84 124 128 88
|
||||
2 3 88 128 132 92
|
||||
2 3 92 132 136 96
|
||||
2 3 96 136 140 100
|
||||
2 3 100 140 144 104
|
||||
2 3 104 144 148 108
|
||||
2 3 108 148 152 112
|
||||
2 3 112 152 156 116
|
||||
3 3 3 7 47 43
|
||||
3 3 7 11 51 47
|
||||
3 3 11 15 55 51
|
||||
3 3 15 19 59 55
|
||||
3 3 19 23 63 59
|
||||
3 3 23 27 67 63
|
||||
3 3 27 31 71 67
|
||||
3 3 31 35 75 71
|
||||
3 3 35 39 79 75
|
||||
3 3 43 47 87 83
|
||||
3 3 47 51 91 87
|
||||
3 3 51 55 95 91
|
||||
3 3 55 59 99 95
|
||||
3 3 59 63 103 99
|
||||
3 3 63 67 107 103
|
||||
3 3 67 71 111 107
|
||||
3 3 71 75 115 111
|
||||
3 3 75 79 119 115
|
||||
3 3 83 87 127 123
|
||||
3 3 87 91 131 127
|
||||
3 3 91 95 135 131
|
||||
3 3 95 99 139 135
|
||||
3 3 99 103 143 139
|
||||
3 3 103 107 147 143
|
||||
3 3 107 111 151 147
|
||||
3 3 111 115 155 151
|
||||
3 3 115 119 159 155
|
||||
1 3 0 1 41 40
|
||||
1 3 40 41 81 80
|
||||
1 3 80 81 121 120
|
||||
1 3 1 2 42 41
|
||||
1 3 41 42 82 81
|
||||
1 3 81 82 122 121
|
||||
1 3 2 3 43 42
|
||||
1 3 42 43 83 82
|
||||
1 3 82 83 123 122
|
||||
1 3 36 76 77 37
|
||||
1 3 76 116 117 77
|
||||
1 3 116 156 157 117
|
||||
1 3 37 77 78 38
|
||||
1 3 77 117 118 78
|
||||
1 3 117 157 158 118
|
||||
1 3 38 78 79 39
|
||||
1 3 78 118 119 79
|
||||
1 3 118 158 159 119
|
||||
5 3 160 163 164 161
|
||||
5 3 161 164 165 162
|
||||
5 3 163 166 167 164
|
||||
5 3 164 167 168 165
|
||||
5 3 178 179 182 181
|
||||
5 3 179 180 183 182
|
||||
5 3 181 182 185 184
|
||||
5 3 182 183 186 185
|
||||
4 3 160 169 172 163
|
||||
4 3 163 172 175 166
|
||||
4 3 169 178 181 172
|
||||
4 3 172 181 184 175
|
||||
6 3 162 165 174 171
|
||||
6 3 165 168 177 174
|
||||
6 3 171 174 183 180
|
||||
6 3 174 177 186 183
|
||||
5 3 160 161 170 169
|
||||
5 3 169 170 179 178
|
||||
5 3 161 162 171 170
|
||||
5 3 170 171 180 179
|
||||
5 3 166 175 176 167
|
||||
5 3 175 184 185 176
|
||||
5 3 167 176 177 168
|
||||
5 3 176 185 186 177
|
||||
|
||||
vertices
|
||||
187
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 1.3333333 0
|
||||
-0.66666667 1.3333333 0
|
||||
-0.33333333 1.3333333 0
|
||||
0 1.3333333 0
|
||||
-1 1.6666667 0
|
||||
-0.66666667 1.6666667 0
|
||||
-0.33333333 1.6666667 0
|
||||
0 1.6666667 0
|
||||
-1 2 0
|
||||
-0.66666667 2 0
|
||||
-0.33333333 2 0
|
||||
0 2 0
|
||||
-1 2.3333333 0
|
||||
-0.66666667 2.3333333 0
|
||||
-0.33333333 2.3333333 0
|
||||
0 2.3333333 0
|
||||
-1 2.6666667 0
|
||||
-0.66666667 2.6666667 0
|
||||
-0.33333333 2.6666667 0
|
||||
0 2.6666667 0
|
||||
-1 3 0
|
||||
-0.66666667 3 0
|
||||
-0.33333333 3 0
|
||||
0 3 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 1.3333333 0.33333333
|
||||
-0.66666667 1.3333333 0.33333333
|
||||
-0.33333333 1.3333333 0.33333333
|
||||
0 1.3333333 0.33333333
|
||||
-1 1.6666667 0.33333333
|
||||
-0.66666667 1.6666667 0.33333333
|
||||
-0.33333333 1.6666667 0.33333333
|
||||
0 1.6666667 0.33333333
|
||||
-1 2 0.33333333
|
||||
-0.66666667 2 0.33333333
|
||||
-0.33333333 2 0.33333333
|
||||
0 2 0.33333333
|
||||
-1 2.3333333 0.33333333
|
||||
-0.66666667 2.3333333 0.33333333
|
||||
-0.33333333 2.3333333 0.33333333
|
||||
0 2.3333333 0.33333333
|
||||
-1 2.6666667 0.33333333
|
||||
-0.66666667 2.6666667 0.33333333
|
||||
-0.33333333 2.6666667 0.33333333
|
||||
0 2.6666667 0.33333333
|
||||
-1 3 0.33333333
|
||||
-0.66666667 3 0.33333333
|
||||
-0.33333333 3 0.33333333
|
||||
0 3 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 1.3333333 0.66666667
|
||||
-0.66666667 1.3333333 0.66666667
|
||||
-0.33333333 1.3333333 0.66666667
|
||||
0 1.3333333 0.66666667
|
||||
-1 1.6666667 0.66666667
|
||||
-0.66666667 1.6666667 0.66666667
|
||||
-0.33333333 1.6666667 0.66666667
|
||||
0 1.6666667 0.66666667
|
||||
-1 2 0.66666667
|
||||
-0.66666667 2 0.66666667
|
||||
-0.33333333 2 0.66666667
|
||||
0 2 0.66666667
|
||||
-1 2.3333333 0.66666667
|
||||
-0.66666667 2.3333333 0.66666667
|
||||
-0.33333333 2.3333333 0.66666667
|
||||
0 2.3333333 0.66666667
|
||||
-1 2.6666667 0.66666667
|
||||
-0.66666667 2.6666667 0.66666667
|
||||
-0.33333333 2.6666667 0.66666667
|
||||
0 2.6666667 0.66666667
|
||||
-1 3 0.66666667
|
||||
-0.66666667 3 0.66666667
|
||||
-0.33333333 3 0.66666667
|
||||
0 3 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
-1 1.3333333 1
|
||||
-0.66666667 1.3333333 1
|
||||
-0.33333333 1.3333333 1
|
||||
0 1.3333333 1
|
||||
-1 1.6666667 1
|
||||
-0.66666667 1.6666667 1
|
||||
-0.33333333 1.6666667 1
|
||||
0 1.6666667 1
|
||||
-1 2 1
|
||||
-0.66666667 2 1
|
||||
-0.33333333 2 1
|
||||
0 2 1
|
||||
-1 2.3333333 1
|
||||
-0.66666667 2.3333333 1
|
||||
-0.33333333 2.3333333 1
|
||||
0 2.3333333 1
|
||||
-1 2.6666667 1
|
||||
-0.66666667 2.6666667 1
|
||||
-0.33333333 2.6666667 1
|
||||
0 2.6666667 1
|
||||
-1 3 1
|
||||
-0.66666667 3 1
|
||||
-0.33333333 3 1
|
||||
0 3 1
|
||||
0 0.83333333 0.25251263
|
||||
0.175 0.83333333 0.25251263
|
||||
0.35 0.83333333 0.25251263
|
||||
0 0.95707702 0.37625631
|
||||
0.175 0.95707702 0.37625631
|
||||
0.35 0.95707702 0.37625631
|
||||
0 1.0808207 0.5
|
||||
0.175 1.0808207 0.5
|
||||
0.35 1.0808207 0.5
|
||||
0 0.70958965 0.37625631
|
||||
0.175 0.70958965 0.37625631
|
||||
0.35 0.70958965 0.37625631
|
||||
0 0.83333333 0.5
|
||||
0.175 0.83333333 0.5
|
||||
0.35 0.83333333 0.5
|
||||
0 0.95707702 0.62374369
|
||||
0.175 0.95707702 0.62374369
|
||||
0.35 0.95707702 0.62374369
|
||||
0 0.58584596 0.5
|
||||
0.175 0.58584596 0.5
|
||||
0.35 0.58584596 0.5
|
||||
0 0.70958965 0.62374369
|
||||
0.175 0.70958965 0.62374369
|
||||
0.35 0.70958965 0.62374369
|
||||
0 0.83333333 0.74748737
|
||||
0.175 0.83333333 0.74748737
|
||||
0.35 0.83333333 0.74748737
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,231 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
# PRISM = 6
|
||||
# PYRAMID = 7
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
35
|
||||
1 5 0 1 5 4 16 17 21 20
|
||||
1 5 16 17 21 20 32 33 37 36
|
||||
1 5 17 18 22 21 33 34 38 37
|
||||
1 5 1 2 6 5 17 18 22 21
|
||||
1 5 5 6 10 9 21 22 26 25
|
||||
1 5 21 22 26 25 37 38 42 41
|
||||
1 5 20 21 25 24 36 37 41 40
|
||||
1 5 4 5 9 8 20 21 25 24
|
||||
1 5 8 9 13 12 24 25 29 28
|
||||
1 5 24 25 29 28 40 41 45 44
|
||||
1 5 9 10 14 13 25 26 30 29
|
||||
1 5 25 26 30 29 41 42 46 45
|
||||
1 5 41 42 46 45 57 58 62 61
|
||||
1 5 40 41 45 44 56 57 61 60
|
||||
1 5 36 37 41 40 52 53 57 56
|
||||
1 5 37 38 42 41 53 54 58 57
|
||||
1 5 32 33 37 36 48 49 53 52
|
||||
1 5 33 34 38 37 49 50 54 53
|
||||
1 5 34 35 39 38 50 51 55 54
|
||||
1 5 38 39 43 42 54 55 59 58
|
||||
1 5 42 43 47 46 58 59 63 62
|
||||
1 5 26 27 31 30 42 43 47 46
|
||||
1 5 10 11 15 14 26 27 31 30
|
||||
1 5 6 7 11 10 22 23 27 26
|
||||
1 5 22 23 27 26 38 39 43 42
|
||||
1 5 18 19 23 22 34 35 39 38
|
||||
1 5 2 3 7 6 18 19 23 22
|
||||
1 5 64 65 68 67 73 74 77 76
|
||||
1 5 67 68 71 70 76 77 80 79
|
||||
1 5 76 77 80 79 85 86 89 88
|
||||
1 5 73 74 77 76 82 83 86 85
|
||||
1 5 74 75 78 77 83 84 87 86
|
||||
1 5 77 78 81 80 86 87 90 89
|
||||
1 5 68 69 72 71 77 78 81 80
|
||||
1 5 65 66 69 68 74 75 78 77
|
||||
|
||||
boundary
|
||||
78
|
||||
1 3 0 4 5 1
|
||||
1 3 1 5 6 2
|
||||
1 3 2 6 7 3
|
||||
1 3 4 8 9 5
|
||||
1 3 5 9 10 6
|
||||
1 3 6 10 11 7
|
||||
1 3 8 12 13 9
|
||||
1 3 9 13 14 10
|
||||
1 3 10 14 15 11
|
||||
1 3 48 49 53 52
|
||||
1 3 49 50 54 53
|
||||
1 3 50 51 55 54
|
||||
1 3 52 53 57 56
|
||||
1 3 53 54 58 57
|
||||
1 3 54 55 59 58
|
||||
1 3 56 57 61 60
|
||||
1 3 57 58 62 61
|
||||
1 3 58 59 63 62
|
||||
2 3 0 16 20 4
|
||||
2 3 4 20 24 8
|
||||
2 3 8 24 28 12
|
||||
2 3 16 32 36 20
|
||||
2 3 20 36 40 24
|
||||
2 3 24 40 44 28
|
||||
2 3 32 48 52 36
|
||||
2 3 36 52 56 40
|
||||
2 3 40 56 60 44
|
||||
3 3 3 7 23 19
|
||||
3 3 7 11 27 23
|
||||
3 3 11 15 31 27
|
||||
3 3 19 23 39 35
|
||||
3 3 23 27 43 39
|
||||
3 3 27 31 47 43
|
||||
3 3 35 39 55 51
|
||||
3 3 39 43 59 55
|
||||
3 3 43 47 63 59
|
||||
1 3 0 1 17 16
|
||||
1 3 16 17 33 32
|
||||
1 3 32 33 49 48
|
||||
1 3 1 2 18 17
|
||||
1 3 17 18 34 33
|
||||
1 3 33 34 50 49
|
||||
1 3 2 3 19 18
|
||||
1 3 18 19 35 34
|
||||
1 3 34 35 51 50
|
||||
1 3 12 28 29 13
|
||||
1 3 28 44 45 29
|
||||
1 3 44 60 61 45
|
||||
1 3 13 29 30 14
|
||||
1 3 29 45 46 30
|
||||
1 3 45 61 62 46
|
||||
1 3 14 30 31 15
|
||||
1 3 30 46 47 31
|
||||
1 3 46 62 63 47
|
||||
5 3 64 67 68 65
|
||||
5 3 65 68 69 66
|
||||
5 3 67 70 71 68
|
||||
5 3 68 71 72 69
|
||||
5 3 82 83 86 85
|
||||
5 3 83 84 87 86
|
||||
5 3 85 86 89 88
|
||||
5 3 86 87 90 89
|
||||
4 3 64 73 76 67
|
||||
4 3 67 76 79 70
|
||||
4 3 73 82 85 76
|
||||
4 3 76 85 88 79
|
||||
6 3 66 69 78 75
|
||||
6 3 69 72 81 78
|
||||
6 3 75 78 87 84
|
||||
6 3 78 81 90 87
|
||||
5 3 64 65 74 73
|
||||
5 3 73 74 83 82
|
||||
5 3 65 66 75 74
|
||||
5 3 74 75 84 83
|
||||
5 3 70 79 80 71
|
||||
5 3 79 88 89 80
|
||||
5 3 71 80 81 72
|
||||
5 3 80 89 90 81
|
||||
|
||||
vertices
|
||||
91
|
||||
3
|
||||
-1 0 0
|
||||
-0.66666667 0 0
|
||||
-0.33333333 0 0
|
||||
0 0 0
|
||||
-1 0.33333333 0
|
||||
-0.66666667 0.33333333 0
|
||||
-0.33333333 0.33333333 0
|
||||
0 0.33333333 0
|
||||
-1 0.66666667 0
|
||||
-0.66666667 0.66666667 0
|
||||
-0.33333333 0.66666667 0
|
||||
0 0.66666667 0
|
||||
-1 1 0
|
||||
-0.66666667 1 0
|
||||
-0.33333333 1 0
|
||||
0 1 0
|
||||
-1 0 0.33333333
|
||||
-0.66666667 0 0.33333333
|
||||
-0.33333333 0 0.33333333
|
||||
0 0 0.33333333
|
||||
-1 0.33333333 0.33333333
|
||||
-0.66666667 0.33333333 0.33333333
|
||||
-0.33333333 0.33333333 0.33333333
|
||||
0 0.33333333 0.33333333
|
||||
-1 0.66666667 0.33333333
|
||||
-0.66666667 0.66666667 0.33333333
|
||||
-0.33333333 0.66666667 0.33333333
|
||||
0 0.66666667 0.33333333
|
||||
-1 1 0.33333333
|
||||
-0.66666667 1 0.33333333
|
||||
-0.33333333 1 0.33333333
|
||||
0 1 0.33333333
|
||||
-1 0 0.66666667
|
||||
-0.66666667 0 0.66666667
|
||||
-0.33333333 0 0.66666667
|
||||
0 0 0.66666667
|
||||
-1 0.33333333 0.66666667
|
||||
-0.66666667 0.33333333 0.66666667
|
||||
-0.33333333 0.33333333 0.66666667
|
||||
0 0.33333333 0.66666667
|
||||
-1 0.66666667 0.66666667
|
||||
-0.66666667 0.66666667 0.66666667
|
||||
-0.33333333 0.66666667 0.66666667
|
||||
0 0.66666667 0.66666667
|
||||
-1 1 0.66666667
|
||||
-0.66666667 1 0.66666667
|
||||
-0.33333333 1 0.66666667
|
||||
0 1 0.66666667
|
||||
-1 0 1
|
||||
-0.66666667 0 1
|
||||
-0.33333333 0 1
|
||||
0 0 1
|
||||
-1 0.33333333 1
|
||||
-0.66666667 0.33333333 1
|
||||
-0.33333333 0.33333333 1
|
||||
0 0.33333333 1
|
||||
-1 0.66666667 1
|
||||
-0.66666667 0.66666667 1
|
||||
-0.33333333 0.66666667 1
|
||||
0 0.66666667 1
|
||||
-1 1 1
|
||||
-0.66666667 1 1
|
||||
-0.33333333 1 1
|
||||
0 1 1
|
||||
0 0.5 0.14644661
|
||||
0.25 0.5 0.14644661
|
||||
0.5 0.5 0.14644661
|
||||
0 0.6767767 0.3232233
|
||||
0.25 0.6767767 0.3232233
|
||||
0.5 0.6767767 0.3232233
|
||||
0 0.85355339 0.5
|
||||
0.25 0.85355339 0.5
|
||||
0.5 0.85355339 0.5
|
||||
0 0.3232233 0.3232233
|
||||
0.25 0.3232233 0.3232233
|
||||
0.5 0.3232233 0.3232233
|
||||
0 0.5 0.5
|
||||
0.25 0.5 0.5
|
||||
0.5 0.5 0.5
|
||||
0 0.6767767 0.6767767
|
||||
0.25 0.6767767 0.6767767
|
||||
0.5 0.6767767 0.6767767
|
||||
0 0.14644661 0.5
|
||||
0.25 0.14644661 0.5
|
||||
0.5 0.14644661 0.5
|
||||
0 0.3232233 0.6767767
|
||||
0.25 0.3232233 0.6767767
|
||||
0.5 0.3232233 0.6767767
|
||||
0 0.5 0.85355339
|
||||
0.25 0.5 0.85355339
|
||||
0.5 0.5 0.85355339
|
||||
@@ -1,663 +0,0 @@
|
||||
#include "parproblems.hpp"
|
||||
|
||||
void ParElasticityProblem::Init()
|
||||
{
|
||||
int dim = pmesh->Dimension();
|
||||
fec = new H1_FECollection(order,dim);
|
||||
fes = new ParFiniteElementSpace(pmesh,fec,dim,Ordering::byVDIM);
|
||||
ndofs = fes->GetVSize();
|
||||
ntdofs = fes->GetTrueVSize();
|
||||
gndofs = fes->GlobalTrueVSize();
|
||||
pmesh->SetNodalFESpace(fes);
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
|
||||
}
|
||||
ess_bdr = 0;
|
||||
Array<int> ess_tdof_list_temp;
|
||||
for (int i = 0; i < ess_bdr_attr.Size(); i++ )
|
||||
{
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 1;
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list_temp,ess_bdr_attr_comp[i]);
|
||||
ess_tdof_list.Append(ess_tdof_list_temp);
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 0;
|
||||
}
|
||||
// Solution GridFunction
|
||||
x.SetSpace(fes); x = 0.0;
|
||||
// RHS
|
||||
b = new ParLinearForm(fes);
|
||||
|
||||
// Elasticity operator
|
||||
lambda.SetSize(pmesh->attributes.Max()); lambda = 57.6923076923;
|
||||
mu.SetSize(pmesh->attributes.Max()); mu = 38.4615384615;
|
||||
|
||||
lambda_cf.UpdateConstants(lambda);
|
||||
mu_cf.UpdateConstants(mu);
|
||||
|
||||
a = new ParBilinearForm(fes);
|
||||
a->AddDomainIntegrator(new ElasticityIntegrator(lambda_cf,mu_cf));
|
||||
}
|
||||
|
||||
void ParElasticityProblem::FormLinearSystem()
|
||||
{
|
||||
if (!formsystem)
|
||||
{
|
||||
formsystem = true;
|
||||
b->Assemble();
|
||||
a->Assemble();
|
||||
a->FormLinearSystem(ess_tdof_list, x, *b, A, X, B);
|
||||
}
|
||||
}
|
||||
|
||||
void ParElasticityProblem::UpdateLinearSystem()
|
||||
{
|
||||
UpdateStep();
|
||||
FormLinearSystem();
|
||||
}
|
||||
|
||||
// #ifdef MFEM_USE_TRIBOL
|
||||
|
||||
|
||||
|
||||
ParContactProblem::ParContactProblem(ParElasticityProblem * prob_,
|
||||
const std::set<int> & mortar_attrs_,
|
||||
const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_,
|
||||
bool doublepass_)
|
||||
: prob(prob_), mortar_attrs(mortar_attrs_), nonmortar_attrs(nonmortar_attrs_), doublepass(doublepass_), coords(coords_)
|
||||
{
|
||||
ParMesh* pmesh = prob->GetMesh();
|
||||
comm = pmesh->GetComm();
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &numprocs);
|
||||
|
||||
dim = pmesh->Dimension();
|
||||
nodes0.SetSpace(pmesh->GetNodes()->FESpace());
|
||||
nodes0 = *pmesh->GetNodes();
|
||||
nodes1 = pmesh->GetNodes();
|
||||
|
||||
prob->FormLinearSystem();
|
||||
K = new HypreParMatrix(prob->GetOperator());
|
||||
B = new Vector(prob->GetRHS());
|
||||
if (doublepass)
|
||||
{
|
||||
SetupTribolDoublePass();
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupTribol();
|
||||
}
|
||||
}
|
||||
|
||||
void ParContactProblem::SetupTribol()
|
||||
{
|
||||
axom::slic::SimpleLogger logger;
|
||||
axom::slic::setIsRoot(mfem::Mpi::Root());
|
||||
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id = 0;
|
||||
int mesh1_id = 0;
|
||||
int mesh2_id = 1;
|
||||
vfes = prob->GetFESpace();
|
||||
ParMesh * pmesh = prob->GetMesh();
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id, mesh1_id, mesh2_id,
|
||||
*pmesh, *coords, mortar_attrs, nonmortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure = tribol::getMfemPressure(coupling_scheme_id);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle = 1; // pseudo cycle
|
||||
double t = 1.0; // pseudo time
|
||||
double dt = 1.0; // pseudo dt
|
||||
tribol::update(cycle, t, dt);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk = tribol::getMfemBlockJacobian(coupling_scheme_id);
|
||||
|
||||
HypreParMatrix * Mfull = (HypreParMatrix *)(&A_blk->GetBlock(1,0));
|
||||
Mfull->EliminateCols(prob->GetEssentialDofs());
|
||||
int h = Mfull->Height();
|
||||
SparseMatrix merged;
|
||||
Mfull->MergeDiagAndOffd(merged);
|
||||
Array<int> nonzero_rows;
|
||||
for (int i = 0; i<h; i++)
|
||||
{
|
||||
if (!merged.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew = nonzero_rows.Size();
|
||||
SparseMatrix P(hnew,h);
|
||||
|
||||
for (int i = 0; i<hnew; i++)
|
||||
{
|
||||
int col = nonzero_rows[i];
|
||||
P.Set(i,col,1.0);
|
||||
}
|
||||
P.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged = Mult(P,merged);
|
||||
|
||||
int rows[2];
|
||||
int cols[2];
|
||||
cols[0] = Mfull->ColPart()[0];
|
||||
cols[1] = Mfull->ColPart()[1];
|
||||
int nrows = reduced_merged->Height();
|
||||
|
||||
int row_offset;
|
||||
MPI_Scan(&nrows,&row_offset,1,MPI_INT,MPI_SUM,Mfull->GetComm());
|
||||
|
||||
row_offset-=nrows;
|
||||
rows[0] = row_offset;
|
||||
rows[1] = row_offset+nrows;
|
||||
int glob_nrows;
|
||||
MPI_Allreduce(&nrows, &glob_nrows,1,MPI_INT,MPI_SUM,Mfull->GetComm());
|
||||
|
||||
|
||||
int glob_ncols = reduced_merged->Width();
|
||||
M = new HypreParMatrix(Mfull->GetComm(), nrows, glob_nrows,
|
||||
glob_ncols, reduced_merged->GetI(), reduced_merged->GetJ(),
|
||||
reduced_merged->GetData(), rows,cols);
|
||||
|
||||
Vector gap;
|
||||
tribol::getMfemGap(coupling_scheme_id, gap);
|
||||
auto& P_submesh = *pressure.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true;
|
||||
gap_true.SetSize(P_submesh.Width());
|
||||
P_submesh.MultTranspose(gap,gap_true);
|
||||
|
||||
gapv.SetSize(nrows);
|
||||
for (int i = 0; i<nrows; i++)
|
||||
{
|
||||
gapv[i] = gap_true[nonzero_rows[i]];
|
||||
}
|
||||
|
||||
constraints_starts.SetSize(2);
|
||||
constraints_starts[0] = M->RowPart()[0];
|
||||
constraints_starts[1] = M->RowPart()[1];
|
||||
|
||||
// find elast dofs in contact;
|
||||
HypreParMatrix * Jt = (HypreParMatrix *)(&A_blk->GetBlock(0,1));
|
||||
Jt->EliminateRows(prob->GetEssentialDofs());
|
||||
|
||||
int hJt = Jt->Height();
|
||||
SparseMatrix mergedJt;
|
||||
Jt->MergeDiagAndOffd(mergedJt);
|
||||
|
||||
Array<int> nonzerorows;
|
||||
Array<int> zerorows;
|
||||
for (int i = 0; i<hJt; i++)
|
||||
{
|
||||
if (!mergedJt.RowIsEmpty(i))
|
||||
{
|
||||
nonzerorows.Append(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
zerorows.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hb = nonzerorows.Size();
|
||||
SparseMatrix Pbt(hb,K->GetGlobalNumCols());
|
||||
|
||||
for (int i = 0; i<hb; i++)
|
||||
{
|
||||
int col = nonzerorows[i]+prob->GetFESpace()->GetMyTDofOffset();
|
||||
Pbt.Set(i,col,1.0);
|
||||
}
|
||||
Pbt.Finalize();
|
||||
|
||||
int rows_b[2];
|
||||
int cols_b[2];
|
||||
int nrows_b = Pbt.Height();
|
||||
|
||||
int row_offset_b;
|
||||
MPI_Scan(&nrows_b,&row_offset_b,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
row_offset_b-=nrows_b;
|
||||
rows_b[0] = row_offset_b;
|
||||
rows_b[1] = row_offset_b+nrows_b;
|
||||
cols_b[0] = K->ColPart()[0];
|
||||
cols_b[1] = K->ColPart()[1];
|
||||
int glob_nrows_b;
|
||||
int glob_ncols_b = K->GetGlobalNumCols();
|
||||
MPI_Allreduce(&nrows_b, &glob_nrows_b,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
HypreParMatrix * P_bt = new HypreParMatrix(MPI_COMM_WORLD, nrows_b, glob_nrows_b,
|
||||
glob_ncols_b, Pbt.GetI(), Pbt.GetJ(),
|
||||
Pbt.GetData(), rows_b,cols_b);
|
||||
|
||||
Pb = P_bt->Transpose();
|
||||
delete P_bt;
|
||||
|
||||
int hi = zerorows.Size();
|
||||
SparseMatrix Pit(hi,K->GetGlobalNumCols());
|
||||
|
||||
for (int i = 0; i<hi; i++)
|
||||
{
|
||||
int col = zerorows[i]+prob->GetFESpace()->GetMyTDofOffset();
|
||||
Pit.Set(i,col,1.0);
|
||||
}
|
||||
Pit.Finalize();
|
||||
|
||||
int rows_i[2];
|
||||
int cols_i[2];
|
||||
int nrows_i = Pit.Height();
|
||||
|
||||
int row_offset_i;
|
||||
MPI_Scan(&nrows_i,&row_offset_i,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
row_offset_i-=nrows_i;
|
||||
rows_i[0] = row_offset_i;
|
||||
rows_i[1] = row_offset_i+nrows_i;
|
||||
cols_i[0] = K->ColPart()[0];
|
||||
cols_i[1] = K->ColPart()[1];
|
||||
int glob_nrows_i;
|
||||
int glob_ncols_i = K->GetGlobalNumCols();
|
||||
MPI_Allreduce(&nrows_i, &glob_nrows_i,1,MPI_INT,MPI_SUM,MPI_COMM_WORLD);
|
||||
|
||||
HypreParMatrix * P_it = new HypreParMatrix(MPI_COMM_WORLD, nrows_i, glob_nrows_i,
|
||||
glob_ncols_i, Pit.GetI(), Pit.GetJ(),
|
||||
Pit.GetData(), rows_i,cols_i);
|
||||
|
||||
Pi = P_it->Transpose();
|
||||
delete P_it;
|
||||
}
|
||||
|
||||
void ParContactProblem::SetupTribolDoublePass()
|
||||
{
|
||||
axom::slic::SimpleLogger logger1;
|
||||
axom::slic::setIsRoot(mfem::Mpi::Root());
|
||||
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id1 = 0;
|
||||
int mesh1_id1 = 0;
|
||||
int mesh2_id1 = 1;
|
||||
vfes = prob->GetFESpace();
|
||||
ParGridFunction * coords1 = new ParGridFunction(vfes);
|
||||
ParMesh * pmesh1 = prob->GetMesh();
|
||||
pmesh1->SetNodalGridFunction(coords1);
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id1, mesh1_id1, mesh2_id1,
|
||||
*pmesh1, *coords1, mortar_attrs, nonmortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure1 = tribol::getMfemPressure(coupling_scheme_id1);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure1.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id1,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle1 = 1; // pseudo cycle
|
||||
double t1 = 1.0; // pseudo time
|
||||
double dt1 = 1.0; // pseudo dt
|
||||
tribol::update(cycle1, t1, dt1);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk1 = tribol::getMfemBlockJacobian(coupling_scheme_id1);
|
||||
|
||||
HypreParMatrix * Mfull1 = (HypreParMatrix *)(&A_blk1->GetBlock(1,0));
|
||||
Mfull1->EliminateCols(prob->GetEssentialDofs());
|
||||
int h1 = Mfull1->Height();
|
||||
SparseMatrix merged1;
|
||||
Mfull1->MergeDiagAndOffd(merged1);
|
||||
Array<int> nonzero_rows1;
|
||||
for (int i = 0; i<h1; i++)
|
||||
{
|
||||
if (!merged1.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows1.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew1 = nonzero_rows1.Size();
|
||||
SparseMatrix P1(hnew1,h1);
|
||||
|
||||
for (int i = 0; i<hnew1; i++)
|
||||
{
|
||||
int col = nonzero_rows1[i];
|
||||
P1.Set(i,col,1.0);
|
||||
}
|
||||
P1.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged1 = Mult(P1,merged1);
|
||||
|
||||
int rows1[2];
|
||||
int cols1[2];
|
||||
cols1[0] = Mfull1->ColPart()[0];
|
||||
cols1[1] = Mfull1->ColPart()[1];
|
||||
int nrows1 = reduced_merged1->Height();
|
||||
|
||||
int row_offset1;
|
||||
MPI_Scan(&nrows1,&row_offset1,1,MPI_INT,MPI_SUM,Mfull1->GetComm());
|
||||
|
||||
row_offset1-=nrows1;
|
||||
rows1[0] = row_offset1;
|
||||
rows1[1] = row_offset1+nrows1;
|
||||
int glob_nrows1;
|
||||
MPI_Allreduce(&nrows1, &glob_nrows1,1,MPI_INT,MPI_SUM,Mfull1->GetComm());
|
||||
|
||||
|
||||
int glob_ncols1 = reduced_merged1->Width();
|
||||
HypreParMatrix * M1 = new HypreParMatrix(Mfull1->GetComm(), nrows1, glob_nrows1,
|
||||
glob_ncols1, reduced_merged1->GetI(), reduced_merged1->GetJ(),
|
||||
reduced_merged1->GetData(), rows1,cols1);
|
||||
|
||||
Vector gap1;
|
||||
tribol::getMfemGap(coupling_scheme_id1, gap1);
|
||||
auto& P_submesh1 = *pressure1.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true1;
|
||||
gap_true1.SetSize(P_submesh1.Width());
|
||||
P_submesh1.MultTranspose(gap1,gap_true1);
|
||||
|
||||
tribol::finalize();
|
||||
|
||||
// ------------------------------
|
||||
// second pass
|
||||
// ------------------------------
|
||||
// Initialize Tribol contact library
|
||||
tribol::initialize(3, MPI_COMM_WORLD);
|
||||
|
||||
int coupling_scheme_id2 = 0;
|
||||
int mesh1_id2 = 0;
|
||||
int mesh2_id2 = 1;
|
||||
ParGridFunction * coords2 = new ParGridFunction(vfes);
|
||||
ParMesh * pmesh2 = prob->GetMesh();
|
||||
pmesh2->SetNodalGridFunction(coords2);
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id2, mesh1_id2, mesh2_id2,
|
||||
*pmesh2, *coords2, nonmortar_attrs, mortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_SLIDING,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// Access Tribol's pressure grid function (on the contact surface)
|
||||
auto& pressure2 = tribol::getMfemPressure(coupling_scheme_id2);
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of pressure unknowns: " <<
|
||||
pressure2.ParFESpace()->GlobalTrueVSize() << std::endl;
|
||||
}
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id2,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// Update contact mesh decomposition
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// Update contact gaps, forces, and tangent stiffness
|
||||
int cycle2 = 1; // pseudo cycle
|
||||
double t2 = 1.0; // pseudo time
|
||||
double dt2 = 1.0; // pseudo dt
|
||||
tribol::update(cycle2, t2, dt2);
|
||||
|
||||
// Return contact contribution to the tangent stiffness matrix
|
||||
auto A_blk2 = tribol::getMfemBlockJacobian(coupling_scheme_id2);
|
||||
|
||||
HypreParMatrix * Mfull2 = (HypreParMatrix *)(&A_blk2->GetBlock(1,0));
|
||||
Mfull2->EliminateCols(prob->GetEssentialDofs());
|
||||
int h2 = Mfull2->Height();
|
||||
SparseMatrix merged2;
|
||||
Mfull2->MergeDiagAndOffd(merged2);
|
||||
Array<int> nonzero_rows2;
|
||||
for (int i = 0; i<h2; i++)
|
||||
{
|
||||
if (!merged2.RowIsEmpty(i))
|
||||
{
|
||||
nonzero_rows2.Append(i);
|
||||
}
|
||||
}
|
||||
|
||||
int hnew2 = nonzero_rows2.Size();
|
||||
SparseMatrix P2(hnew2,h2);
|
||||
|
||||
for (int i = 0; i<hnew2; i++)
|
||||
{
|
||||
int col = nonzero_rows2[i];
|
||||
P2.Set(i,col,1.0);
|
||||
}
|
||||
P2.Finalize();
|
||||
|
||||
SparseMatrix * reduced_merged2 = Mult(P2,merged2);
|
||||
|
||||
int rows2[2];
|
||||
int cols2[2];
|
||||
cols2[0] = Mfull2->ColPart()[0];
|
||||
cols2[1] = Mfull2->ColPart()[1];
|
||||
int nrows2 = reduced_merged2->Height();
|
||||
|
||||
int row_offset2;
|
||||
MPI_Scan(&nrows2,&row_offset2,1,MPI_INT,MPI_SUM,Mfull2->GetComm());
|
||||
|
||||
row_offset2-=nrows2;
|
||||
rows2[0] = row_offset2;
|
||||
rows2[1] = row_offset2+nrows2;
|
||||
int glob_nrows2;
|
||||
MPI_Allreduce(&nrows2, &glob_nrows2,1,MPI_INT,MPI_SUM,Mfull2->GetComm());
|
||||
|
||||
|
||||
int glob_ncols2 = reduced_merged2->Width();
|
||||
HypreParMatrix * M2 = new HypreParMatrix(Mfull2->GetComm(), nrows2, glob_nrows2,
|
||||
glob_ncols2, reduced_merged2->GetI(), reduced_merged2->GetJ(),
|
||||
reduced_merged2->GetData(), rows2,cols2);
|
||||
|
||||
Vector gap2;
|
||||
tribol::getMfemGap(coupling_scheme_id2, gap2);
|
||||
auto& P_submesh2 = *pressure2.ParFESpace()->GetProlongationMatrix();
|
||||
Vector gap_true2;
|
||||
gap_true2.SetSize(P_submesh2.Width());
|
||||
P_submesh2.MultTranspose(gap2,gap_true2);
|
||||
|
||||
tribol::finalize();
|
||||
|
||||
|
||||
gapv.SetSize(nrows1+nrows2);
|
||||
for (int i = 0; i<nrows1; i++)
|
||||
{
|
||||
gapv[i] = gap_true1[nonzero_rows1[i]];
|
||||
}
|
||||
for (int i = 0; i<nrows2; i++)
|
||||
{
|
||||
gapv[nrows1+i] = gap_true2[nonzero_rows2[i]];
|
||||
}
|
||||
|
||||
Array2D<HypreParMatrix *> A_array(2,1);
|
||||
A_array(0,0) = M1;
|
||||
A_array(1,0) = M2;
|
||||
|
||||
M = HypreParMatrixFromBlocks(A_array);
|
||||
|
||||
constraints_starts.SetSize(2);
|
||||
constraints_starts[0] = M->RowPart()[0];
|
||||
constraints_starts[1] = M->RowPart()[1];
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
double ParContactProblem::E(const Vector & d)
|
||||
{
|
||||
Vector kd(K->Height());
|
||||
K->Mult(d,kd);
|
||||
return 0.5 * InnerProduct(comm,d, kd) - InnerProduct(comm,d, *B);
|
||||
}
|
||||
|
||||
void ParContactProblem::DdE(const Vector &d, Vector &gradE)
|
||||
{
|
||||
gradE.SetSize(K->Height());
|
||||
K->Mult(d, gradE);
|
||||
gradE.Add(-1.0, *B);
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::DddE(const Vector &d)
|
||||
{
|
||||
return K;
|
||||
}
|
||||
|
||||
void ParContactProblem::g(const Vector &d, Vector &gd)
|
||||
{
|
||||
gd = GetGapFunction();
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::Ddg(const Vector &d)
|
||||
{
|
||||
return GetJacobian();
|
||||
}
|
||||
|
||||
HypreParMatrix* ParContactProblem::lDddg(const Vector &d, const Vector &l)
|
||||
{
|
||||
return nullptr; // for now
|
||||
}
|
||||
|
||||
|
||||
QPOptParContactProblem::QPOptParContactProblem(ParContactProblem * problem_, Vector &xref_)
|
||||
: problem(problem_)
|
||||
{
|
||||
dimU = problem->GetNumDofs();
|
||||
dimM = problem->GetNumConstraints();
|
||||
dimC = problem->GetNumConstraints();
|
||||
ml.SetSize(dimM); ml = 0.0;
|
||||
Vector negone(dimM); negone = -1.0;
|
||||
SparseMatrix diag(negone);
|
||||
|
||||
xref.SetSize(xref_.Size());
|
||||
xref.Set(1.0, xref_);
|
||||
|
||||
int gsize = problem->GetGlobalNumConstraints();
|
||||
int * rows = problem->GetConstraintsStarts().GetData();
|
||||
|
||||
NegId = new HypreParMatrix(problem->GetComm(),gsize, rows,&diag);
|
||||
HypreStealOwnership(*NegId, diag);
|
||||
}
|
||||
|
||||
int QPOptParContactProblem::GetDimU() { return dimU; }
|
||||
|
||||
int QPOptParContactProblem::GetDimM() { return dimM; }
|
||||
|
||||
int QPOptParContactProblem::GetDimC() { return dimC; }
|
||||
|
||||
Vector & QPOptParContactProblem::Getml() { return ml; }
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Duuf(const BlockVector & x)
|
||||
{
|
||||
return problem->DddE(x.GetBlock(0));
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dumf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmuf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmmf(const BlockVector & x)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Duc(const BlockVector & x)
|
||||
{
|
||||
return problem->Ddg(x.GetBlock(0));
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::Dmc(const BlockVector & x)
|
||||
{
|
||||
return NegId;
|
||||
}
|
||||
|
||||
HypreParMatrix * QPOptParContactProblem::lDuuc(const BlockVector & x, const Vector & l)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void QPOptParContactProblem::c(const BlockVector &x, Vector & y)
|
||||
{
|
||||
Vector g0; // g(dref)
|
||||
problem->g(x.GetBlock(0), g0); // gap function
|
||||
|
||||
// temp = d - xref (expansion)
|
||||
Vector temp(x.GetBlock(0).Size()); temp = 0.0;
|
||||
temp.Set(1.0, x.GetBlock(0));
|
||||
temp.Add(-1.0, xref); // displacement at previous time step
|
||||
|
||||
problem->GetJacobian()->Mult(temp, y); // J * (d - xref)
|
||||
y.Add(1.0, g0); // J * (d - xref) + g0
|
||||
y.Add(-1.0, x.GetBlock(1)); // J * (d - xref) + g0 - s
|
||||
}
|
||||
|
||||
double QPOptParContactProblem::CalcObjective(const BlockVector & x)
|
||||
{
|
||||
return problem->E(x.GetBlock(0));
|
||||
}
|
||||
|
||||
void QPOptParContactProblem::CalcObjectiveGrad(const BlockVector & x, BlockVector & y)
|
||||
{
|
||||
problem->DdE(x.GetBlock(0), y.GetBlock(0));
|
||||
y.GetBlock(1) = 0.0;
|
||||
}
|
||||
|
||||
QPOptParContactProblem::~QPOptParContactProblem()
|
||||
{
|
||||
delete NegId;
|
||||
}
|
||||
|
||||
// #endif
|
||||
@@ -1,335 +0,0 @@
|
||||
|
||||
#include "parproblems_util.hpp"
|
||||
|
||||
class ParElasticityProblem
|
||||
{
|
||||
private:
|
||||
MPI_Comm comm;
|
||||
bool formsystem = false;
|
||||
ParMesh * pmesh = nullptr;
|
||||
Array<int> ess_bdr_attr, ess_bdr_attr_comp;
|
||||
int order;
|
||||
int ndofs;
|
||||
int ntdofs;
|
||||
int gndofs;
|
||||
FiniteElementCollection * fec = nullptr;
|
||||
ParFiniteElementSpace * fes = nullptr;
|
||||
Vector lambda, mu;
|
||||
PWConstCoefficient lambda_cf, mu_cf;
|
||||
Array<int> ess_bdr, ess_tdof_list;
|
||||
ParBilinearForm * a = nullptr;
|
||||
ParLinearForm * b = nullptr;
|
||||
ParGridFunction x;
|
||||
HypreParMatrix A;
|
||||
Vector B,X;
|
||||
ConstantCoefficient pressure_cf;
|
||||
VectorArrayCoefficient * bf = nullptr;
|
||||
void Init();
|
||||
bool own_mesh;
|
||||
public:
|
||||
ParElasticityProblem(MPI_Comm comm_, const char *mesh_file , int sref, int pref,
|
||||
Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_,
|
||||
int order_ = 1 )
|
||||
: comm(comm_), ess_bdr_attr(ess_bdr_attr_),ess_bdr_attr_comp(ess_bdr_attr_comp_), order(order_)
|
||||
{
|
||||
own_mesh = true;
|
||||
Mesh * mesh = new Mesh(mesh_file,1,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
pmesh = new ParMesh(comm,*mesh);
|
||||
MFEM_VERIFY(pmesh->GetNE(), "ParElasticityProblem::Empty partition");
|
||||
delete mesh;
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
ParElasticityProblem(ParMesh * pmesh_, Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_, int order_ = 1)
|
||||
: pmesh(pmesh_), ess_bdr_attr(ess_bdr_attr_), ess_bdr_attr_comp(ess_bdr_attr_comp_), order(order_)
|
||||
{
|
||||
own_mesh = false;
|
||||
comm = pmesh->GetComm();
|
||||
Init();
|
||||
}
|
||||
|
||||
ParMesh * GetMesh() { return pmesh; }
|
||||
ParFiniteElementSpace * GetFESpace() { return fes; }
|
||||
FiniteElementCollection * GetFECol() { return fec; }
|
||||
int GetNumDofs() { return ndofs; }
|
||||
int GetNumTDofs() { return ntdofs; }
|
||||
int GetGlobalNumDofs() { return gndofs; }
|
||||
HypreParMatrix & GetOperator()
|
||||
{
|
||||
MFEM_VERIFY(formsystem, "System not formed yet. Call FormLinearSystem()");
|
||||
return A;
|
||||
}
|
||||
Vector & GetRHS()
|
||||
{
|
||||
MFEM_VERIFY(formsystem, "System not formed yet. Call FormLinearSystem()");
|
||||
return B;
|
||||
}
|
||||
|
||||
void SetLambda(const Vector & lambda_)
|
||||
{
|
||||
lambda = lambda_;
|
||||
lambda_cf.UpdateConstants(lambda);
|
||||
}
|
||||
void SetMu(const Vector & mu_)
|
||||
{
|
||||
mu = mu_;
|
||||
mu_cf.UpdateConstants(mu);
|
||||
}
|
||||
|
||||
void SetNeumanPressureData(ConstantCoefficient &f, Array<int> & bdr_marker)
|
||||
{
|
||||
pressure_cf.constant = f.constant;
|
||||
b->AddBoundaryIntegrator(new VectorBoundaryFluxLFIntegrator(pressure_cf),bdr_marker);
|
||||
}
|
||||
|
||||
void SetNeumanData(int comp, int bdrattr, double value)
|
||||
{
|
||||
int dim = pmesh->Dimension();
|
||||
bf = new VectorArrayCoefficient(dim);
|
||||
for (int i = 0; i < dim; i++)
|
||||
{
|
||||
if (i == comp)
|
||||
{
|
||||
Vector pull_force(pmesh->bdr_attributes.Max());
|
||||
pull_force = 0.0;
|
||||
pull_force(bdrattr-1) = value;
|
||||
bf->Set(i, new PWConstCoefficient(pull_force));
|
||||
}
|
||||
else
|
||||
{
|
||||
bf->Set(i, new ConstantCoefficient(0.0));
|
||||
}
|
||||
}
|
||||
b->AddBoundaryIntegrator(new VectorBoundaryLFIntegrator(*bf));
|
||||
}
|
||||
|
||||
void UpdateEssentialBC(Array<int> & ess_bdr_attr_, Array<int> & ess_bdr_attr_comp_)
|
||||
{
|
||||
ess_bdr_attr = ess_bdr_attr_;
|
||||
ess_bdr_attr_comp = ess_bdr_attr_comp_;
|
||||
ess_tdof_list.SetSize(0);
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
|
||||
}
|
||||
ess_bdr = 0;
|
||||
Array<int> ess_tdof_list_temp;
|
||||
for (int i = 0; i < ess_bdr_attr.Size(); i++ )
|
||||
{
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 1;
|
||||
fes->GetEssentialTrueDofs(ess_bdr,ess_tdof_list_temp,ess_bdr_attr_comp[i]);
|
||||
ess_tdof_list.Append(ess_tdof_list_temp);
|
||||
ess_bdr[ess_bdr_attr[i]-1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateStep()
|
||||
{
|
||||
if (formsystem)
|
||||
{
|
||||
delete b;
|
||||
b = new ParLinearForm(fes);
|
||||
delete a;
|
||||
a = new ParBilinearForm(fes);
|
||||
a->AddDomainIntegrator(new ElasticityIntegrator(lambda_cf,mu_cf));
|
||||
|
||||
|
||||
// a->Update();
|
||||
formsystem = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FormLinearSystem();
|
||||
void UpdateLinearSystem();
|
||||
|
||||
void SetDisplacementDirichletData(const Vector & delta)
|
||||
{
|
||||
VectorConstantCoefficient delta_cf(delta);
|
||||
x.ProjectBdrCoefficient(delta_cf,ess_bdr);
|
||||
bool vis = false;
|
||||
if (vis)
|
||||
{
|
||||
int myid, num_procs;
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *pmesh << x << std::flush;
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
};
|
||||
|
||||
void ResetDisplacementDirichletData()
|
||||
{
|
||||
x = 0.0;
|
||||
}
|
||||
|
||||
void SetDisplacementDirichletData(const Vector & delta, Array<int> essbdr)
|
||||
{
|
||||
VectorConstantCoefficient delta_cf(delta);
|
||||
x.ProjectBdrCoefficient(delta_cf,essbdr);
|
||||
bool vis = false;
|
||||
if (vis)
|
||||
{
|
||||
int myid, num_procs;
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
socketstream sol_sock(vishost, visport);
|
||||
sol_sock << "parallel " << num_procs << " " << myid << "\n";
|
||||
sol_sock.precision(8);
|
||||
sol_sock << "solution\n" << *pmesh << x << std::flush;
|
||||
MFEM_ABORT("");
|
||||
}
|
||||
};
|
||||
|
||||
ParGridFunction & GetDisplacementGridFunction() {return x;};
|
||||
Array<int> & GetEssentialDofs() {return ess_tdof_list;};
|
||||
|
||||
~ParElasticityProblem()
|
||||
{
|
||||
delete a;
|
||||
delete b;
|
||||
delete fes;
|
||||
delete fec;
|
||||
if (own_mesh)
|
||||
{
|
||||
delete pmesh;
|
||||
}
|
||||
delete bf;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// #ifdef MFEM_USE_TRIBOL
|
||||
|
||||
class ParContactProblem
|
||||
{
|
||||
private:
|
||||
MPI_Comm comm;
|
||||
int numprocs;
|
||||
int myid;
|
||||
ParElasticityProblem * prob = nullptr;
|
||||
ParFiniteElementSpace * vfes = nullptr;
|
||||
int dim;
|
||||
GridFunction nodes0;
|
||||
GridFunction *nodes1 = nullptr;
|
||||
std::set<int> contact_vertices;
|
||||
std::vector<int> dof_offsets;
|
||||
std::vector<int> vertex_offsets;
|
||||
std::vector<int> constraints_offsets;
|
||||
Array<int> tdof_offsets;
|
||||
Array<int> constraints_starts;
|
||||
Array<int> globalvertices;
|
||||
Array<int> vertices;
|
||||
ParGridFunction * coords = nullptr;
|
||||
//ParGridFunction * xref = nullptr;
|
||||
|
||||
protected:
|
||||
int npoints=0;
|
||||
int gnpoints=0;
|
||||
int nv, gnv;
|
||||
HypreParMatrix * K = nullptr;
|
||||
HypreParMatrix * Pi = nullptr;
|
||||
HypreParMatrix * Pb = nullptr;
|
||||
Vector *B = nullptr;
|
||||
Vector gapv;
|
||||
HypreParMatrix * M=nullptr;
|
||||
void SetupTribol();
|
||||
void SetupTribolDoublePass();
|
||||
std::set<int> mortar_attrs;
|
||||
// plane of top block
|
||||
std::set<int> nonmortar_attrs;
|
||||
bool doublepass = false;
|
||||
|
||||
public:
|
||||
ParContactProblem(ParElasticityProblem * prob_,
|
||||
const std::set<int> & mortar_attrs_, const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_,
|
||||
bool doublepass = false);
|
||||
|
||||
ParElasticityProblem * GetElasticityProblem() {return prob;}
|
||||
MPI_Comm GetComm() {return comm;}
|
||||
int GetNumDofs() {return K->Height();}
|
||||
int GetGlobalNumDofs() {return K->GetGlobalNumRows();}
|
||||
int GetNumConstraints() {return M->Height();}
|
||||
int GetGlobalNumConstraints() { return M->GetGlobalNumRows(); }
|
||||
|
||||
std::vector<int> & GetDofOffets() { return dof_offsets; }
|
||||
std::vector<int> & GetVertexOffsets() { return vertex_offsets; }
|
||||
std::vector<int> & GetConstraintsOffsets() { return constraints_offsets; }
|
||||
Array<int> & GetConstraintsStarts() { return constraints_starts; }
|
||||
|
||||
Vector & GetGapFunction() {return gapv;}
|
||||
|
||||
HypreParMatrix * GetJacobian() {return M;}
|
||||
|
||||
double E(const Vector & d);
|
||||
void DdE(const Vector &d, Vector &gradE);
|
||||
HypreParMatrix* DddE(const Vector &d);
|
||||
void g(const Vector &d, Vector &gd);
|
||||
HypreParMatrix* Ddg(const Vector &d);
|
||||
HypreParMatrix* lDddg(const Vector &d, const Vector &l);
|
||||
|
||||
HypreParMatrix * GetRestrictionToInteriorDofs() {return Pi;}
|
||||
HypreParMatrix * GetRestrictionToContactDofs() {return Pb;}
|
||||
|
||||
~ParContactProblem()
|
||||
{
|
||||
delete B;
|
||||
delete K;
|
||||
delete M;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class QPOptParContactProblem
|
||||
{
|
||||
private:
|
||||
ParContactProblem * problem = nullptr;
|
||||
int dimU, dimM, dimC;
|
||||
Vector ml;
|
||||
HypreParMatrix * NegId = nullptr;
|
||||
Vector xref;
|
||||
public:
|
||||
QPOptParContactProblem(ParContactProblem * problem_, Vector & xref_);
|
||||
int GetDimU();
|
||||
int GetDimM();
|
||||
int GetDimC();
|
||||
Vector & Getml();
|
||||
MPI_Comm GetComm() {return problem->GetComm();}
|
||||
int * GetConstraintsStarts() {return problem->GetConstraintsStarts().GetData();}
|
||||
int GetGlobalNumConstraints() {return problem->GetGlobalNumConstraints();}
|
||||
|
||||
ParElasticityProblem * GetElasticityProblem() {return problem->GetElasticityProblem();}
|
||||
|
||||
HypreParMatrix * Duuf(const BlockVector &);
|
||||
HypreParMatrix * Dumf(const BlockVector &);
|
||||
HypreParMatrix * Dmuf(const BlockVector &);
|
||||
HypreParMatrix * Dmmf(const BlockVector &);
|
||||
HypreParMatrix * Duc(const BlockVector &);
|
||||
HypreParMatrix * Dmc(const BlockVector &);
|
||||
HypreParMatrix * lDuuc(const BlockVector &, const Vector &);
|
||||
|
||||
HypreParMatrix * GetRestrictionToInteriorDofs() {return problem->GetRestrictionToInteriorDofs();}
|
||||
HypreParMatrix * GetRestrictionToContactDofs() {return problem->GetRestrictionToContactDofs();}
|
||||
|
||||
void c(const BlockVector &, Vector &);
|
||||
double CalcObjective(const BlockVector &);
|
||||
void CalcObjectiveGrad(const BlockVector &, BlockVector &);
|
||||
~QPOptParContactProblem();
|
||||
};
|
||||
|
||||
// #endif
|
||||
@@ -1,115 +0,0 @@
|
||||
#include "parproblems_util.hpp"
|
||||
|
||||
int get_rank(int tdof, std::vector<int> & tdof_offsets)
|
||||
{
|
||||
int size = tdof_offsets.size();
|
||||
if (size == 1) { return 0; }
|
||||
std::vector<int>::iterator up;
|
||||
up=std::upper_bound(tdof_offsets.begin(), tdof_offsets.end(),tdof); //
|
||||
return std::distance(tdof_offsets.begin(),up)-1;
|
||||
}
|
||||
|
||||
void ComputeTdofOffsets(const ParFiniteElementSpace * pfes,
|
||||
std::vector<int> & tdof_offsets)
|
||||
{
|
||||
MPI_Comm comm = pfes->GetComm();
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm, &num_procs);
|
||||
tdof_offsets.resize(num_procs);
|
||||
int mytoffset = pfes->GetMyTDofOffset();
|
||||
MPI_Allgather(&mytoffset,1,MPI_INT,&tdof_offsets[0],1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
void ComputeTdofOffsets(MPI_Comm comm, int mytoffset, std::vector<int> & tdof_offsets)
|
||||
{
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm,&num_procs);
|
||||
tdof_offsets.resize(num_procs);
|
||||
MPI_Allgather(&mytoffset,1,MPI_INT,&tdof_offsets[0],1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
void ComputeTdofs(MPI_Comm comm, int mytoffs, std::vector<int> & tdofs)
|
||||
{
|
||||
int num_procs;
|
||||
MPI_Comm_size(comm,&num_procs);
|
||||
tdofs.resize(num_procs);
|
||||
MPI_Allgather(&mytoffs,1,MPI_INT,&tdofs,1,MPI_INT,comm);
|
||||
}
|
||||
|
||||
|
||||
// Performs Pᵀ * A * P for BlockOperator P (with blocks as HypreParMatrices)
|
||||
// and A a HypreParMatrix, i.e., this handles the special case
|
||||
// where P = [P₁ P₂ ⋅⋅⋅ Pₙ]
|
||||
// C = Pᵀ * A * P
|
||||
void RAP(const HypreParMatrix & A, const BlockOperator & P,
|
||||
BlockOperator & C)
|
||||
{
|
||||
int nblocks = P.NumColBlocks();
|
||||
|
||||
const HypreParMatrix * Pi = nullptr;
|
||||
const HypreParMatrix * Pj = nullptr;
|
||||
HypreParMatrix * PitAPj = nullptr;
|
||||
|
||||
for (int i = 0; i< nblocks; i++)
|
||||
{
|
||||
if (P.IsZeroBlock(0,i)) continue;
|
||||
Pi = dynamic_cast<const HypreParMatrix*>(&P.GetBlock(0,i));
|
||||
for (int j = 0; j<nblocks; j++)
|
||||
{
|
||||
if (P.IsZeroBlock(0,j)) continue;
|
||||
Pj = dynamic_cast<const HypreParMatrix*>(&P.GetBlock(0,j));
|
||||
if (i == j)
|
||||
{
|
||||
PitAPj = RAP(&A, Pj);
|
||||
}
|
||||
else
|
||||
{
|
||||
PitAPj = RAP(Pi, &A, Pj);
|
||||
}
|
||||
C.SetBlock(i,j,PitAPj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParAdd(const BlockOperator & A, const BlockOperator & B, BlockOperator & C)
|
||||
{
|
||||
int n = A.NumRowBlocks();
|
||||
int m = A.NumColBlocks();
|
||||
MFEM_VERIFY(B.NumRowBlocks() == n, "Inconsistent number of row blocks");
|
||||
MFEM_VERIFY(B.NumColBlocks() == m, "Inconsistent number of column blocks");
|
||||
|
||||
const HypreParMatrix * a;
|
||||
const HypreParMatrix * b;
|
||||
for (int i = 0; i<n; i++)
|
||||
{
|
||||
for (int j = 0; j<m; j++)
|
||||
{
|
||||
a = nullptr;
|
||||
b = nullptr;
|
||||
if (!A.IsZeroBlock(i,j))
|
||||
{
|
||||
a = dynamic_cast<const HypreParMatrix*>(&A.GetBlock(i,j));
|
||||
}
|
||||
if (!B.IsZeroBlock(i,j))
|
||||
{
|
||||
b = dynamic_cast<const HypreParMatrix*>(&B.GetBlock(i,j));
|
||||
}
|
||||
if (a && b)
|
||||
{
|
||||
C.SetBlock(i,j,ParAdd(a,b));
|
||||
}
|
||||
else if (a)
|
||||
{
|
||||
C.SetBlock(i,j,new HypreParMatrix(*a));
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
C.SetBlock(i,j,new HypreParMatrix(*b));
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
#include "mfem.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
#include "axom/slic.hpp"
|
||||
|
||||
#include "tribol/interface/tribol.hpp"
|
||||
#include "tribol/interface/mfem_tribol.hpp"
|
||||
int get_rank(int tdof, std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofOffsets(const ParFiniteElementSpace * pfes,
|
||||
std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofOffsets(MPI_Comm comm, int mytoffset, std::vector<int> & tdof_offsets);
|
||||
void ComputeTdofs(MPI_Comm comm, int mytoffs, std::vector<int> & tdofs);
|
||||
|
||||
|
||||
// Performs Pᵀ * A * P for BlockOperator P (with blocks as HypreParMatrices)
|
||||
// and A a HypreParMatrix, i.e., this handles the special case
|
||||
// where P = [P₁ P₂ ⋅⋅⋅ Pₙ]
|
||||
void RAP(const HypreParMatrix & A, const BlockOperator & P, BlockOperator & C);
|
||||
void ParAdd(const BlockOperator & A, const BlockOperator & B, BlockOperator & C);
|
||||
@@ -1,564 +0,0 @@
|
||||
// Parallel contact example
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 1 -testno 4
|
||||
// CG iteration numbers = 105 114 116 115 113 109 113 108 107 114 206 236 268 435 987
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 5
|
||||
// CG iteration numbers = 106 116 116 116 115 113 107 107 128 131 531 1437 1318
|
||||
|
||||
// mpirun -np 4 ./contact -ls 2 -sr 0 -testno 6
|
||||
// CG iteration numbers = 18 18 18 18 18 17 17 21 22 46 52 53
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "ipsolver/ParIPsolver.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Mpi::Init();
|
||||
int myid = Mpi::WorldRank();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
Hypre::Init();
|
||||
|
||||
int order = 1;
|
||||
int sref = 1;
|
||||
int pref = 0;
|
||||
Array<int> attr;
|
||||
Array<int> m_attr;
|
||||
bool visualization = true;
|
||||
bool paraview = false;
|
||||
bool elast = false;
|
||||
bool nocontact = false;
|
||||
int testNo = -1; // 0-6
|
||||
// 1. Parse command-line options.
|
||||
OptionsParser args(argc, argv);
|
||||
args.AddOption(&testNo, "-testno", "--test-number",
|
||||
"Choice of test problem:"
|
||||
"-1: default (original 2 block problem)"
|
||||
"0: not implemented yet"
|
||||
"1: not implemented yet"
|
||||
"2: not implemented yet"
|
||||
"3: not implemented yet"
|
||||
"4: two block problem - diablo"
|
||||
"41: two block problem - twisted"
|
||||
"5: ironing problem"
|
||||
"51: ironing problem extended"
|
||||
"6: nested spheres problem");
|
||||
args.AddOption(&attr, "-at", "--attributes-surf",
|
||||
"Attributes of boundary faces on contact surface for mesh 2.");
|
||||
args.AddOption(&sref, "-sr", "--serial-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&pref, "-pr", "--parallel-refinements",
|
||||
"Number of uniform refinements.");
|
||||
args.AddOption(&elast, "-elast", "--elast", "-no-elast",
|
||||
"--no-elast",
|
||||
"Enable or disable AMG Elasticity options.");
|
||||
args.AddOption(&nocontact, "-nocontact", "--nocontact", "-no-nocontact",
|
||||
"--no-nocontact",
|
||||
"Enable or disable AMG solve with no contact for testing.");
|
||||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||||
"--no-visualization",
|
||||
"Enable or disable GLVis visualization.");
|
||||
args.AddOption(¶view, "-paraview", "--paraview", "-no-paraview",
|
||||
"--no-paraview",
|
||||
"Enable or disable ParaView visualization.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintUsage(cout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (myid == 0)
|
||||
{
|
||||
args.PrintOptions(cout);
|
||||
}
|
||||
|
||||
if (Mpi::Root())
|
||||
{
|
||||
mfem::out << "Solving test problem number: " << testNo << endl;
|
||||
}
|
||||
|
||||
const char *mesh_file = nullptr;
|
||||
|
||||
switch (testNo)
|
||||
{
|
||||
case -1:
|
||||
mesh_file = "meshes/two-block.mesh";
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
MFEM_ABORT("Problem not implemented yet");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
mesh_file = "meshes/Test4.mesh";
|
||||
break;
|
||||
case 40:
|
||||
mesh_file = "meshes/Test40.mesh";
|
||||
break;
|
||||
case 41:
|
||||
mesh_file = "meshes/Test41.mesh";
|
||||
break;
|
||||
case 42:
|
||||
mesh_file = "meshes/Test42.mesh";
|
||||
break;
|
||||
case 5:
|
||||
mesh_file = "meshes/Test5.mesh";
|
||||
break;
|
||||
case 51:
|
||||
mesh_file = "meshes/Test51.mesh";
|
||||
break;
|
||||
case 6:
|
||||
mesh_file = "meshes/Test6.mesh";
|
||||
break;
|
||||
case 61:
|
||||
// Something wrong with this mesh
|
||||
mesh_file = "meshes/Test61.mesh";
|
||||
break;
|
||||
case 62:
|
||||
mesh_file = "meshes/Test62.mesh";
|
||||
break;
|
||||
default:
|
||||
MFEM_ABORT("Should be unreachable");
|
||||
break;
|
||||
}
|
||||
|
||||
Mesh * mesh = new Mesh(mesh_file,1);
|
||||
for (int i = 0; i<sref; i++)
|
||||
{
|
||||
mesh->UniformRefinement();
|
||||
}
|
||||
|
||||
ParMesh * pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
|
||||
|
||||
for (int i = 0; i<pref; i++)
|
||||
{
|
||||
pmesh->UniformRefinement();
|
||||
}
|
||||
|
||||
Array<int> ess_bdr_attr;
|
||||
Array<int> ess_bdr_attr_comp;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(1);
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(2);
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 62)
|
||||
{
|
||||
ess_bdr_attr.Append(4); ess_bdr_attr_comp.Append(0);
|
||||
ess_bdr_attr.Append(5); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else if (testNo == 40)
|
||||
{
|
||||
ess_bdr_attr.Append(1); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(10); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_bdr_attr.Append(2); ess_bdr_attr_comp.Append(-1);
|
||||
ess_bdr_attr.Append(6); ess_bdr_attr_comp.Append(-1);
|
||||
}
|
||||
ParElasticityProblem * prob = new ParElasticityProblem(pmesh,
|
||||
ess_bdr_attr,ess_bdr_attr_comp,
|
||||
order);
|
||||
Vector lambda(prob->GetMesh()->attributes.Max());
|
||||
Vector mu(prob->GetMesh()->attributes.Max());
|
||||
|
||||
if (testNo == -1 )
|
||||
{
|
||||
lambda = 57.6923076923;
|
||||
mu = 38.4615384615;
|
||||
}
|
||||
else if (testNo == 6 || testNo == 61 || testNo == 62)
|
||||
{
|
||||
lambda = (1000*0.3)/(1.3*0.4);
|
||||
mu = 500/(1.3);
|
||||
}
|
||||
else
|
||||
{
|
||||
lambda[0] = 0.499/(1.499*0.002);
|
||||
lambda[1] = 0.0;
|
||||
mu[0] = 1./(2*1.499);
|
||||
mu[1] = 500;
|
||||
}
|
||||
|
||||
prob->SetLambda(lambda); prob->SetMu(mu);
|
||||
|
||||
int dim = pmesh->Dimension();
|
||||
Vector ess_values(dim);
|
||||
int essbdr_attr;
|
||||
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
||||
|
||||
ess_values = 0.0;
|
||||
|
||||
|
||||
// ConstantCoefficient one(-area);
|
||||
ConstantCoefficient one(-1.0);
|
||||
|
||||
std::set<int> mortar_attr;
|
||||
std::set<int> nonmortar_attr;
|
||||
|
||||
int nsteps = 100;
|
||||
if (testNo == 6 || testNo == 61)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[0] = 1;
|
||||
ess_bdr[1] = 1;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else if(testNo == 62)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_bdr = 0;
|
||||
ess_bdr[3] = 1;
|
||||
ess_bdr[4] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
// prob->SetNeumanPressureData(one,ess_bdr);
|
||||
prob->SetNeumanData(0,3,-2.0);
|
||||
mortar_attr.insert(6);
|
||||
mortar_attr.insert(9);
|
||||
nonmortar_attr.insert(7);
|
||||
nonmortar_attr.insert(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (testNo == -1 || testNo == 41)
|
||||
{
|
||||
ess_values[0] = 0.1/nsteps;
|
||||
}
|
||||
else
|
||||
{
|
||||
ess_values[2] = 1.0/1.4/nsteps;
|
||||
// ess_values[0] = -2.0/nsteps;
|
||||
}
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = (testNo == 40) ? 10 : 6;
|
||||
ess_values = 0.0; ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
// prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
if (testNo == 40)
|
||||
{
|
||||
mortar_attr.insert(4);
|
||||
nonmortar_attr.insert(7);
|
||||
}
|
||||
else
|
||||
{
|
||||
mortar_attr.insert(3);
|
||||
nonmortar_attr.insert(4);
|
||||
}
|
||||
}
|
||||
|
||||
ParFiniteElementSpace * fes = prob->GetFESpace();
|
||||
ParGridFunction x_gf(fes); x_gf = 0.0;
|
||||
ParGridFunction xnew(fes); xnew = 0.0;
|
||||
ParaViewDataCollection * paraview_dc = nullptr;
|
||||
ParMesh pmesh_copy(*pmesh);
|
||||
ParFiniteElementSpace fes_copy(*fes,pmesh_copy);
|
||||
ParGridFunction xcopy_gf(&fes_copy); xcopy_gf = 0.0;
|
||||
|
||||
if (paraview)
|
||||
{
|
||||
std::ostringstream paraview_file_name;
|
||||
paraview_file_name << "QPContact-Test_" << testNo
|
||||
<< "_par_ref_" << pref
|
||||
<< "_ser_ref_" << sref;
|
||||
paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &pmesh_copy);
|
||||
paraview_dc->SetPrefixPath("ParaView");
|
||||
paraview_dc->SetLevelsOfDetail(1);
|
||||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc->SetHighOrderOutput(true);
|
||||
// paraview_dc->RegisterField("u", &x_gf);
|
||||
paraview_dc->RegisterField("u", &xcopy_gf);
|
||||
paraview_dc->SetCycle(0);
|
||||
paraview_dc->SetTime(double(0));
|
||||
paraview_dc->Save();
|
||||
}
|
||||
socketstream sol_sock;
|
||||
if (visualization)
|
||||
{
|
||||
char vishost[] = "localhost";
|
||||
int visport = 19916;
|
||||
sol_sock.open(vishost, visport);
|
||||
sol_sock.precision(8);
|
||||
}
|
||||
|
||||
|
||||
ParGridFunction ref_coords(prob->GetFESpace());
|
||||
ParGridFunction new_coords(prob->GetFESpace());
|
||||
pmesh->GetNodes(new_coords);
|
||||
pmesh->GetNodes(ref_coords);
|
||||
|
||||
Vector xref(x_gf.GetTrueVector().Size());
|
||||
|
||||
double p = 1;
|
||||
ConstantCoefficient f(p);
|
||||
|
||||
double pseudotime = 1.0 / ((double) nsteps);
|
||||
if (testNo == 6)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
ess_bdr[2] = 1;
|
||||
f.constant = -p * pseudotime;
|
||||
prob->SetNeumanPressureData(f,ess_bdr);
|
||||
// prob->SetNeumanData(0,3,-p*(i+1)/nsteps);
|
||||
}
|
||||
else if (testNo == 4 || testNo == 40 || testNo == 5 || testNo == 51)
|
||||
{
|
||||
ess_bdr = 0;
|
||||
essbdr_attr = (testNo == 40) ? 1 : 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
ess_values = 0.0;
|
||||
//ess_values[2] = 4.0 / 7.0 * pseudotime;
|
||||
ess_values[2] = 1.0/1.4 * pseudotime;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
else if (testNo == 41)
|
||||
{
|
||||
ess_values = 0.0;
|
||||
ess_values[0] = 0.5 * pseudotime; //0.5/nsteps*(i+1);
|
||||
// ess_values[0] = 0.0;
|
||||
essbdr_attr = 2;
|
||||
ess_bdr[essbdr_attr-1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
essbdr_attr = 6;
|
||||
ess_values = 0.0;
|
||||
// ess_values[0] = -0.5/nsteps*(i+1);
|
||||
if (myid == 0)
|
||||
{
|
||||
mfem::out << "ess_values[0] = " << ess_values[0] << endl;
|
||||
}
|
||||
ess_bdr = 0; ess_bdr[essbdr_attr - 1] = 1;
|
||||
prob->SetDisplacementDirichletData(ess_values, ess_bdr);
|
||||
}
|
||||
|
||||
|
||||
/* ------- finite difference check -------- */
|
||||
Vector x0(fes->GetTrueVSize()); x0 = 0.0;
|
||||
//x0 = 2.0;
|
||||
//x0.Randomize(); x0 *= 1.e-2;
|
||||
Array<int> vdofs;
|
||||
for (int i = 0; i < pmesh->GetNE(); i++)
|
||||
{
|
||||
cout << "attribute = " << pmesh->GetAttribute(i) << endl;
|
||||
if (pmesh->GetAttribute(i) == 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
for (int j = 0; j < vdofs.Size(); j++)
|
||||
{
|
||||
x0(vdofs[j]) = 0.01;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
x_gf.SetFromTrueDofs(x0);
|
||||
add(ref_coords, x_gf, new_coords);
|
||||
|
||||
Vector x1(fes->GetTrueVSize()); x1 = 0.0;
|
||||
Vector xdir(fes->GetTrueVSize()); xdir.Randomize();
|
||||
Vector temp(fes->GetTrueVSize()); temp = 0.0;
|
||||
xdir *= 1.e-2; // scale so as to avoid mesh tangling
|
||||
double eps = 1.0;
|
||||
|
||||
ParContactProblem ref_contact(prob, mortar_attr, nonmortar_attr, &new_coords);
|
||||
int ndofs = ref_contact.GetNumDofs();
|
||||
int nconstraints = ref_contact.GetNumConstraints();
|
||||
Vector g0 = ref_contact.GetGapFunction();
|
||||
g0.Print();
|
||||
HypreParMatrix * J0 = ref_contact.GetJacobian();
|
||||
|
||||
//for (int i = 0; i < 30; i++)
|
||||
//{
|
||||
// x1.Set(1.0, x0); // x1 = x0 + eps * xdir
|
||||
// x1.Add(eps, xdir);
|
||||
// x_gf.SetFromTrueDofs(x1);
|
||||
// add(ref_coords, x_gf, new_coords);
|
||||
// ParContactProblem new_contact(prob, mortar_attr, nonmortar_attr, &new_coords);
|
||||
// Vector g1 = new_contact.GetGapFunction(); // g1 = g(x0 + eps * xdir)
|
||||
// Vector fd_err(g1.Size());
|
||||
|
||||
// // ||J0 * xdir - (g1 - g0) / eps||
|
||||
// J0->Mult(xdir, fd_err);
|
||||
// fd_err.Add(-1.0 / eps, g1);
|
||||
// fd_err.Add(1.0 / eps, g0);
|
||||
// cout << "fd err = " << fd_err.Norml2() << ", eps = " << eps << endl;
|
||||
// eps /= 2.0;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
//for (int i = 0; i < 30; i++)
|
||||
//{
|
||||
//// add(ref_coords,x_gf,new_coords);
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
//for (int i = 0; i < nsteps; i++)
|
||||
//{
|
||||
// //pseudotime = ((double) (i) / ((double) SQPrepeat) + 1.) / ((double) nsteps);
|
||||
// pseudotime = ((double) (i)) / ((double) nsteps);
|
||||
// for (int j = 0; j < SQPrepeat; j++)
|
||||
// {
|
||||
// paraview_time = pseudotime + j * paraview_subtimestep;
|
||||
|
||||
// //xref.Set(1.0, new_coords.GetTrueVector());
|
||||
// //xref.Add(-1.0, ref_coords.GetTrueVector());
|
||||
// xref.Set(1.0, x_gf.GetTrueVector());
|
||||
// ParContactProblem contact(prob, mortar_attr, nonmortar_attr, &new_coords, doublepass);
|
||||
// QPOptParContactProblem qpopt(&contact, xref);
|
||||
// int numconstr = contact.GetGlobalNumConstraints();
|
||||
// ParInteriorPointSolver optimizer(&qpopt);
|
||||
// optimizer.SetTol(optimizer_tol);
|
||||
// optimizer.SetMaxIter(optimizer_maxit);
|
||||
// optimizer.SetLinearSolver(linsolver);
|
||||
// optimizer.SetLinearSolveRelTol(linsolverrtol);
|
||||
// optimizer.SetLinearSolveAbsTol(linsolveratol);
|
||||
// optimizer.SetLinearSolveRelaxType(relax_type);
|
||||
// if (nocontact)
|
||||
// {
|
||||
// optimizer.EnableNoContactSolve();
|
||||
// }
|
||||
// if (elast)
|
||||
// {
|
||||
// optimizer.SetElasticityOptions(prob->GetFESpace());
|
||||
// }
|
||||
// // ParGridFunction x = prob->GetDisplacementGridFunction();
|
||||
// // x.SetTrueVector();
|
||||
// // Vector x0 = x.GetTrueVector();
|
||||
|
||||
// x_gf.SetTrueVector();
|
||||
// Vector x0 = x_gf.GetTrueVector();
|
||||
// int ndofs = x0.Size();
|
||||
// Vector xf(ndofs); xf = 0.0;
|
||||
// optimizer.Mult(x0, xf);
|
||||
// QPConverged = optimizer.GetConverged();
|
||||
// MFEM_VERIFY(QPConverged, "IPM not converged on QP contact problem");
|
||||
// //optimizer.SaveLambda(i);
|
||||
// //optimizer.SaveZl(i);
|
||||
// Vector xf_copy(xf);
|
||||
// xf_copy+=x0;
|
||||
// double Einitial = contact.E(x0);
|
||||
// // double Efinal = contact.E(xf);
|
||||
// double Efinal = contact.E(xf_copy);
|
||||
// Array<int> & CGiterations = optimizer.GetCGIterNumbers();
|
||||
// int gndofs = prob->GetGlobalNumDofs();
|
||||
// //dgdu = contact.Ddg(xf_copy);
|
||||
// //std::ostringstream dgdu_file_name;
|
||||
// //dgdu_file_name << "Jacobians/J" << i;
|
||||
// //dgdu->Print(dgdu_file_name.str().c_str());
|
||||
// if (Mpi::Root())
|
||||
// {
|
||||
// mfem::out << endl;
|
||||
// mfem::out << " Initial Energy objective = " << Einitial << endl;
|
||||
// mfem::out << " Final Energy objective = " << Efinal << endl;
|
||||
// mfem::out << " Global number of dofs = " << gndofs << endl;
|
||||
// mfem::out << " Global number of constraints = " << numconstr << endl;
|
||||
// mfem::out << " Optimizer number of iterations = " <<
|
||||
// optimizer.GetNumIterations() << endl;
|
||||
// if (linsolver == 2 || linsolver == 3 || linsolver == 4)
|
||||
// {
|
||||
// mfem::out << " CG iteration numbers = " ;
|
||||
// CGiterations.Print(mfem::out, CGiterations.Size());
|
||||
// }
|
||||
// if (nocontact)
|
||||
// {
|
||||
// Array<int> & CGNoContactIterations = optimizer.GetCGNoContactIterNumbers();
|
||||
// mfem::out << " CG no Contact iteration numbers = " ;
|
||||
// CGNoContactIterations.Print(mfem::out, CGNoContactIterations.Size());
|
||||
// }
|
||||
// if (outputfiles)
|
||||
// {
|
||||
// ostringstream file_name;
|
||||
// file_name << "output/Testno-"<<testNo<<"-ref-"<<sref+pref << "-step-" << i;
|
||||
// OutputData(file_name, Einitial, Efinal, gndofs,numconstr, optimizer.GetNumIterations(), CGiterations);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Vector X_new(xf.GetData(),fes->GetTrueVSize());
|
||||
// // xnew.SetFromTrueDofs(X_new);
|
||||
// // x_gf = xnew;
|
||||
// x_gf.SetFromTrueDofs(xf);
|
||||
// // mfem::out << "x_gf norm = " << x_gf.Norml2() << endl;
|
||||
// // cin.get();
|
||||
// // pmesh->MoveNodes(xnew);
|
||||
// // pmesh_copy.MoveNodes(xnew);
|
||||
// // pmesh_copy.MoveNodes(xnew);
|
||||
// add(ref_coords,x_gf,new_coords);
|
||||
// // mfem::out << " ref_coords norm " << ref_coords.Norml2() << endl;
|
||||
// // mfem::out << " x_gf norm " << x_gf.Norml2() << endl;
|
||||
// // mfem::out << " new_coords norm " << new_coords.Norml2() << endl;
|
||||
// // pmesh_copy.SetNodes(new_coords);
|
||||
// pmesh_copy.SetNodes(new_coords);
|
||||
// xcopy_gf = x_gf;
|
||||
// // pmesh_copy.MoveNodes(x_gf);
|
||||
// // pmesh_copy.SetNodes(x_gf);
|
||||
// if (paraview && ((i+1) % paraview_plot_every == 0 ))
|
||||
// {
|
||||
// paraview_cycle += 1;
|
||||
// paraview_dc->SetCycle(paraview_cycle) ;
|
||||
// paraview_dc->SetTime(paraview_time);
|
||||
// paraview_dc->Save();
|
||||
// }
|
||||
|
||||
// if (visualization)
|
||||
// {
|
||||
// sol_sock << "parallel " << num_procs << " " << myid << "\n"
|
||||
// << "solution\n" << pmesh_copy << x_gf << flush;
|
||||
//
|
||||
// if (i == nsteps - 1 && j == SQPrepeat - 1)
|
||||
// {
|
||||
// pmesh->MoveNodes(x_gf);
|
||||
// char vishost[] = "localhost";
|
||||
// int visport = 19916;
|
||||
// socketstream sol_sock1(vishost, visport);
|
||||
// sol_sock1 << "parallel " << num_procs << " " << myid << "\n";
|
||||
// sol_sock1.precision(8);
|
||||
// sol_sock1 << "solution\n" << *pmesh << x_gf << flush;
|
||||
// }
|
||||
// }
|
||||
// if (i == nsteps - 1 && j == SQPrepeat) break;
|
||||
|
||||
// prob->UpdateStep();
|
||||
// if (testNo == 6 )
|
||||
// {
|
||||
// double area_new = GetBdrArea(3,*pmesh);
|
||||
// if (myid == 0)
|
||||
// {
|
||||
// mfem::out << "New area = " << area_new << endl;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
delete prob;
|
||||
delete pmesh;
|
||||
delete mesh;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,453 +0,0 @@
|
||||
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
|
||||
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
||||
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
||||
//
|
||||
// This file is part of the MFEM library. For more information and source code
|
||||
// availability visit https://mfem.org.
|
||||
//
|
||||
// MFEM is free software; you can redistribute it and/or modify it under the
|
||||
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
||||
// CONTRIBUTING.md for details.
|
||||
//
|
||||
// -----------------------------------------
|
||||
// Tribol Miniapp: Mortar contact patch test
|
||||
// -----------------------------------------
|
||||
//
|
||||
//
|
||||
// Command line options:
|
||||
// - -r, --refine: number of uniform refinements of the mesh (default: 2)
|
||||
//
|
||||
|
||||
#include "mfem.hpp"
|
||||
|
||||
#include "axom/slic.hpp"
|
||||
|
||||
#include "tribol/interface/tribol.hpp"
|
||||
#include "tribol/interface/mfem_tribol.hpp"
|
||||
|
||||
// Define MPI_REAL_T
|
||||
#if defined(MFEM_USE_DOUBLE)
|
||||
#define MPI_REAL_T MPI_DOUBLE
|
||||
#else
|
||||
#error "Tribol requires MFEM built with double precision!"
|
||||
#endif
|
||||
|
||||
|
||||
using namespace mfem;
|
||||
|
||||
class ContactObj
|
||||
{
|
||||
protected:
|
||||
HypreParMatrix * Jacobian = nullptr;
|
||||
mfem::Vector gap;
|
||||
std::unique_ptr<mfem::BlockOperator> A_blk;
|
||||
ParMesh * mesh = nullptr;
|
||||
ParGridFunction * coords = nullptr;
|
||||
std::set<int> mortar_attrs;
|
||||
std::set<int> nonmortar_attrs;
|
||||
public:
|
||||
ContactObj(ParMesh * mesh_,
|
||||
const std::set<int> & mortar_attrs_,
|
||||
const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_);
|
||||
void GetGap(mfem::Vector & g) const;
|
||||
mfem::HypreParMatrix * GetJacobian() const;
|
||||
virtual ~ContactObj();
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Initialize MPI
|
||||
mfem::Mpi::Init();
|
||||
|
||||
// Initialize logging with axom::slic
|
||||
axom::slic::SimpleLogger logger;
|
||||
axom::slic::setIsRoot(mfem::Mpi::Root());
|
||||
|
||||
// Define command line options
|
||||
int ref_levels = 2; // number of times to uniformly refine the serial mesh
|
||||
double u0shift = 0.0;
|
||||
bool outputfiles = false;
|
||||
// Parse command line options
|
||||
mfem::OptionsParser args(argc, argv);
|
||||
args.AddOption(&ref_levels, "-r", "--refine",
|
||||
"Number of times to refine the mesh uniformly.");
|
||||
args.AddOption(&u0shift, "-u0shift", "--u0shift", "magnitude (inf norm) of random displacement where finite difference test is evaluated");
|
||||
args.AddOption(&outputfiles, "-out", "--output", "-no-out",
|
||||
"--no-ouput",
|
||||
"Enable or disable ouput to files.");
|
||||
args.Parse();
|
||||
if (!args.Good())
|
||||
{
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
args.PrintUsage(std::cout);
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
args.PrintOptions(std::cout);
|
||||
}
|
||||
|
||||
// Fixed options
|
||||
// two block mesh; bottom block = [0,1]^3 and top block = [0,1]x[0,1]x[0.99,1.99]
|
||||
std::string mesh_file = "modified-two-hex.mesh";
|
||||
// Problem dimension (NOTE: Tribol's mortar only works in 3D)
|
||||
constexpr int dim = 3;
|
||||
// FE polynomial degree (NOTE: only 1 works for now)
|
||||
constexpr int order = 1;
|
||||
// z=1 plane of bottom block (contact plane)
|
||||
std::set<int> mortar_attrs({4});
|
||||
// z=0.99 plane of top block (contact plane)
|
||||
std::set<int> nonmortar_attrs({5});
|
||||
// per-dimension sets of boundary attributes with homogeneous Dirichlet BCs.
|
||||
// allows transverse deformation of the blocks while precluding rigid body
|
||||
// rotations/translations.
|
||||
std::vector<std::set<int>> fixed_attrs(dim);
|
||||
fixed_attrs[0] = {1}; // x=0 plane of both blocks
|
||||
fixed_attrs[1] = {2}; // y=0 plane of both blocks
|
||||
fixed_attrs[2] = {3, 6}; // 3: z=0 plane of bottom block; 6: z=1.99 plane of top block
|
||||
|
||||
// Read the mesh, refine, and create a mfem::ParMesh
|
||||
mfem::Mesh serial_mesh(mesh_file);
|
||||
for (int i = 0; i < ref_levels; ++i)
|
||||
{
|
||||
serial_mesh.UniformRefinement();
|
||||
}
|
||||
mfem::ParMesh mesh(MPI_COMM_WORLD, serial_mesh);
|
||||
mfem::ParMesh mesh_copy(mesh);
|
||||
|
||||
serial_mesh.Clear();
|
||||
|
||||
MFEM_ASSERT(dim == mesh.Dimension(),
|
||||
"This miniapp must be run with the supplied two-hex.mesh file.");
|
||||
|
||||
// Create an H1 finite element space on the mesh for displacements/forces
|
||||
mfem::H1_FECollection fec(order, dim);
|
||||
mfem::ParFiniteElementSpace fespace(&mesh, &fec, dim);
|
||||
auto n_displacement_dofs = fespace.GlobalTrueVSize();
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "Number of displacement unknowns: " << n_displacement_dofs <<
|
||||
std::endl;
|
||||
}
|
||||
|
||||
// Create coordinate and displacement grid functions
|
||||
mfem::ParGridFunction coords(&fespace);
|
||||
mesh.SetNodalGridFunction(&coords);
|
||||
mfem::ParGridFunction displacement(&fespace);
|
||||
displacement = 0.0;
|
||||
|
||||
// Find true dofs with homogeneous Dirichlet BCs
|
||||
mfem::Array<int> ess_tdof_list;
|
||||
{
|
||||
mfem::Array<int> ess_vdof_marker(fespace.GetVSize());
|
||||
ess_vdof_marker = 0;
|
||||
for (int i = 0; i < dim; ++i)
|
||||
{
|
||||
mfem::Array<int> ess_bdr(mesh.bdr_attributes.Max());
|
||||
ess_bdr = 0;
|
||||
for (auto xfixed_attr : fixed_attrs[i])
|
||||
{
|
||||
ess_bdr[xfixed_attr-1] = 1;
|
||||
}
|
||||
mfem::Array<int> new_ess_vdof_marker;
|
||||
fespace.GetEssentialVDofs(ess_bdr, new_ess_vdof_marker, i);
|
||||
for (int j = 0; j < new_ess_vdof_marker.Size(); ++j)
|
||||
{
|
||||
ess_vdof_marker[j] = ess_vdof_marker[j] || new_ess_vdof_marker[j];
|
||||
}
|
||||
}
|
||||
mfem::Array<int> ess_tdof_marker;
|
||||
fespace.GetRestrictionMatrix()->BooleanMult(ess_vdof_marker, ess_tdof_marker);
|
||||
mfem::FiniteElementSpace::MarkerToList(ess_tdof_marker, ess_tdof_list);
|
||||
}
|
||||
|
||||
// #1: Initialize Tribol contact library
|
||||
tribol::initialize(dim, MPI_COMM_WORLD);
|
||||
|
||||
|
||||
/* Begin Tucker addition
|
||||
* finite difference check of the gap function Jacobian at u = u0
|
||||
* we evaluate the norm of the finite difference residual
|
||||
* err(eps) = || (g(u0 + eps * udir) - g(u0)) / eps - J(u0) * udir ||_2
|
||||
* which in the absence of finite-precision
|
||||
* err(eps) = O(eps) when the gap is not linear
|
||||
* err(eps) = 0, when the gap is linear
|
||||
*/
|
||||
int dimU = fespace.GetTrueVSize();
|
||||
Vector u0(dimU); u0 = 0.0;
|
||||
Vector u1(dimU); u1 = 0.0;
|
||||
Vector udir(dimU); udir = 0.0; udir.Randomize(); udir *= 1.e-2;
|
||||
|
||||
Array<int> vdofs;
|
||||
for (int i = 0; i < mesh.GetNBE(); i++)
|
||||
{
|
||||
const int attr = (mesh.GetBdrElement(i))->GetAttribute();
|
||||
if (attr == 4)
|
||||
{
|
||||
fespace.GetBdrElementVDofs(i, vdofs);
|
||||
for (int j = 0; j < vdofs.Size(); j++)
|
||||
{
|
||||
if (j / 4 == 2)
|
||||
{
|
||||
u0(vdofs[j]) = -1.0 * u0shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ParGridFunction new_coords(&fespace);
|
||||
mesh.GetNodes(new_coords);
|
||||
|
||||
// evaluate the gap and gap Jacobian at u = u0
|
||||
u1.Set(1.0, u0);
|
||||
displacement.SetFromTrueDofs(u1);
|
||||
add(coords, displacement, new_coords);
|
||||
|
||||
ContactObj contact0(&mesh, mortar_attrs, nonmortar_attrs, &new_coords);
|
||||
HypreParMatrix * J0 = contact0.GetJacobian();
|
||||
int dimG = J0->Height();
|
||||
|
||||
Vector g0(dimG); g0 = 0.0; contact0.GetGap(g0);
|
||||
Vector g1(dimG); g1 = 0.0;
|
||||
|
||||
// finite difference residual
|
||||
Vector fdres(dimG); fdres = 0.0;
|
||||
|
||||
// J0udir = J(u0) * udir
|
||||
Vector J0udir(dimG); J0->Mult(udir, J0udir);
|
||||
|
||||
// output various configurations
|
||||
// to visualize u = u0, u = u0 + eps * udir
|
||||
// use linear adjustment for eps here
|
||||
std::ostringstream paraview_file_name;
|
||||
paraview_file_name << "BlockConfigurations_ref_" << ref_levels << "shift" << u0shift;
|
||||
ParaViewDataCollection * paraview_dc = new ParaViewDataCollection(paraview_file_name.str(), &mesh_copy);
|
||||
paraview_dc->SetPrefixPath("ParaView");
|
||||
paraview_dc->SetLevelsOfDetail(1);
|
||||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||||
paraview_dc->SetHighOrderOutput(true);
|
||||
paraview_dc->SetCycle(0);
|
||||
paraview_dc->SetTime(double(0));
|
||||
paraview_dc->Save();
|
||||
|
||||
std::ofstream fdepsStream;
|
||||
std::ostringstream fdeps_file_name;
|
||||
fdeps_file_name << "data/fdeps.dat";
|
||||
|
||||
std::ofstream fderrStream;
|
||||
std::ostringstream fderr_file_name;
|
||||
fderr_file_name << "data/fderr.dat";
|
||||
|
||||
// write new configuration (reference coordinates + displacement u0) to file
|
||||
u1.Set(1.0, u0);
|
||||
displacement.SetFromTrueDofs(u1);
|
||||
add(coords, displacement, new_coords);
|
||||
|
||||
Vector config(u0.Size()); config = 0.0;
|
||||
new_coords.GetTrueDofs(config);
|
||||
|
||||
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
fdepsStream.open(fdeps_file_name.str(), std::ios::out | std::ios::trunc);
|
||||
fderrStream.open(fderr_file_name.str(), std::ios::out | std::ios::trunc);
|
||||
}
|
||||
|
||||
double eps = 1.0;
|
||||
int neps = 40;
|
||||
for (int i = 0; i < neps; i++) // eps_min = 0.5^(39) \approx 10^(-12)
|
||||
{
|
||||
// compute g1 = g(u1), u1 = u0 + eps * udir
|
||||
u1.Set(1.0, u0);
|
||||
u1.Add(eps, udir);
|
||||
displacement.SetFromTrueDofs(u1);
|
||||
add(coords, displacement, new_coords);
|
||||
ContactObj contact1(&mesh, mortar_attrs, nonmortar_attrs, &new_coords);
|
||||
contact1.GetGap(g1);
|
||||
|
||||
// determine finite difference residual: fdres = (g1 - g0) / eps - J0 * udir
|
||||
fdres.Set(1. / eps, g1);
|
||||
fdres.Add(-1. / eps, g0);
|
||||
fdres.Add(-1, J0udir);
|
||||
double fderr_l2norm = GlobalLpNorm(2, fdres.Norml2(), MPI_COMM_WORLD);
|
||||
double udir_l2norm = GlobalLpNorm(2, udir.Norml2(), MPI_COMM_WORLD);
|
||||
|
||||
if (mfem::Mpi::Root())
|
||||
{
|
||||
std::cout << "--------------------------------------------\n\n";
|
||||
std::cout << "||(g(u0 + eps * udir) - g(u0)) / eps - J(u0) * udir|| = " << fderr_l2norm << ", eps = " << eps << "\n\n";
|
||||
std::cout << "||(g(u0 + eps * udir) - g(u0)) / eps - J(u0) * udir||_2 / ||udir||_2 = " << fderr_l2norm / udir_l2norm << std::endl;
|
||||
}
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
fdepsStream << eps << std::endl;
|
||||
fderrStream << fderr_l2norm << std::endl;
|
||||
}
|
||||
eps /= 2.0;
|
||||
}
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
fdepsStream.close();
|
||||
fderrStream.close();
|
||||
}
|
||||
|
||||
|
||||
/* What follows we linearly modify epsilon
|
||||
* output the gap, in order to check for discontinuities
|
||||
* and also output the various states u0 + eps * udir to file
|
||||
* in order to visualize the mesh configurations *
|
||||
* */
|
||||
eps = 1.0;
|
||||
neps = 100;
|
||||
double deps = eps / ((double) neps);
|
||||
std::ofstream epsStream;
|
||||
std::ostringstream eps_file_name;
|
||||
eps_file_name << "data/eps_ref_" << ref_levels << ".dat";
|
||||
|
||||
std::ofstream gapStream;
|
||||
std::ostringstream gap_file_name;
|
||||
gap_file_name << "data/gap_ref_" << ref_levels << ".dat";
|
||||
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
epsStream.open(eps_file_name.str(), std::ios::out | std::ios::trunc);
|
||||
gapStream.open(gap_file_name.str(), std::ios::out | std::ios::trunc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < neps; i++)
|
||||
{
|
||||
// compute g1 = g(u1), u1 = u0 + eps * udir
|
||||
u1.Set(1.0, u0);
|
||||
u1.Add(eps, udir);
|
||||
displacement.SetFromTrueDofs(u1);
|
||||
add(coords, displacement, new_coords);
|
||||
ContactObj contact1(&mesh, mortar_attrs, nonmortar_attrs, &new_coords);
|
||||
contact1.GetGap(g1);
|
||||
double gap_l2norm = GlobalLpNorm(2, g1.Norml2(), MPI_COMM_WORLD);
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
epsStream << eps << std::endl;
|
||||
gapStream << g1.Norml2() << std::endl;
|
||||
}
|
||||
|
||||
// update mesh according to u1 and write to Paraview for visualization
|
||||
mesh_copy.SetNodes(new_coords);
|
||||
paraview_dc->SetCycle(i+1) ;
|
||||
paraview_dc->SetTime((double) (i+1));
|
||||
paraview_dc->Save();
|
||||
|
||||
// linear update to eps: eps = eps - deps
|
||||
eps -= deps;
|
||||
}
|
||||
|
||||
if (mfem::Mpi::Root() && outputfiles)
|
||||
{
|
||||
epsStream.close();
|
||||
gapStream.close();
|
||||
}
|
||||
|
||||
// #7: Tribol cleanup: deletes coupling schemes and clears associated memory
|
||||
tribol::finalize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ContactObj::ContactObj(ParMesh * mesh_, const std::set<int> & mortar_attrs_,
|
||||
const std::set<int> & nonmortar_attrs_,
|
||||
ParGridFunction * coords_) :
|
||||
mesh(mesh_), mortar_attrs(mortar_attrs_),
|
||||
nonmortar_attrs(nonmortar_attrs_),
|
||||
coords(coords_)
|
||||
{
|
||||
// #2: Create a Tribol coupling scheme: defines contact surfaces and enforcement
|
||||
int coupling_scheme_id = 0;
|
||||
// NOTE: While there is a single mfem ParMesh for this problem, Tribol
|
||||
// defines a mortar and a nonmortar contact mesh, each with a unique mesh ID.
|
||||
// The Tribol mesh IDs for each contact surface are defined here.
|
||||
int mesh1_id = 0;
|
||||
int mesh2_id = 1;
|
||||
tribol::registerMfemCouplingScheme(
|
||||
coupling_scheme_id, mesh1_id, mesh2_id,
|
||||
*mesh, *coords, mortar_attrs, nonmortar_attrs,
|
||||
tribol::SURFACE_TO_SURFACE,
|
||||
tribol::NO_CASE,
|
||||
tribol::SINGLE_MORTAR,
|
||||
tribol::FRICTIONLESS,
|
||||
tribol::LAGRANGE_MULTIPLIER,
|
||||
tribol::BINNING_GRID
|
||||
);
|
||||
|
||||
// #3: Set additional options/access pressure grid function on contact surfaces
|
||||
// Access Tribol's pressure grid function (on the contact surface). The
|
||||
// pressure ParGridFunction is created upon calling
|
||||
// registerMfemCouplingScheme(). It's lifetime coincides with the lifetime of
|
||||
// the coupling scheme, so the host code can reference and update it as
|
||||
// needed.
|
||||
auto& pressure = tribol::getMfemPressure(coupling_scheme_id);
|
||||
|
||||
// Set Tribol options for Lagrange multiplier enforcement
|
||||
tribol::setLagrangeMultiplierOptions(
|
||||
coupling_scheme_id,
|
||||
tribol::ImplicitEvalMode::MORTAR_RESIDUAL_JACOBIAN
|
||||
);
|
||||
|
||||
// #4: Update contact mesh decomposition so the on-rank Tribol meshes
|
||||
// coincide with the current configuration of the mesh. This must be called
|
||||
// before tribol::update().
|
||||
tribol::updateMfemParallelDecomposition();
|
||||
|
||||
// #5: Update contact gaps, forces, and tangent stiffness contributions
|
||||
int cycle = 1; // pseudo cycle
|
||||
mfem::real_t t = 1.0; // pseudo time
|
||||
mfem::real_t dt = 1.0; // pseudo dt
|
||||
tribol::update(cycle, t, dt);
|
||||
|
||||
|
||||
// #6a: Return contact contribution to the tangent stiffness matrix as a
|
||||
// block operator. See documentation for getMfemBlockJacobian() for block
|
||||
// definitions.
|
||||
//auto A_blk = tribol::getMfemBlockJacobian(coupling_scheme_id);
|
||||
A_blk = tribol::getMfemBlockJacobian(coupling_scheme_id);
|
||||
Jacobian = (HypreParMatrix *)(& A_blk->GetBlock(1, 0));
|
||||
|
||||
|
||||
mfem::BlockVector B_blk(A_blk->RowOffsets());
|
||||
B_blk = 0.0;
|
||||
|
||||
// Fill with initial nodal gaps.
|
||||
// Note forces from contact are currently zero since pressure is zero prior
|
||||
// to first solve.
|
||||
mfem::Vector gap_temp;
|
||||
// #6b: Return computed gap constraints on the contact surfaces
|
||||
tribol::getMfemGap(coupling_scheme_id, gap_temp); // gap on ldofs
|
||||
auto& P_submesh = *pressure.ParFESpace()->GetProlongationMatrix();
|
||||
//auto& gap_true = B_blk.GetBlock(1); // gap tdof vectorParFESpace()
|
||||
// gap is a dual vector, so (gap tdof vector) = P^T * (gap ldof vector)
|
||||
gap.SetSize(P_submesh.Width()); gap = 0.0;
|
||||
|
||||
P_submesh.MultTranspose(gap_temp, gap);
|
||||
}
|
||||
|
||||
void ContactObj::GetGap(mfem::Vector & g) const
|
||||
{
|
||||
g.SetSize(gap.Size());
|
||||
g.Set(1.0, gap);
|
||||
}
|
||||
|
||||
|
||||
mfem::HypreParMatrix * ContactObj::GetJacobian() const
|
||||
{
|
||||
return Jacobian;
|
||||
}
|
||||
|
||||
ContactObj::~ContactObj()
|
||||
{
|
||||
}
|
||||
@@ -22,7 +22,7 @@ MFEM_LIB_FILE = mfem_is_not_built
|
||||
-include $(CONFIG_MK)
|
||||
|
||||
ifeq ($(MFEM_USE_TRIBOL)$(MFEM_USE_MPI),YESYES)
|
||||
MINIAPPS = contact-patch-test contact-patch-finite-difference-test
|
||||
MINIAPPS = contact-patch-test
|
||||
else
|
||||
MINIAPPS =
|
||||
endif
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
MFEM mesh v1.0
|
||||
|
||||
# two unit cubes occupying [0,1]^3 and [0,1]x[0,1]x[0.99,1.99]
|
||||
|
||||
#
|
||||
# MFEM Geometry Types (see mesh/geom.hpp):
|
||||
#
|
||||
# POINT = 0
|
||||
# SEGMENT = 1
|
||||
# TRIANGLE = 2
|
||||
# SQUARE = 3
|
||||
# TETRAHEDRON = 4
|
||||
# CUBE = 5
|
||||
#
|
||||
|
||||
dimension
|
||||
3
|
||||
|
||||
elements
|
||||
2
|
||||
1 5 0 1 3 2 4 5 7 6
|
||||
1 5 8 9 11 10 12 13 15 14
|
||||
|
||||
boundary
|
||||
12
|
||||
3 3 2 3 1 0
|
||||
2 3 0 1 5 4
|
||||
7 3 3 2 6 7
|
||||
1 3 2 0 4 6
|
||||
4 3 4 5 7 6
|
||||
7 3 1 3 7 5
|
||||
5 3 10 11 9 8
|
||||
2 3 8 9 13 12
|
||||
7 3 11 10 14 15
|
||||
1 3 10 8 12 14
|
||||
6 3 12 13 15 14
|
||||
7 3 9 11 15 13
|
||||
|
||||
vertices
|
||||
16
|
||||
3
|
||||
0.25 0.25 0
|
||||
0.75 0.25 0
|
||||
0.25 0.75 0
|
||||
0.75 0.75 0
|
||||
0.25 0.25 1
|
||||
0.75 0.25 1
|
||||
0.25 0.75 1
|
||||
0.75 0.75 1
|
||||
0 0 1.00
|
||||
1 0 1.00
|
||||
0 1 1.00
|
||||
1 1 1.00
|
||||
0 0 2.00
|
||||
1 0 2.00
|
||||
0 1 2.00
|
||||
1 1 2.00
|
||||
@@ -47,11 +47,11 @@ vertices
|
||||
1 0 1
|
||||
0 1 1
|
||||
1 1 1
|
||||
0 0 1.01
|
||||
1 0 1.01
|
||||
0 1 1.01
|
||||
1 1 1.01
|
||||
0 0 0.99
|
||||
1 0 0.99
|
||||
0 1 0.99
|
||||
1 1 0.99
|
||||
0 0 1.99
|
||||
1 0 1.99
|
||||
0 1 1.99
|
||||
1 1 1.99
|
||||
1 1 1.99
|
||||
@@ -163,6 +163,13 @@ double poly3d(const IntegrationPoint &ip, int l, int m, int n)
|
||||
// l!m!n!/(p+3)! = 1/binom(p,l+m)/binom(l+m,l)/(p+1)/(p+2)/(p+3)
|
||||
}
|
||||
|
||||
double poly4d(const IntegrationPoint &ip, int l, int m, int n, int o)
|
||||
{
|
||||
return pow(ip.x, l)*pow(ip.y, m)*pow(ip.z, n)*pow(ip.t, o);
|
||||
// exact integral over the reference pentatope is (with p = l+m+n+o)
|
||||
// l!m!n!o!/(p+4)! = 1/binom(p,l)/binom(p-l,m)/binom(n+o,o)/(p+1)/(p+2)/(p+3)/(p+4)
|
||||
}
|
||||
|
||||
TEST_CASE("Simplex integration rules", "[SimplexRules]")
|
||||
{
|
||||
// This code is automatically re-executed for all of the sections.
|
||||
@@ -243,4 +250,40 @@ TEST_CASE("Simplex integration rules", "[SimplexRules]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("low pent integration error on reference element for f=x^l y^m z^n t^o, where l+m+n+o <= p")
|
||||
{
|
||||
for (int order = 0; order <= 10; order++)
|
||||
{
|
||||
const IntegrationRule &ir = IntRules.Get(Geometry::PENTATOPE, order);
|
||||
|
||||
for (int p = 0; p <= order; p++)
|
||||
{
|
||||
for (int l = p; l >= 0; l--)
|
||||
{
|
||||
for (int m = p - l; m >= 0; m--)
|
||||
{
|
||||
for (int n = p - l - m; n >= 0; n--)
|
||||
{
|
||||
int o = p - l - m - n;
|
||||
|
||||
double integral = 0.0;
|
||||
for (int i = 0; i < ir.GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir.IntPoint(i);
|
||||
integral += ip.weight*poly4d(ip, l, m, n, o);
|
||||
}
|
||||
|
||||
double exact = 1.0/binom[p][l]/binom[p-l][m]/binom[n+o][o]/(p+1)/(p+2)/(p+3)/(p+4);
|
||||
double relerr = 1. - integral/exact;
|
||||
|
||||
//If a test fails any INFO statements preceding the REQUIRE are displayed
|
||||
INFO("p=" << p << ", l=" << l << ", m=" << m << ", n=" << n << ", o=" << o);
|
||||
REQUIRE(fabs(relerr) < 1e-11);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user