Compare commits
668
Commits
ethos_MS
...
issue-4604
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c6198593fb | ||
|
|
c9db272586 | ||
|
|
ae117fa580 | ||
|
|
ee0e35c94b | ||
|
|
a0c3bdc93e | ||
|
|
2a1dd3d9c2 | ||
|
|
2277c3729f | ||
|
|
afb7aaa2a5 | ||
|
|
34cb75622a | ||
|
|
5dc85da306 | ||
|
|
3f810f3591 | ||
|
|
b60df76e98 | ||
|
|
21537ec6c6 | ||
|
|
5ba722dd2f | ||
|
|
4a9a6e3ba3 | ||
|
|
c4e672c71a | ||
|
|
7bb9027c82 | ||
|
|
7150b9e9bd | ||
|
|
2105441b2c | ||
|
|
55dc0f4b97 | ||
|
|
4de1e1bad3 | ||
|
|
dfec0c0281 | ||
|
|
61d4d6bbc2 | ||
|
|
e2ed642f5b | ||
|
|
0656bc02cf | ||
|
|
5b002f9452 | ||
|
|
f65afa6f7b | ||
|
|
72dc6dd9df | ||
|
|
d4b8071871 | ||
|
|
006e348182 | ||
|
|
f280d43ac9 | ||
|
|
abe37e5ed7 | ||
|
|
d9fef7f574 | ||
|
|
65585868a7 | ||
|
|
0e0b81d87f | ||
|
|
56bc30fa75 | ||
|
|
0d306df7ec | ||
|
|
60aea56a1d | ||
|
|
f13d975c21 | ||
|
|
a496df4734 | ||
|
|
5b1171aae9 | ||
|
|
8ce411f481 | ||
|
|
bd3d1b6dcc | ||
|
|
7d7ec1fa6a | ||
|
|
c42fd1ccd5 | ||
|
|
7e1884ca65 | ||
|
|
3ac922ac32 | ||
|
|
e09decae30 | ||
|
|
2e326c97bf | ||
|
|
c0ad0924cd | ||
|
|
109b2f3eb3 | ||
|
|
2dddad5381 | ||
|
|
2fdac5753b | ||
|
|
5c53d66dc4 | ||
|
|
dfb72d01f6 | ||
|
|
dd8c1241a5 | ||
|
|
db323179f1 | ||
|
|
4983d81eb9 | ||
|
|
13b9e14526 | ||
|
|
7324c70027 | ||
|
|
3bb7b0bcfe | ||
|
|
6932e2038f | ||
|
|
dbbb7b6b5d | ||
|
|
e7cf9fb5ac | ||
|
|
15accf0271 | ||
|
|
47afa5868b | ||
|
|
7fe2ba5e92 | ||
|
|
ae033ff089 | ||
|
|
2f09f46776 | ||
|
|
09d9b0b1de | ||
|
|
99958b1c67 | ||
|
|
7c78f98552 | ||
|
|
6c2f6a9e7f | ||
|
|
96a0320f2c | ||
|
|
04b09171dc | ||
|
|
97bbd21b16 | ||
|
|
810eb3dc09 | ||
|
|
6e1101f058 | ||
|
|
9b4086319a | ||
|
|
e3e0eccc86 | ||
|
|
caa7ff4a95 | ||
|
|
e1c1fcc3fa | ||
|
|
c4e853a8ee | ||
|
|
07db30222c | ||
|
|
b521859413 | ||
|
|
88ae946755 | ||
|
|
d9758bd216 | ||
|
|
3e0c373ee2 | ||
|
|
c6bbe85b21 | ||
|
|
837333b88a | ||
|
|
b249a4de62 | ||
|
|
72de1e5d50 | ||
|
|
5bcba26e08 | ||
|
|
6ddea3ff47 | ||
|
|
e97ff1222e | ||
|
|
697c21aa7e | ||
|
|
78e593bea1 | ||
|
|
d85c8fb65a | ||
|
|
178a4db5c8 | ||
|
|
dc241f8298 | ||
|
|
701d3875c5 | ||
|
|
3bdbfb51f9 | ||
|
|
8d254f488e | ||
|
|
92e927ccf8 | ||
|
|
b8a120ec3e | ||
|
|
d10c9f7952 | ||
|
|
50f5fcc42e | ||
|
|
4d5054c197 | ||
|
|
845ff55e3f | ||
|
|
ecfee97b37 | ||
|
|
8eaae0ff87 | ||
|
|
0345861c6f | ||
|
|
01d57ee7f8 | ||
|
|
900385e06d | ||
|
|
678d44a01e | ||
|
|
bf312430a7 | ||
|
|
f35689d7bc | ||
|
|
c45b3ef3ee | ||
|
|
598413e2fc | ||
|
|
81cf9ed9a1 | ||
|
|
33efde9e81 | ||
|
|
19a1750527 | ||
|
|
d08c019d4c | ||
|
|
1deaa1cb57 | ||
|
|
e69ad849ff | ||
|
|
49450e3db7 | ||
|
|
14255ad4f4 | ||
|
|
d9850f4baa | ||
|
|
4219887355 | ||
|
|
f51d715503 | ||
|
|
3d35c66864 | ||
|
|
b626908505 | ||
|
|
8b95b3353b | ||
|
|
bc2b87e891 | ||
|
|
e01407f82b | ||
|
|
88a10cb42b | ||
|
|
17cd445e8b | ||
|
|
20fce49843 | ||
|
|
c53f1c9188 | ||
|
|
085f779379 | ||
|
|
48ce125336 | ||
|
|
2bbdafa9f4 | ||
|
|
76fd3575d1 | ||
|
|
b22b2158bf | ||
|
|
a1c279ee79 | ||
|
|
a1429e80e2 | ||
|
|
8bfa001844 | ||
|
|
3230923742 | ||
|
|
5038e96f34 | ||
|
|
c421146f47 | ||
|
|
86336f1c51 | ||
|
|
699bb4d422 | ||
|
|
ce0bda7a35 | ||
|
|
e2a20d381c | ||
|
|
1f38748b11 | ||
|
|
42300d0fca | ||
|
|
7db0a9a8d3 | ||
|
|
16a9b2be3c | ||
|
|
e731d2dd69 | ||
|
|
6afc7e6fe8 | ||
|
|
2a4fd1121e | ||
|
|
d5f029f016 | ||
|
|
06e7948445 | ||
|
|
1bd9ed53b3 | ||
|
|
f72bfcce92 | ||
|
|
971864c3a1 | ||
|
|
b11a4e2c6a | ||
|
|
2a109bd2ea | ||
|
|
9fce164b33 | ||
|
|
faf6ea6ca6 | ||
|
|
cbac9063ad | ||
|
|
66c3474eb3 | ||
|
|
61fd002be4 | ||
|
|
24da41f6bb | ||
|
|
9943072dca | ||
|
|
f8b638c569 | ||
|
|
0c88591848 | ||
|
|
1cdc2eb295 | ||
|
|
c8aa01fbe6 | ||
|
|
03c874a199 | ||
|
|
3e69daedf7 | ||
|
|
1e4f2b5d2b | ||
|
|
e94e997790 | ||
|
|
8b7b8bc4af | ||
|
|
8a63fe8a49 | ||
|
|
08d8058ce1 | ||
|
|
ca48beb934 | ||
|
|
9a9087e20b | ||
|
|
d7370c8518 | ||
|
|
ef2636e4e9 | ||
|
|
0e1f45f060 | ||
|
|
8cc9877716 | ||
|
|
0d389eed75 | ||
|
|
029d0ee306 | ||
|
|
46ab66d499 | ||
|
|
144db3a53c | ||
|
|
5895c08ff2 | ||
|
|
74e93755fa | ||
|
|
acb91a69ab | ||
|
|
59b656a18c | ||
|
|
4305f39092 | ||
|
|
367266ee95 | ||
|
|
afbaca05de | ||
|
|
5780c2c21c | ||
|
|
16e0bad850 | ||
|
|
5c0bd60944 | ||
|
|
44438536af | ||
|
|
3d488cd2fd | ||
|
|
099c3493b2 | ||
|
|
655623ca9b | ||
|
|
f91f3d12a6 | ||
|
|
fc8312383f | ||
|
|
947bcc2b80 | ||
|
|
4ff80fbb80 | ||
|
|
915fc1e910 | ||
|
|
6324806008 | ||
|
|
c3771b3352 | ||
|
|
51a75893f7 | ||
|
|
b164ad53a2 | ||
|
|
aab51f6935 | ||
|
|
23afe83964 | ||
|
|
7845bca7be | ||
|
|
98bbecd492 | ||
|
|
e079915f76 | ||
|
|
ce253361c6 | ||
|
|
718a86594c | ||
|
|
d24fd7d447 | ||
|
|
cac27438f5 | ||
|
|
7f2a2692dd | ||
|
|
48c1a80fdc | ||
|
|
29a2501f8c | ||
|
|
ad7d173497 | ||
|
|
9d2b6007ed | ||
|
|
35bbdc75c9 | ||
|
|
88416db438 | ||
|
|
00616cfccf | ||
|
|
b7c8d66a3d | ||
|
|
c992bd681c | ||
|
|
9bee2fcac8 | ||
|
|
f1304374e0 | ||
|
|
d835203da0 | ||
|
|
49e4bd9d3d | ||
|
|
a3137917cd | ||
|
|
965959e88c | ||
|
|
1136a2f283 | ||
|
|
baf6ba5d66 | ||
|
|
3fb7697ffb | ||
|
|
6d288efd68 | ||
|
|
4b87236e73 | ||
|
|
8464088792 | ||
|
|
c03257233f | ||
|
|
0f3df57632 | ||
|
|
5c4d967f6c | ||
|
|
436d1fa2ff | ||
|
|
4f3bc873cc | ||
|
|
cf90e56850 | ||
|
|
7a6caccf99 | ||
|
|
f319ddef60 | ||
|
|
8f4c1dbe79 | ||
|
|
1e838ff45e | ||
|
|
45c130f77b | ||
|
|
b805f2a48d | ||
|
|
6b87974c70 | ||
|
|
181030cc29 | ||
|
|
04c43fa7b9 | ||
|
|
0dc0d1fcb9 | ||
|
|
b96db37ab8 | ||
|
|
79834fa003 | ||
|
|
25a1f0b3c6 | ||
|
|
aba31a53be | ||
|
|
54982a700a | ||
|
|
d47622eed2 | ||
|
|
6bcd940840 | ||
|
|
93c07b5c1c | ||
|
|
90e77b9ca1 | ||
|
|
3bd439a3c4 | ||
|
|
5b825515f7 | ||
|
|
d4da37d89a | ||
|
|
deb8bc7ed3 | ||
|
|
982583068a | ||
|
|
a6fdbe53b5 | ||
|
|
21bf9c3c10 | ||
|
|
899a96b769 | ||
|
|
b4bd2f7e63 | ||
|
|
9837922654 | ||
|
|
5ec2931690 | ||
|
|
911511ed1d | ||
|
|
d7e8d78ca4 | ||
|
|
bbc37c5236 | ||
|
|
4ca2e5cef2 | ||
|
|
c09c15c0b2 | ||
|
|
d6d3e30832 | ||
|
|
9129e51b86 | ||
|
|
0797adb30a | ||
|
|
3945247cf5 | ||
|
|
de6ac02a8d | ||
|
|
873a6aa84c | ||
|
|
2ac825abe8 | ||
|
|
1262d17e8b | ||
|
|
211baab557 | ||
|
|
d6e1063c5e | ||
|
|
fe9bd03f4b | ||
|
|
7645bce2b5 | ||
|
|
7cb81d5916 | ||
|
|
128882200d | ||
|
|
3f4dd4db7f | ||
|
|
73dbd7446f | ||
|
|
7c1a0eb5e3 | ||
|
|
fc0a1eb8da | ||
|
|
e458e579e0 | ||
|
|
f6dbf49709 | ||
|
|
f4be9104f5 | ||
|
|
3183af1b3c | ||
|
|
ced884b231 | ||
|
|
afbd1a1ba5 | ||
|
|
314ae7ed36 | ||
|
|
72dc18cccb | ||
|
|
119d257bb1 | ||
|
|
4559bd4bea | ||
|
|
8e3674396f | ||
|
|
4c0c3f822a | ||
|
|
cba0739740 | ||
|
|
75f0ed1b67 | ||
|
|
8853f574da | ||
|
|
645b7ba0dc | ||
|
|
e90cff6413 | ||
|
|
0fc4ee363b | ||
|
|
449778485d | ||
|
|
59a033b3ea | ||
|
|
bf47bc9210 | ||
|
|
4eac35a79a | ||
|
|
dffee6b764 | ||
|
|
302be130d1 | ||
|
|
9d7696d803 | ||
|
|
1e0bb496e8 | ||
|
|
a954ed2046 | ||
|
|
064c5261a7 | ||
|
|
6e814df8cd | ||
|
|
fe3a6cba80 | ||
|
|
8883f34f5d | ||
|
|
737d9032d7 | ||
|
|
4993d5e715 | ||
|
|
9148e14b6f | ||
|
|
e8c5dbd885 | ||
|
|
e561db6d0a | ||
|
|
40dbb933e7 | ||
|
|
71a25ca7fa | ||
|
|
d06d5e2a5a | ||
|
|
026c5c9808 | ||
|
|
7587dcad87 | ||
|
|
3bcd024ca4 | ||
|
|
701f109c1b | ||
|
|
e250112b1b | ||
|
|
70af0843a6 | ||
|
|
9176c2b95f | ||
|
|
79afc9f006 | ||
|
|
57ebd5f0a1 | ||
|
|
df8989a28a | ||
|
|
6377476998 | ||
|
|
aeeadfe5d0 | ||
|
|
29417aed77 | ||
|
|
1f6abc2e0b | ||
|
|
293b5f78e8 | ||
|
|
2ebe3efde8 | ||
|
|
7399d8a8e0 | ||
|
|
6ae591075c | ||
|
|
5f69535a0e | ||
|
|
df13f75834 | ||
|
|
e49747c49b | ||
|
|
5a1d69837d | ||
|
|
b0b726a2a9 | ||
|
|
86b2599e50 | ||
|
|
8007b5073f | ||
|
|
564e2ff58e | ||
|
|
780eaeda5a | ||
|
|
8a4bb61a2a | ||
|
|
dc1b1ce0ec | ||
|
|
cd34967081 | ||
|
|
f2496c3599 | ||
|
|
1ad507217d | ||
|
|
5ea5e37c9f | ||
|
|
909272fc0d | ||
|
|
ff4544771b | ||
|
|
255c0c77e0 | ||
|
|
1fcea2faf4 | ||
|
|
199f3616b6 | ||
|
|
3b4825675b | ||
|
|
470698bb28 | ||
|
|
8a4df331fe | ||
|
|
6c07f873ef | ||
|
|
7068d022f8 | ||
|
|
c232029d84 | ||
|
|
c9cf2ec345 | ||
|
|
7195af90b1 | ||
|
|
325929278d | ||
|
|
833ed331e1 | ||
|
|
ea6ab76762 | ||
|
|
b4efd401b8 | ||
|
|
c7bb0201c0 | ||
|
|
8a19254fc6 | ||
|
|
ff0b016126 | ||
|
|
88f90717b1 | ||
|
|
256995a053 | ||
|
|
941c6c2bac | ||
|
|
de235a0660 | ||
|
|
bee8df8b42 | ||
|
|
4e17193a11 | ||
|
|
b4dfb8660d | ||
|
|
95a5c503b1 | ||
|
|
e05a13bc98 | ||
|
|
e5cfc35f87 | ||
|
|
2cb4f5fd65 | ||
|
|
9f708051da | ||
|
|
e1b98c30ec | ||
|
|
33cbfac042 | ||
|
|
41d94a5528 | ||
|
|
a7382dd25e | ||
|
|
c83264e825 | ||
|
|
70a4d67169 | ||
|
|
498d539f68 | ||
|
|
a7cdb86334 | ||
|
|
4259ecc48b | ||
|
|
1382f6c771 | ||
|
|
d0b1f760eb | ||
|
|
846c63d53e | ||
|
|
91f14abe6e | ||
|
|
d7c3190a68 | ||
|
|
d98eb5b5a0 | ||
|
|
14e5114039 | ||
|
|
854b2c5ed8 | ||
|
|
de70ec68cf | ||
|
|
acf8bdb43e | ||
|
|
c99c7581d8 | ||
|
|
17d29a8390 | ||
|
|
e5de10c9d9 | ||
|
|
33e507ccbc | ||
|
|
db75ba5bed | ||
|
|
a926841cf9 | ||
|
|
bb1f48cc06 | ||
|
|
b42f27fe48 | ||
|
|
ee59eb5cc0 | ||
|
|
6672424982 | ||
|
|
449ae5e8c3 | ||
|
|
a130d17bc9 | ||
|
|
445e41bb77 | ||
|
|
6c17447045 | ||
|
|
ada0e37801 | ||
|
|
4cf617347f | ||
|
|
976234b376 | ||
|
|
09b7d0a251 | ||
|
|
607775421c | ||
|
|
3d226227d8 | ||
|
|
48c1be8fb5 | ||
|
|
ab15daf765 | ||
|
|
a8ca317754 | ||
|
|
2a703daa56 | ||
|
|
b3323ef6e4 | ||
|
|
345957aae2 | ||
|
|
e85a96e745 | ||
|
|
7719196373 | ||
|
|
601ea3a147 | ||
|
|
8e85dcfbc8 | ||
|
|
f8e809903b | ||
|
|
ae6a90e383 | ||
|
|
cd20285435 | ||
|
|
e31e40b4fb | ||
|
|
3320cbda43 | ||
|
|
b269d1dc2f | ||
|
|
381abe9002 | ||
|
|
2496d2af00 | ||
|
|
8d077885a2 | ||
|
|
d929df70c2 | ||
|
|
ecf167ca37 | ||
|
|
343c4812a6 | ||
|
|
beae628d98 | ||
|
|
d9814767a2 | ||
|
|
b6c7920a3d | ||
|
|
00a1775659 | ||
|
|
8c4f7851b3 | ||
|
|
ac0a593a6e | ||
|
|
b1c328aafb | ||
|
|
dd3fa25da7 | ||
|
|
f3814356d3 | ||
|
|
7a708f4d64 | ||
|
|
969077f526 | ||
|
|
825e8224a2 | ||
|
|
f645bae11a | ||
|
|
e05b0bcb44 | ||
|
|
52945319b2 | ||
|
|
13cd22c4b2 | ||
|
|
f920464b4d | ||
|
|
48cfa24e8e | ||
|
|
8d2402e654 | ||
|
|
c0ac027e72 | ||
|
|
90ce12cb2f | ||
|
|
97619c08f7 | ||
|
|
db38490daf | ||
|
|
ffaa345807 | ||
|
|
91f8956649 | ||
|
|
03007510f3 | ||
|
|
af1d533330 | ||
|
|
51af7963da | ||
|
|
fa467ebf11 | ||
|
|
6d461e600d | ||
|
|
4e52184594 | ||
|
|
3dda022825 | ||
|
|
be17af796b | ||
|
|
130aa7072b | ||
|
|
c36623d665 | ||
|
|
dad4e4cf2e | ||
|
|
cb5470b63c | ||
|
|
4aa52f4d61 | ||
|
|
39ee3831e7 | ||
|
|
824ae129c5 | ||
|
|
7a824a4489 | ||
|
|
f42b4d5789 | ||
|
|
87638e3f26 | ||
|
|
77095f5bc8 | ||
|
|
c4d26dd313 | ||
|
|
093670e070 | ||
|
|
612e0777d8 | ||
|
|
e75359d87f | ||
|
|
78aea079ff | ||
|
|
985b4c121e | ||
|
|
07230f9d47 | ||
|
|
3eacfe9d7e | ||
|
|
98e0932f63 | ||
|
|
7f6cbffd82 | ||
|
|
f61629c5a5 | ||
|
|
b3fff9267a | ||
|
|
c253f00ddc | ||
|
|
cc43f03baa | ||
|
|
cd5a72fabe | ||
|
|
0432b1c47c | ||
|
|
f08544c863 | ||
|
|
17929e4781 | ||
|
|
37dd6b32d3 | ||
|
|
708a8d92f8 | ||
|
|
fd270b6c5f | ||
|
|
910e840fda | ||
|
|
f3add08ae3 | ||
|
|
6194522f56 | ||
|
|
99cbad4040 | ||
|
|
fa7adc73eb | ||
|
|
7d3a46e95b | ||
|
|
9bc55b81b4 | ||
|
|
b541898594 | ||
|
|
cf530e9029 | ||
|
|
2f6871e449 | ||
|
|
8a2ef8aa36 | ||
|
|
f0bc536820 | ||
|
|
f052af3d6b | ||
|
|
a3be873907 | ||
|
|
d0c358ab48 | ||
|
|
982f7a1729 | ||
|
|
96ef25817c | ||
|
|
7f0e9c8801 | ||
|
|
f96f8af545 | ||
|
|
4edd730ce7 | ||
|
|
06955c17d9 | ||
|
|
06a8b35570 | ||
|
|
92ff8c744f | ||
|
|
c269b1ea54 | ||
|
|
cc70734bc0 | ||
|
|
013eace8a6 | ||
|
|
8237b9212d | ||
|
|
009837f4c8 | ||
|
|
b991cb755e | ||
|
|
5e3359a805 | ||
|
|
4a9f7f683d | ||
|
|
9d89d1abef | ||
|
|
2ea08bacb4 | ||
|
|
b3ab618e6e | ||
|
|
66a2f5439d | ||
|
|
60326c575e | ||
|
|
a9ae482df0 | ||
|
|
04c7fa0f1c | ||
|
|
c65e6ad71c | ||
|
|
8537c16f3d | ||
|
|
551c7a2a72 | ||
|
|
66981ac2fa | ||
|
|
9b331b608d | ||
|
|
11e2e7f039 | ||
|
|
9827a0f33e | ||
|
|
eb6a485bc2 | ||
|
|
24532a295f | ||
|
|
9ae249c2fc | ||
|
|
312ed03ffd | ||
|
|
1b16534745 | ||
|
|
81dcc8cdb1 | ||
|
|
cfc96fa055 | ||
|
|
1c768998a4 | ||
|
|
a9f6fc53da | ||
|
|
3e967ff7b7 | ||
|
|
1bd5b19ad4 | ||
|
|
b0971b1f80 | ||
|
|
0284105a59 | ||
|
|
5830a87b75 | ||
|
|
b062c59580 | ||
|
|
1fce567e82 | ||
|
|
c06e6d6431 | ||
|
|
8fc7079174 | ||
|
|
5fe5e0068d | ||
|
|
4e67781c2c | ||
|
|
65daeaa533 | ||
|
|
281c0182be | ||
|
|
f88486fda1 | ||
|
|
d8df6b8020 | ||
|
|
061b6109a2 | ||
|
|
1241960dc4 | ||
|
|
ee501168de | ||
|
|
4c96ebc652 | ||
|
|
06f60e28d5 | ||
|
|
10705f397f | ||
|
|
bbb78602a4 | ||
|
|
040c5b2450 | ||
|
|
8e7428fbc3 | ||
|
|
5cda5516ff | ||
|
|
b0060c136d | ||
|
|
3d162b51a8 | ||
|
|
961882055b | ||
|
|
d86613219c | ||
|
|
63f977d03f | ||
|
|
ccccdf1736 | ||
|
|
3b6c6ce6fb | ||
|
|
c768c5f579 | ||
|
|
30091d6561 | ||
|
|
c2722880b5 | ||
|
|
02def42421 | ||
|
|
9aba2322fc | ||
|
|
4af8539ec3 | ||
|
|
a7eed94562 | ||
|
|
ec535699d8 | ||
|
|
8184de5c57 | ||
|
|
54f6694c16 | ||
|
|
ef9043a122 | ||
|
|
d3855adba0 | ||
|
|
a981a24dcc | ||
|
|
aab735263b | ||
|
|
966143b0ce | ||
|
|
01b3d0ae8b | ||
|
|
ae862ca52d | ||
|
|
051499f343 | ||
|
|
98ee0c0047 | ||
|
|
d8a13d8da6 | ||
|
|
87a9aa9f69 | ||
|
|
e315b66aeb | ||
|
|
fb54c7c59a | ||
|
|
72277751d7 | ||
|
|
c5ae059755 | ||
|
|
56eded3dc3 | ||
|
|
08a4ed8197 | ||
|
|
7026c0eba2 | ||
|
|
650dec9528 | ||
|
|
1f2e93b391 | ||
|
|
9792e8dbdd | ||
|
|
0bf89c6b62 | ||
|
|
cd01ff94f5 | ||
|
|
ab1c6c8652 | ||
|
|
13032f8ee9 | ||
|
|
393277c410 | ||
|
|
75dbd8dd14 | ||
|
|
9047821947 | ||
|
|
a6fac7c19b | ||
|
|
128c3f7d73 | ||
|
|
0bc03e1128 | ||
|
|
21fb6bc10f | ||
|
|
ae4acc54d8 |
@@ -29,6 +29,10 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
HYPRE_ARCHIVE: v2.19.0.tar.gz
|
||||
HYPRE_TOP_DIR: hypre-2.19.0
|
||||
@@ -92,6 +96,7 @@ jobs:
|
||||
build-system: cmake
|
||||
hypre-target: int32
|
||||
precision: fp64
|
||||
config-opts: '-DCMAKE_INSTALL_PREFIX=../cmake-install'
|
||||
# This option can be set to pass additional configuration options to
|
||||
# the MFEM configuration command.
|
||||
# config-opts: '-DCMAKE_VERBOSE_MAKEFILE=ON'
|
||||
@@ -114,13 +119,6 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
# This external action allows to interrupt a workflow already running on
|
||||
# the same branch to save resources.
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.12.1
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
# Fix 'No space left on device' errors for Ubuntu builds.
|
||||
- name: Run Actions Cleaner
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
@@ -306,6 +304,22 @@ jobs:
|
||||
ctest --rerun-failed --output-on-failure -C ${CTEST_CONFIG}
|
||||
shell: bash
|
||||
|
||||
- name: make install
|
||||
if: matrix.build-system == 'make'
|
||||
run: |
|
||||
cd ${{ env.MFEM_TOP_DIR }} && make install
|
||||
|
||||
- name: cmake install
|
||||
if: matrix.build-system == 'cmake'
|
||||
run: |
|
||||
CONFIG="Release"
|
||||
[[ ${{ matrix.target }} == 'dbg' ]] && CONFIG="Debug"
|
||||
TARGET="install"
|
||||
[[ ${{ matrix.os }} == 'windows-latest' ]] && TARGET="INSTALL"
|
||||
cd ${{ env.MFEM_TOP_DIR }} && \
|
||||
cmake --build build --target ${TARGET} --config ${CONFIG}
|
||||
shell: bash
|
||||
|
||||
# Code coverage (process and upload reports)
|
||||
- name: codecov
|
||||
if: matrix.codecov == 'YES'
|
||||
|
||||
@@ -18,6 +18,10 @@ on:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: ["master"]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
|
||||
@@ -22,6 +22,10 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
HYPRE_ARCHIVE: v2.19.0.tar.gz
|
||||
HYPRE_TOP_DIR: hypre-2.19.0
|
||||
@@ -34,11 +38,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.12.1
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: checkout MFEM
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
@@ -22,22 +22,15 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
Serial:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Temporary workaround for sanitizer crashes
|
||||
# See https://github.com/actions/runner-images/issues/9491
|
||||
# The issue should be fixed in the next runner image for Ubuntu 22.04,
|
||||
# see https://github.com/actions/runner-images/pull/9513
|
||||
run: sudo sysctl vm.mmap_rnd_bits=28
|
||||
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.12.1
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: MFEM Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -55,7 +48,7 @@ jobs:
|
||||
build-system: make
|
||||
library-only: false
|
||||
config-options:
|
||||
CXX="clang++-14"
|
||||
CXX="clang++-18"
|
||||
CXXFLAGS="-g -O1 -std=c++11
|
||||
-fsanitize=address
|
||||
-fno-omit-frame-pointer
|
||||
|
||||
@@ -19,6 +19,10 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# This workflow is run on pushes to any branch in the MFEM repo (with or without
|
||||
# PRs), as well as on updates to PRs from forks. In particular, we do not
|
||||
# duplicate work by running on both pushes and updates to local PRs. We do that
|
||||
@@ -33,11 +37,6 @@ jobs:
|
||||
(github.event_name == 'push' ||
|
||||
github.event.pull_request.head.repo.full_name != github.repository)
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.12.1
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: checkout mfem
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
name: Mark stale issues and pull requests
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
@@ -13,9 +14,10 @@ jobs:
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: ':warning: This issue has been automatically marked as stale because it has not had any activity in the last month. *If no activity occurs in the next week, it will be automatically closed.* Thank you for your contributions.'
|
||||
@@ -24,6 +26,6 @@ jobs:
|
||||
days-before-close: 7
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
operations-per-run: 30
|
||||
operations-per-run: 500
|
||||
exempt-issue-labels: "bug,WIP,ready-for-review,in-review,in-next"
|
||||
exempt-pr-labels: "bug,WIP,ready-for-review,in-review,in-next"
|
||||
|
||||
+11
@@ -8,6 +8,7 @@
|
||||
|
||||
# Object and library files
|
||||
*.o
|
||||
*.o.tmp
|
||||
/libmfem.*
|
||||
/miniapps/common/libmfem-common.*
|
||||
|
||||
@@ -226,6 +227,7 @@ miniapps/meshing/extruder
|
||||
miniapps/meshing/fit-node-position
|
||||
miniapps/meshing/trimmer
|
||||
miniapps/meshing/reflector
|
||||
miniapps/meshing/ref321
|
||||
miniapps/meshing/mesh-optimizer
|
||||
miniapps/meshing/pmesh-optimizer
|
||||
miniapps/meshing/pmesh-fitting
|
||||
@@ -245,6 +247,8 @@ miniapps/meshing/shaper.mesh
|
||||
miniapps/meshing/extruder.mesh
|
||||
miniapps/meshing/trimmer.mesh
|
||||
miniapps/meshing/reflected.mesh
|
||||
miniapps/meshing/ref321.mesh
|
||||
miniapps/meshing/sol.gf
|
||||
miniapps/meshing/optimized*
|
||||
miniapps/meshing/perturbed*
|
||||
miniapps/meshing/polar-nc.mesh
|
||||
@@ -339,6 +343,7 @@ miniapps/toys/rubik
|
||||
miniapps/toys/snake
|
||||
miniapps/toys/lissajous
|
||||
miniapps/toys/mondrian
|
||||
miniapps/toys/spiral
|
||||
miniapps/toys/snake-init.mesh
|
||||
miniapps/toys/snake-user.mesh
|
||||
miniapps/toys/snake-joined.mesh
|
||||
@@ -427,3 +432,9 @@ pkg.gitcommit
|
||||
|
||||
# Jupyter Notebook Checkpoints
|
||||
.ipynb_checkpoints
|
||||
|
||||
# emacs tag file
|
||||
TAGS
|
||||
|
||||
# vs code
|
||||
.vscode
|
||||
|
||||
@@ -12,6 +12,8 @@ Version 4.7.1 (development)
|
||||
===========================
|
||||
- Refactored ALGOIM cut integration rules. The interface is unified with
|
||||
the interface for moment based cut integration rules.
|
||||
- Altered (Par)GridFunction::Compute*Error functions to ensure they return
|
||||
non-negative values and therefore behave as "norms".
|
||||
|
||||
Discretization improvements
|
||||
---------------------------
|
||||
@@ -20,11 +22,28 @@ Discretization improvements
|
||||
|
||||
- Added support for boundary constraints to the hybridization class.
|
||||
|
||||
- Added support for external boundary submeshes with nonconformal mesh adaptation.
|
||||
|
||||
- Added assembly of Jacobians to `HyperbolicFormIntegrator`.
|
||||
|
||||
- Added average fluxes to `NumericalFlux` (formerly `RiemannSolver`)
|
||||
and `FluxFunction`.
|
||||
|
||||
- Added component-wise upwinded flux (`ComponentwiseUpwindFlux`).
|
||||
|
||||
Meshing improvements
|
||||
--------------------
|
||||
- Added native AD support for numerous TMOP metrics that didn't have first or
|
||||
second derivative implementations.
|
||||
|
||||
- The ExodusII reader now handles pyramid and wedge element types. Mixed meshes
|
||||
are also supported.
|
||||
|
||||
- Added support for nonuniform anisotropic (nonconforming) mesh refinement with
|
||||
arbitrary spacing in each direction, for quadrilateral (2D) and hexahedral
|
||||
(3D) meshes. This enables in particular 3:1 refinement, as demonstrated in the
|
||||
new meshing miniapp ref321.
|
||||
|
||||
New and updated examples and miniapps
|
||||
-------------------------------------
|
||||
- Added miniapps to demonstrate the H(div) and H(curl) NURBS elements.
|
||||
@@ -32,6 +51,9 @@ New and updated examples and miniapps
|
||||
- Added an MFEM example for the eikonal equation. This new solver is based on
|
||||
the proximal Galerkin method introduced by Keith and Surowiec.
|
||||
|
||||
- Added a new toy miniapp that animates an interesting fidget spiral cone toy.
|
||||
See miniapps/toys/spiral.cpp.
|
||||
|
||||
- Added a command line option to all miniapps (`-p` or `--send-port`) for
|
||||
specifying the GLVis server socket port (19916 by default).
|
||||
|
||||
@@ -56,6 +78,9 @@ GPU computing
|
||||
high-order transfer operators. New kernels can be offloaded as device
|
||||
kernels. Example usage may be found in lor-transfer.cpp under miniapps/tools.
|
||||
|
||||
- Added support for GPU accelerated FindPointsGSLIB. Note that this will require
|
||||
the users to switch from gslib v1.0.7 to v1.0.9.
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
- Added support for SUNDIALS v7. See the section "API changes" for some small
|
||||
@@ -73,10 +98,39 @@ Miscellaneous
|
||||
|
||||
- Added support for custom interpolation procedure in FindPointsGSLIB.
|
||||
|
||||
- `FiniteElementSpace` has new methods to directly set prolongation and
|
||||
restriction operators to arbitrary sparse matrices.
|
||||
|
||||
- There are new convenience constructors for NURBS patches and knot vectors.
|
||||
|
||||
- Added convenience methods for manipulating boundary attribute marker arrays;
|
||||
`(Par)Mesh::MarkExternalBoundaries`, `(Par)Mesh::UnmarkInternalBoundaries`,
|
||||
`(Par)Mesh::MarkNamedBoundaries`, and `(Par)Mesh::UnmarkNamedBoundaries`.
|
||||
See examples `ex1.cpp`, `ex1p.cpp`, and `ex11p.cpp` for basic usage.
|
||||
|
||||
- Added `(Par)Mesh::GetExteriorFaceMarker` for identifying faces on the
|
||||
exterior of the mesh irrespective of their presence in the list of "boundary
|
||||
elements".
|
||||
|
||||
- Added methods to `(Par)FiniteElementSpace` to identify all degrees of freedom
|
||||
located on the exterior of the domain without reference to the list of
|
||||
"boundary elements"; `GetExteriorVDofs` and `GetExteriorTrueDofs`.
|
||||
|
||||
- `LinearFormIntegrator` and `NonlinearFormIntegrator` (including
|
||||
`BilinearFormIntegrator`) now all inherit from a base class `Integrator`
|
||||
that combines some logic related to selecting quadrature rules. This includes
|
||||
a virtual method `Integrator::GetDefaultIntegrationRule`, which should be
|
||||
favored over directly defining a default integration rule in the element-level
|
||||
assembly routines (although the latter is still possible, by leaving the new
|
||||
virtual method as its default base implementation of returning `NULL`).
|
||||
|
||||
API changes
|
||||
-----------
|
||||
- API change: in class GridFunction, 'fec' was renamed to 'fec_owned'.
|
||||
|
||||
- API change: `RiemannSolver` was renamed to `NumericalFlux` (the old name has
|
||||
been been depracated through typedef)
|
||||
|
||||
- API change: support for SUNDIALS v7:
|
||||
* the SUNDIALS types `realtype` and `booleantype` are no longer defined by v7
|
||||
and therefore MFEM now uses the new type names `sunrealtype` and
|
||||
|
||||
+36
-19
@@ -618,15 +618,37 @@ set(MASTER_HEADERS
|
||||
${PROJECT_SOURCE_DIR}/mfem.hpp
|
||||
${PROJECT_SOURCE_DIR}/mfem-performance.hpp)
|
||||
|
||||
set(_lib_path "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON CACHE BOOL "")
|
||||
set(CMAKE_INSTALL_RPATH "${_lib_path}" CACHE PATH "")
|
||||
set(CMAKE_INSTALL_NAME_DIR "${_lib_path}" CACHE PATH "")
|
||||
# Installation options (we use GNUInstallDirs but prefer lib by default)
|
||||
set(MFEM_USE_GNUINSTALLDIRS OFF CACHE BOOL
|
||||
"Use CMAKE_INSTALL_LIBDIR as defined by the GNUInstallDirs CMake module.")
|
||||
if (NOT MFEM_USE_GNUINSTALLDIRS)
|
||||
mfem_cache_path(CMAKE_INSTALL_LIBDIR "lib" "Object code libraries (lib)")
|
||||
endif()
|
||||
include(GNUInstallDirs)
|
||||
mfem_cache_path(INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}"
|
||||
"Relative or absolute path for installing header files.")
|
||||
mfem_cache_path(INSTALL_BIN_DIR "${CMAKE_INSTALL_BINDIR}"
|
||||
"Relative or absolute path for installing the binaries.")
|
||||
mfem_cache_path(INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR}"
|
||||
"Relative or absolute path for installing the library.")
|
||||
mfem_cache_path(INSTALL_SHARE_DIR "${CMAKE_INSTALL_DATAROOTDIR}"
|
||||
"Relative or absolute path for installing shared data.")
|
||||
# other options: "share/mfem/cmake", "lib/mfem/cmake"
|
||||
mfem_cache_path(INSTALL_CMAKE_DIR "${INSTALL_LIB_DIR}/cmake/mfem"
|
||||
"Relative or absolute path for installing cmake config files.")
|
||||
|
||||
set(MFEM_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
|
||||
"The MFEM source directory" FORCE)
|
||||
set(MFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX} CACHE PATH
|
||||
"The MFEM install directory" FORCE)
|
||||
mfem_path_to_fullpath("${INSTALL_LIB_DIR}" "${CMAKE_INSTALL_PREFIX}" _lib_path)
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON CACHE BOOL "")
|
||||
if(NOT DEFINED CMAKE_INSTALL_RPATH)
|
||||
set(CMAKE_INSTALL_RPATH "${_lib_path}")
|
||||
endif()
|
||||
if(NOT DEFINED CMAKE_INSTALL_NAME_DIR)
|
||||
set(CMAKE_INSTALL_NAME_DIR "${_lib_path}")
|
||||
endif()
|
||||
|
||||
# Variables used when generating _config.hpp, and config.mk
|
||||
set(MFEM_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(MFEM_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
# Declaring the library
|
||||
mfem_add_library(mfem ${SOURCES} ${HEADERS} ${MASTER_HEADERS})
|
||||
@@ -745,7 +767,11 @@ endif()
|
||||
# Create a target for all miniapps and, optionally, enable it.
|
||||
set(MFEM_ALL_MINIAPPS_TARGET_NAME miniapps)
|
||||
add_mfem_target(${MFEM_ALL_MINIAPPS_TARGET_NAME} ${MFEM_ENABLE_MINIAPPS})
|
||||
add_subdirectory(miniapps EXCLUDE_FROM_ALL)
|
||||
if (MFEM_ENABLE_MINIAPPS)
|
||||
add_subdirectory(miniapps) #install miniapps if enabled
|
||||
else()
|
||||
add_subdirectory(miniapps EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# Target to build all executables, i.e. everything.
|
||||
add_custom_target(exec)
|
||||
@@ -795,15 +821,6 @@ add_subdirectory(doc)
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
message(STATUS "CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
|
||||
set(INSTALL_INCLUDE_DIR include
|
||||
CACHE PATH "Relative path for installing header files.")
|
||||
set(INSTALL_BIN_DIR bin
|
||||
CACHE PATH "Relative path for installing the binaries.")
|
||||
set(INSTALL_LIB_DIR lib
|
||||
CACHE PATH "Relative path for installing the library.")
|
||||
# other options: "share/mfem/cmake", "lib/mfem/cmake"
|
||||
set(INSTALL_CMAKE_DIR lib/cmake/mfem
|
||||
CACHE PATH "Relative path for installing cmake config files.")
|
||||
|
||||
target_include_directories(mfem BEFORE
|
||||
PUBLIC
|
||||
@@ -828,7 +845,7 @@ foreach(Header mfem.hpp mfem-performance.hpp)
|
||||
endforeach()
|
||||
install(FILES ${MASTER_HEADERS} DESTINATION ${INSTALL_INCLUDE_DIR}/mfem)
|
||||
|
||||
# Install the headers; currently, the miniapps headers are excluded
|
||||
# Install the headers (except common miniapp which is installed from its subdir)
|
||||
install(DIRECTORY ${MFEM_SOURCE_DIRS}
|
||||
DESTINATION ${INSTALL_INCLUDE_DIR}/mfem
|
||||
FILES_MATCHING PATTERN "*.hpp")
|
||||
|
||||
@@ -220,9 +220,10 @@ An optional installation of the library and the headers can be performed with
|
||||
|
||||
make install [PREFIX=<dir>]
|
||||
|
||||
The library will be installed in $(PREFIX)/lib, the headers in
|
||||
$(PREFIX)/include, and the configuration makefile (config.mk) in
|
||||
$(PREFIX)/share/mfem. The PREFIX option can also be set during configuration.
|
||||
The library will be installed in ${PREFIX}/lib, the headers in
|
||||
${PREFIX}/include, and the configuration and testing makefiles (config.mk and
|
||||
test.mk) in ${PREFIX}/share/mfem. The PREFIX option can also be set during
|
||||
configuration.
|
||||
|
||||
Information about the current build configuration can be viewed using
|
||||
|
||||
@@ -271,8 +272,9 @@ Build options:
|
||||
|
||||
Installation options:
|
||||
PREFIX - Specify the installation directory. The library (libmfem.a) will be
|
||||
installed in $(PREFIX)/lib, the headers in $(PREFIX)/include, and
|
||||
the configuration makefile (config.mk) in $(PREFIX)/share/mfem.
|
||||
installed in ${PREFIX}/lib, the headers in ${PREFIX}/include, and
|
||||
the configuration and testing makefiles (config.mk and test.mk) in
|
||||
${PREFIX}/share/mfem.
|
||||
INSTALL - Specify the install program, default = /usr/bin/install
|
||||
INSTALL_DEF_PERM - Specify the default install permissions. This affects
|
||||
headers and configuration makefiles, default = 644
|
||||
@@ -791,14 +793,14 @@ The specific libraries and their options are:
|
||||
Versions: 1.9.3
|
||||
|
||||
- GSLIB (optional), used when MFEM_USE_GSLIB = YES. The gslib library must be
|
||||
built prior to the MFEM build, as follows: download gslib-1.0.7, untar it at
|
||||
the same level as MFEM and create a symbolic link: "ln -s gslib-1.0.7 gslib".
|
||||
built prior to the MFEM build, as follows: download gslib-1.0.9, untar it at
|
||||
the same level as MFEM and create a symbolic link: "ln -s gslib-1.0.9 gslib".
|
||||
Build gslib in parallel or in serial based on the desired MFEM build: "make
|
||||
clean; make CC=mpicc" or "make clean; make CC=gcc MPI=0". Build MFEM with
|
||||
MFEM_USE_GSLIB=YES.
|
||||
URL: https://github.com/gslib/gslib/archive/v1.0.7.tar.gz
|
||||
URL: https://github.com/gslib/gslib/archive/v1.0.9.tar.gz
|
||||
Options: GSLIB_OPT, GSLIB_LIB.
|
||||
Versions: GSLIB >= 1.0.7.
|
||||
Versions: GSLIB >= 1.0.9.
|
||||
|
||||
- ALGOIM (optional), used when MFEM_USE_ALGOIM=YES. The library provides only
|
||||
headers so it just needs to be downloaded at the same level as MFEM. Download
|
||||
@@ -980,8 +982,20 @@ or
|
||||
cmake --build . --config Release --target install [Xcode]
|
||||
cmake --build . --config Release --target INSTALL [Visual Studio]
|
||||
|
||||
The library will be installed in <PREFIX>/lib, the headers in <PREFIX>/include,
|
||||
and the configuration CMake files in <PREFIX>/lib/cmake/mfem.
|
||||
By default, the library will be installed in ${CMAKE_INSTALL_PREFIX}/lib, the
|
||||
headers in ${CMAKE_INSTALL_PREFIX}/include, the configuration CMake files in
|
||||
${CMAKE_INSTALL_PREFIX}/lib/cmake/mfem, and the configuration and testing GNU
|
||||
make files in ${CMAKE_INSTALL_PREFIX}/share/mfem. For fine-tuning the
|
||||
installation directories the following variables can be used:
|
||||
INSTALL_INCLUDE_DIR, INSTALL_LIB_DIR, INSTALL_BIN_DIR (e.g. for dll files on
|
||||
Windows), INSTALL_SHARE_DIR, and INSTALL_CMAKE_DIR; alternatively, with lower
|
||||
precedence, the CMake GNUInstallDirs variables can also be used:
|
||||
CMAKE_INSTALL_INCLUDEDIR, CMAKE_INSTALL_LIBDIR, CMAKE_INSTALL_BINDIR and
|
||||
CMAKE_INSTALL_DATAROOTDIR. Note that the default for INSTALL_LIB_DIR and
|
||||
CMAKE_INSTALL_LIBDIR is lib. This is in contrast to the default behavior for
|
||||
GNUInstallDirs, which defines a platform-dependent default value for
|
||||
CMAKE_INSTALL_LIBDIR (lib or lib64 or lib/<multiarch-tuple> on Debian). To
|
||||
restore this behavior, the user can set MFEM_USE_GNUINSTALLDIRS=YES.
|
||||
|
||||
|
||||
Configuration variables (CMake)
|
||||
|
||||
@@ -117,8 +117,8 @@ macro (MULTIPASS_SOURCE_RUNS includes libraries source runs language)
|
||||
math (EXPR _tmp "${MULTIPASS_TEST_COUNT} + 1") # Why can't I add to a cache variable?
|
||||
set (MULTIPASS_TEST_COUNT ${_tmp} CACHE INTERNAL "Unique test ID")
|
||||
set (testname MULTIPASS_TEST_${MULTIPASS_TEST_COUNT}_${runs})
|
||||
set (CMAKE_REQUIRED_INCLUDES ${includes})
|
||||
set (CMAKE_REQUIRED_LIBRARIES ${libraries})
|
||||
set (CMAKE_REQUIRED_INCLUDES ${includes} ${MPI_${language}_INCLUDE_PATH})
|
||||
set (CMAKE_REQUIRED_LIBRARIES ${libraries} ${MPI_${language}_LIBRARIES})
|
||||
if(${language} STREQUAL "C")
|
||||
check_c_source_runs ("${source}" ${testname})
|
||||
elseif(${language} STREQUAL "CXX")
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
# - SLEPC_INCLUDE_DIRS
|
||||
# - SLEPC_LIBRARIES
|
||||
|
||||
set(SLEPc_REQUIRED_PACKAGES "PETSC" CACHE STRING
|
||||
set(SLEPc_REQUIRED_PACKAGES "PETSC" "MPI" CACHE STRING
|
||||
"Additional packages required by SLEPc")
|
||||
|
||||
include(MfemCmakeUtilities)
|
||||
|
||||
@@ -138,6 +138,8 @@ macro(add_mfem_miniapp MFEM_EXE_NAME)
|
||||
# Actually add the executable
|
||||
mfem_add_executable(${MFEM_EXE_NAME} ${MAIN_LIST}
|
||||
${EXTRA_SOURCES_LIST} ${EXTRA_HEADERS_LIST})
|
||||
install(TARGETS ${MFEM_EXE_NAME}
|
||||
RUNTIME DESTINATION miniapps)
|
||||
add_dependencies(${MFEM_ALL_MINIAPPS_TARGET_NAME} ${MFEM_EXE_NAME})
|
||||
add_dependencies(${MFEM_EXE_NAME} ${MFEM_EXEC_PREREQUISITES_TARGET_NAME})
|
||||
|
||||
@@ -825,6 +827,20 @@ function(mfem_get_target_options Target CompileOptsVar LinkOptsVar)
|
||||
endfunction(mfem_get_target_options)
|
||||
|
||||
|
||||
#
|
||||
# If ${Path} is not an absolute path, assign ${Prefix}/${Path} to the variable
|
||||
# ${OutVar}. If ${Path} is an absolute path, assign ${Path} to the variable
|
||||
# ${OutVar}.
|
||||
#
|
||||
function(mfem_path_to_fullpath Path Prefix OutVar)
|
||||
if(IS_ABSOLUTE "${Path}")
|
||||
set(${OutVar} "${Path}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${OutVar} "${Prefix}/${Path}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
#
|
||||
# Function that creates 'config.mk' from 'config.mk.in' for the both the
|
||||
# build- and the install-locations and define install rules for 'config.mk'
|
||||
@@ -991,9 +1007,12 @@ function(mfem_export_mk_files)
|
||||
"${PROJECT_BINARY_DIR}/config/test.mk" COPYONLY)
|
||||
|
||||
# Update variables for the install-tree version of 'config.mk'
|
||||
set(MFEM_INC_DIR "${CMAKE_INSTALL_PREFIX}/include")
|
||||
set(MFEM_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
set(MFEM_TEST_MK "${CMAKE_INSTALL_PREFIX}/share/mfem/test.mk")
|
||||
mfem_path_to_fullpath(
|
||||
"${INSTALL_INCLUDE_DIR}" "${CMAKE_INSTALL_PREFIX}" MFEM_INC_DIR)
|
||||
mfem_path_to_fullpath(
|
||||
"${INSTALL_LIB_DIR}" "${CMAKE_INSTALL_PREFIX}" MFEM_LIB_DIR)
|
||||
mfem_path_to_fullpath(
|
||||
"${INSTALL_SHARE_DIR}/mfem/test.mk" "${CMAKE_INSTALL_PREFIX}" MFEM_TEST_MK)
|
||||
set(MFEM_CONFIG_EXTRA "")
|
||||
|
||||
# Create the install-tree version of 'config.mk'
|
||||
@@ -1003,8 +1022,30 @@ function(mfem_export_mk_files)
|
||||
|
||||
# Install rules for 'config.mk' and 'test.mk'
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/config/test.mk
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mfem/)
|
||||
DESTINATION ${INSTALL_SHARE_DIR}/mfem/)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/config/config-install.mk
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mfem/ RENAME config.mk)
|
||||
DESTINATION ${INSTALL_SHARE_DIR}/mfem/
|
||||
RENAME config.mk)
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
#
|
||||
# Function similar to the macro _GNUInstallDirs_cache_path from the module
|
||||
# GNUInstallDirs. Used to process variables like INSTALL_LIB_DIR if they are
|
||||
# set on the cmake command line without specifying type: -DINSTALL_LIB_DIR=lib.
|
||||
# Without this special treatment, relative paths are expanded to full paths
|
||||
# and we want to avoid that.
|
||||
#
|
||||
function(mfem_cache_path PathVar DefaultPath HelpStr)
|
||||
if(NOT DEFINED ${PathVar})
|
||||
set(${PathVar} "${DefaultPath}" CACHE PATH "${HelpStr}")
|
||||
endif()
|
||||
get_property(cache_type CACHE ${PathVar} PROPERTY TYPE)
|
||||
if(cache_type STREQUAL "UNINITIALIZED")
|
||||
file(TO_CMAKE_PATH "${${PathVar}}" cmakepath)
|
||||
set_property(CACHE ${PathVar} PROPERTY TYPE PATH)
|
||||
set_property(CACHE ${PathVar} PROPERTY VALUE "${cmakepath}")
|
||||
set_property(CACHE ${PathVar} PROPERTY HELPSTRING "${HelpStr}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
+8
-3
@@ -163,13 +163,18 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 6. Determine the list of true (i.e. 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.
|
||||
// the external boundary attributes from the mesh as essential (Dirichlet)
|
||||
// and converting them to a list of true dofs.
|
||||
Array<int> ess_tdof_list;
|
||||
if (mesh.bdr_attributes.Size())
|
||||
{
|
||||
Array<int> ess_bdr(mesh.bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
ess_bdr = 0;
|
||||
// Apply boundary conditions on all external boundaries:
|
||||
mesh.MarkExternalBoundaries(ess_bdr);
|
||||
// Boundary conditions can also be applied based on named attributes:
|
||||
// mesh.MarkNamedBoundaries(set_name, ess_bdr)
|
||||
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -192,7 +192,11 @@ int main(int argc, char *argv[])
|
||||
if (pmesh->bdr_attributes.Size())
|
||||
{
|
||||
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
|
||||
ess_bdr = 1;
|
||||
ess_bdr = 0;
|
||||
// Apply boundary conditions on all external boundaries:
|
||||
pmesh->MarkExternalBoundaries(ess_bdr);
|
||||
// Boundary conditions can also be applied based on named attributes:
|
||||
// pmesh->MarkNamedBoundaries(set_name, ess_bdr)
|
||||
}
|
||||
|
||||
ParBilinearForm *a = new ParBilinearForm(fespace);
|
||||
|
||||
+8
-3
@@ -190,13 +190,18 @@ int main(int argc, char *argv[])
|
||||
|
||||
// 8. 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.
|
||||
// by marking all the external 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 = 1;
|
||||
ess_bdr = 0;
|
||||
// Apply boundary conditions on all external boundaries:
|
||||
pmesh.MarkExternalBoundaries(ess_bdr);
|
||||
// Boundary conditions can also be applied based on named attributes:
|
||||
// pmesh.MarkNamedBoundaries(set_name, ess_bdr)
|
||||
|
||||
fespace.GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ int main(int argc, char *argv[])
|
||||
// 7. Set up the linear form b(.) which corresponds to the right-hand side of
|
||||
// the FEM linear system.
|
||||
ComplexLinearForm b(fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
b = 0.0;
|
||||
|
||||
// 8. Define the solution vector u as a complex finite element grid function
|
||||
// corresponding to fespace. Initialize u with initial guess of 1+0i or
|
||||
|
||||
+1
-1
@@ -235,7 +235,7 @@ int main(int argc, char *argv[])
|
||||
// 9. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system.
|
||||
ParComplexLinearForm b(fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
b = 0.0;
|
||||
|
||||
// 10. Define the solution vector u as a parallel complex finite element grid
|
||||
// function corresponding to fespace. Initialize u with initial guess of
|
||||
|
||||
+1
-1
@@ -347,7 +347,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
b.AddDomainIntegrator(NULL, new VectorFEDomainLFIntegrator(f));
|
||||
}
|
||||
b.Vector::operator=(0.0);
|
||||
b = 0.0;
|
||||
b.Assemble();
|
||||
|
||||
// 11. Define the solution vector x as a complex finite element grid function
|
||||
|
||||
+1
-1
@@ -392,7 +392,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
b.AddDomainIntegrator(NULL, new VectorFEDomainLFIntegrator(f));
|
||||
}
|
||||
b.Vector::operator=(0.0);
|
||||
b = 0.0;
|
||||
b.Assemble();
|
||||
|
||||
// 13. Define the solution vector x as a parallel complex finite element grid
|
||||
|
||||
+1
-1
@@ -318,7 +318,7 @@ int main(int argc, char *argv[])
|
||||
// 10. Set up the parallel linear form b(.) which corresponds to the
|
||||
// right-hand side of the FEM linear system.
|
||||
ParComplexLinearForm b(&fespace, conv);
|
||||
b.Vector::operator=(0.0);
|
||||
b = 0.0;
|
||||
|
||||
// 11a. Define the solution vector u as a parallel complex finite element
|
||||
// grid function corresponding to fespace. Initialize u to equal zero.
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ public:
|
||||
DG_Solver(SparseMatrix &M_, SparseMatrix &K_, const FiniteElementSpace &fes)
|
||||
: M(M_),
|
||||
K(K_),
|
||||
prec(fes.GetFE(0)->GetDof(),
|
||||
prec(fes.GetTypicalFE()->GetDof(),
|
||||
BlockILU::Reordering::MINIMUM_DISCARDED_FILL),
|
||||
dt(-1.0)
|
||||
{
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ public:
|
||||
linear_solver(M.GetComm()),
|
||||
dt(-1.0)
|
||||
{
|
||||
int block_size = fes.GetFE(0)->GetDof();
|
||||
int block_size = fes.GetTypicalFE()->GetDof();
|
||||
if (prec_type == PrecType::ILU)
|
||||
{
|
||||
prec = new BlockILU(block_size,
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "mfem.hpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace mfem;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// 1. Initialize MPI and HYPRE.
|
||||
Mpi::Init();
|
||||
int num_procs = Mpi::WorldSize();
|
||||
int myid = Mpi::WorldRank();
|
||||
Hypre::Init();
|
||||
|
||||
//Mesh mesh = Mesh::MakeCartesian3D(2, 2 ,2, Element::Type::HEXAHEDRON);
|
||||
Mesh mesh = Mesh::MakeCartesian3D(2, 2, 2, Element::Type::TETRAHEDRON);
|
||||
|
||||
// Build faces and boundary
|
||||
mesh.FinalizeTopology();
|
||||
mesh.Finalize();
|
||||
|
||||
// Changing element and boundary attributes
|
||||
for (int i=0; i<mesh.GetNE(); ++i)
|
||||
{
|
||||
mesh.SetAttribute(i, myid + 1);
|
||||
}
|
||||
|
||||
for (int i=0; i<mesh.GetNBE(); ++i)
|
||||
{
|
||||
mesh.SetBdrAttribute(i, 100);
|
||||
}
|
||||
|
||||
mesh.SetAttributes();
|
||||
|
||||
// Add internal boundary facets used for integrators
|
||||
// TODO: what should be added here?
|
||||
|
||||
// Finalize connectivity and topology (is this even needed?)
|
||||
mesh.FinalizeTopology();
|
||||
mesh.Finalize(true);
|
||||
|
||||
// Make sure mesh is non-conforming
|
||||
mesh.EnsureNCMesh(true);
|
||||
|
||||
// Make parallel mesh
|
||||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||||
mesh.Clear();
|
||||
pmesh.EnsureNCMesh(true);
|
||||
|
||||
// Refinement
|
||||
Array<Refinement> refinements;
|
||||
refinements.Append(Refinement(0)); // Local element 0 on this rank
|
||||
|
||||
pmesh.GeneralRefinement(refinements);
|
||||
pmesh.SetAttributes();
|
||||
|
||||
{
|
||||
ostringstream mesh_name;
|
||||
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
|
||||
|
||||
ofstream mesh_ofs(mesh_name.str().c_str());
|
||||
mesh_ofs.precision(8);
|
||||
pmesh.Print(mesh_ofs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
DG_Solver(SparseMatrix &M_, SparseMatrix &K_, const FiniteElementSpace &fes)
|
||||
: M(M_),
|
||||
K(K_),
|
||||
prec(fes.GetFE(0)->GetDof(),
|
||||
prec(fes.GetTypicalFE()->GetDof(),
|
||||
BlockILU::Reordering::MINIMUM_DISCARDED_FILL),
|
||||
dt(-1.0)
|
||||
{
|
||||
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
linear_solver(M.GetComm()),
|
||||
dt(-1.0)
|
||||
{
|
||||
int block_size = fes.GetFE(0)->GetDof();
|
||||
int block_size = fes.GetTypicalFE()->GetDof();
|
||||
if (prec_type == PrecType::ILU)
|
||||
{
|
||||
prec = new BlockILU(block_size,
|
||||
|
||||
@@ -148,8 +148,13 @@ set(SRCS
|
||||
tmop_tools.cpp
|
||||
tmop_amr.cpp
|
||||
gslib.cpp
|
||||
gslib/findpts_local_2.cpp
|
||||
gslib/findpts_local_3.cpp
|
||||
gslib/interpolate_local_2.cpp
|
||||
gslib/interpolate_local_3.cpp
|
||||
transfer.cpp
|
||||
hyperbolic.cpp
|
||||
integrator.cpp
|
||||
)
|
||||
|
||||
set(HDRS
|
||||
@@ -248,6 +253,7 @@ set(HDRS
|
||||
gslib.hpp
|
||||
transfer.hpp
|
||||
hyperbolic.hpp
|
||||
integrator.hpp
|
||||
)
|
||||
|
||||
if (MFEM_USE_SIDRE)
|
||||
|
||||
@@ -1006,7 +1006,7 @@ void BilinearForm::ComputeElementMatrices()
|
||||
}
|
||||
|
||||
int num_elements = fes->GetNE();
|
||||
int num_dofs_per_el = fes->GetFE(0)->GetDof() * fes->GetVDim();
|
||||
int num_dofs_per_el = fes->GetTypicalFE()->GetDof() * fes->GetVDim();
|
||||
|
||||
element_matrices = new DenseTensor(num_dofs_per_el, num_dofs_per_el,
|
||||
num_elements);
|
||||
|
||||
@@ -862,7 +862,7 @@ void EABilinearFormExtension::Assemble()
|
||||
SetupRestrictionOperators(L2FaceValues::SingleValued);
|
||||
|
||||
ne = trial_fes->GetMesh()->GetNE();
|
||||
elemDofs = trial_fes->GetFE(0)->GetDof();
|
||||
elemDofs = trial_fes->GetTypicalFE()->GetDof();
|
||||
|
||||
ea_data.SetSize(ne*elemDofs*elemDofs, Device::GetMemoryType());
|
||||
ea_data.UseDevice(true);
|
||||
@@ -878,9 +878,7 @@ void EABilinearFormExtension::Assemble()
|
||||
integrators[i]->AssembleEA(*a->FESpace(), ea_data, i);
|
||||
}
|
||||
|
||||
faceDofs = trial_fes ->
|
||||
GetTraceElement(0, trial_fes->GetMesh()->GetFaceGeometry(0)) ->
|
||||
GetDof();
|
||||
faceDofs = trial_fes->GetTypicalTraceElement()->GetDof();
|
||||
|
||||
MFEM_VERIFY(a->GetBBFI()->Size() == 0,
|
||||
"Element assembly does not support AddBoundaryIntegrator yet.");
|
||||
|
||||
+106
-75
@@ -508,7 +508,8 @@ void MixedScalarIntegrator::AssembleElementMatrix2(
|
||||
|
||||
elmat.SetSize(test_nd, trial_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int ir_order = this->GetIntegrationOrder(trial_fe, test_fe, Trans);
|
||||
@@ -599,7 +600,7 @@ void MixedVectorIntegrator::AssembleElementMatrix2(
|
||||
|
||||
elmat.SetSize(test_nd, trial_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int ir_order = this->GetIntegrationOrder(trial_fe, test_fe, Trans);
|
||||
@@ -755,7 +756,8 @@ void MixedScalarVectorIntegrator::AssembleElementMatrix2(
|
||||
|
||||
elmat.SetSize(test_nd, trial_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int ir_order = this->GetIntegrationOrder(trial_fe, test_fe, Trans);
|
||||
@@ -805,9 +807,8 @@ void GradientIntegrator::AssembleElementMatrix2(
|
||||
shape.SetSize(test_dof);
|
||||
elmat.SetSize(dim * test_dof, trial_dof);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
|
||||
Trans);
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
elmat = 0.0;
|
||||
elmat_comp.SetSize(test_dof, trial_dof);
|
||||
|
||||
@@ -848,13 +849,41 @@ void GradientIntegrator::AssembleElementMatrix2(
|
||||
const IntegrationRule &GradientIntegrator::GetRule(const FiniteElement
|
||||
&trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
const ElementTransformation &Trans)
|
||||
{
|
||||
int order = Trans.OrderGrad(&trial_fe) + test_fe.GetOrder() + Trans.OrderJ();
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
|
||||
DiffusionIntegrator::DiffusionIntegrator(const IntegrationRule *ir)
|
||||
: BilinearFormIntegrator(ir),
|
||||
Q(nullptr), VQ(nullptr), MQ(nullptr), maps(nullptr), geom(nullptr)
|
||||
{
|
||||
static Kernels kernels;
|
||||
}
|
||||
|
||||
DiffusionIntegrator::DiffusionIntegrator(Coefficient &q,
|
||||
const IntegrationRule *ir)
|
||||
: DiffusionIntegrator(ir)
|
||||
{
|
||||
Q = &q;
|
||||
}
|
||||
|
||||
DiffusionIntegrator::DiffusionIntegrator(VectorCoefficient &q,
|
||||
const IntegrationRule *ir)
|
||||
: DiffusionIntegrator(ir)
|
||||
{
|
||||
VQ = &q;
|
||||
}
|
||||
|
||||
DiffusionIntegrator::DiffusionIntegrator(MatrixCoefficient &q,
|
||||
const IntegrationRule *ir)
|
||||
: DiffusionIntegrator(ir)
|
||||
{
|
||||
MQ = &q;
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssembleElementMatrix
|
||||
( const FiniteElement &el, ElementTransformation &Trans,
|
||||
DenseMatrix &elmat )
|
||||
@@ -892,21 +921,7 @@ void DiffusionIntegrator::AssembleElementMatrix
|
||||
#endif
|
||||
elmat.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
|
||||
|
||||
const NURBSFiniteElement *NURBSFE =
|
||||
dynamic_cast<const NURBSFiniteElement *>(&el);
|
||||
|
||||
bool deleteRule = false;
|
||||
if (NURBSFE && patchRules)
|
||||
{
|
||||
const int patch = NURBSFE->GetPatch();
|
||||
const int* ijk = NURBSFE->GetIJK();
|
||||
Array<const KnotVector*>& kv = NURBSFE->KnotVectors();
|
||||
ir = &patchRules->GetElementRule(NURBSFE->GetElement(), patch, ijk, kv,
|
||||
deleteRule);
|
||||
}
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
@@ -941,11 +956,6 @@ void DiffusionIntegrator::AssembleElementMatrix
|
||||
AddMult_a_AAt(w, dshapedxt, elmat);
|
||||
}
|
||||
}
|
||||
|
||||
if (deleteRule)
|
||||
{
|
||||
delete ir;
|
||||
}
|
||||
}
|
||||
|
||||
void DiffusionIntegrator::AssembleElementMatrix2(
|
||||
@@ -991,8 +1001,7 @@ void DiffusionIntegrator::AssembleElementMatrix2(
|
||||
#endif
|
||||
elmat.SetSize(te_nd, tr_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe);
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
@@ -1069,8 +1078,8 @@ void DiffusionIntegrator::AssembleElementVector(
|
||||
|
||||
elvect.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
elvect = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
@@ -1235,7 +1244,6 @@ real_t DiffusionIntegrator::ComputeFluxEnergy
|
||||
|
||||
int order = 2 * fluxelem.GetOrder(); // <--
|
||||
const IntegrationRule *ir = &IntRules.Get(fluxelem.GetGeomType(), order);
|
||||
|
||||
real_t energy = 0.0;
|
||||
if (d_energy) { *d_energy = 0.0; }
|
||||
|
||||
@@ -1310,6 +1318,17 @@ const IntegrationRule &DiffusionIntegrator::GetRule(
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
}
|
||||
|
||||
MassIntegrator::MassIntegrator(const IntegrationRule *ir)
|
||||
: BilinearFormIntegrator(ir), Q(nullptr), maps(nullptr), geom(nullptr)
|
||||
{
|
||||
static Kernels kernels;
|
||||
}
|
||||
|
||||
MassIntegrator::MassIntegrator(Coefficient &q, const IntegrationRule *ir)
|
||||
: MassIntegrator(ir)
|
||||
{
|
||||
Q = &q;
|
||||
}
|
||||
|
||||
void MassIntegrator::AssembleElementMatrix
|
||||
( const FiniteElement &el, ElementTransformation &Trans,
|
||||
@@ -1325,8 +1344,8 @@ void MassIntegrator::AssembleElementMatrix
|
||||
elmat.SetSize(nd);
|
||||
shape.SetSize(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, Trans);
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
@@ -1360,9 +1379,7 @@ void MassIntegrator::AssembleElementMatrix2(
|
||||
shape.SetSize(tr_nd);
|
||||
te_shape.SetSize(te_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule :
|
||||
&GetRule(trial_fe, test_fe, Trans);
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
@@ -1385,7 +1402,7 @@ void MassIntegrator::AssembleElementMatrix2(
|
||||
|
||||
const IntegrationRule &MassIntegrator::GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
const ElementTransformation &Trans)
|
||||
{
|
||||
// int order = trial_fe.GetOrder() + test_fe.GetOrder();
|
||||
const int order = trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderW();
|
||||
@@ -1461,7 +1478,8 @@ void ConvectionIntegrator::AssembleElementMatrix(
|
||||
|
||||
Vector vec1;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = Trans.OrderGrad(&el) + Trans.Order() + el.GetOrder();
|
||||
@@ -1502,7 +1520,7 @@ void GroupConvectionIntegrator::AssembleElementMatrix(
|
||||
shape.SetSize(nd);
|
||||
grad.SetSize(nd,dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = Trans.OrderGrad(&el) + el.GetOrder();
|
||||
@@ -1544,7 +1562,7 @@ void GroupConvectionIntegrator::AssembleElementMatrix(
|
||||
|
||||
const IntegrationRule &ConvectionIntegrator::GetRule(
|
||||
const FiniteElement &trial_fe, const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
const ElementTransformation &Trans)
|
||||
{
|
||||
int order = Trans.OrderGrad(&trial_fe) + Trans.Order() + test_fe.GetOrder();
|
||||
|
||||
@@ -1552,7 +1570,7 @@ const IntegrationRule &ConvectionIntegrator::GetRule(
|
||||
}
|
||||
|
||||
const IntegrationRule &ConvectionIntegrator::GetRule(
|
||||
const FiniteElement &el, ElementTransformation &Trans)
|
||||
const FiniteElement &el, const ElementTransformation &Trans)
|
||||
{
|
||||
return GetRule(el,el,Trans);
|
||||
}
|
||||
@@ -1581,7 +1599,8 @@ void VectorMassIntegrator::AssembleElementMatrix
|
||||
mcoeff.SetSize(vdim);
|
||||
}
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = 2 * el.GetOrder() + Trans.OrderW() + Q_order;
|
||||
@@ -1664,7 +1683,8 @@ void VectorMassIntegrator::AssembleElementMatrix2(
|
||||
mcoeff.SetSize(vdim);
|
||||
}
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = (trial_fe.GetOrder() + test_fe.GetOrder() +
|
||||
@@ -1739,7 +1759,7 @@ void VectorFEDivergenceIntegrator::AssembleElementMatrix2(
|
||||
|
||||
elmat.SetSize(test_nd, trial_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder() - 1; // <--
|
||||
@@ -1790,7 +1810,7 @@ void VectorFEWeakDivergenceIntegrator::AssembleElementMatrix2(
|
||||
|
||||
elmat.SetSize(test_nd, trial_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
// The integrand on the reference element is:
|
||||
@@ -1883,7 +1903,7 @@ void VectorFECurlIntegrator::AssembleElementMatrix2(
|
||||
|
||||
elmat.SetSize(test_nd, trial_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder() - 1; // <--
|
||||
@@ -2047,7 +2067,7 @@ void DerivativeIntegrator::AssembleElementMatrix2 (
|
||||
invdfdx.SetSize(dim, spaceDim);
|
||||
shape.SetSize (test_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
@@ -2114,7 +2134,7 @@ void CurlCurlIntegrator::AssembleElementMatrix
|
||||
if (MQ) { M.SetSize(dimc); }
|
||||
if (DQ) { D.SetSize(dimc); }
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
@@ -2191,7 +2211,8 @@ void CurlCurlIntegrator::AssembleElementMatrix2(const FiniteElement &trial_fe,
|
||||
if (MQ) { M.SetSize(dimc); }
|
||||
if (DQ) { D.SetSize(dimc); }
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order;
|
||||
@@ -2383,7 +2404,8 @@ void VectorCurlCurlIntegrator::AssembleElementMatrix(
|
||||
Jadj.SetSize(dim);
|
||||
#endif
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
// use the same integration rule as diffusion
|
||||
@@ -2431,7 +2453,8 @@ real_t VectorCurlCurlIntegrator::GetElementEnergy(
|
||||
#endif
|
||||
DenseMatrix elfun_mat(elfun.GetData(), dof, dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
if (ir == NULL)
|
||||
{
|
||||
// use the same integration rule as diffusion
|
||||
@@ -2514,8 +2537,8 @@ void MixedCurlIntegrator::AssembleElementMatrix2(
|
||||
|
||||
real_t c;
|
||||
Vector d_col;
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = trial_fe.GetOrder() + test_fe.GetOrder() + Trans.OrderJ();
|
||||
@@ -2583,7 +2606,7 @@ void VectorFEMassIntegrator::AssembleElementMatrix(
|
||||
elmat.SetSize(dof);
|
||||
elmat = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
// int order = 2 * el.GetOrder();
|
||||
@@ -2628,6 +2651,8 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
|
||||
const FiniteElement &trial_fe, const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans, DenseMatrix &elmat)
|
||||
{
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
|
||||
if (test_fe.GetRangeType() == FiniteElement::SCALAR
|
||||
&& trial_fe.GetRangeType() == FiniteElement::VECTOR)
|
||||
{
|
||||
@@ -2651,8 +2676,6 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
|
||||
#endif
|
||||
|
||||
elmat.SetSize(vdim*test_dof, trial_dof);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = (Trans.OrderW() + test_fe.GetOrder() + trial_fe.GetOrder());
|
||||
@@ -2752,7 +2775,6 @@ void VectorFEMassIntegrator::AssembleElementMatrix2(
|
||||
|
||||
elmat.SetSize (test_dof, trial_dof);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = (Trans.OrderW() + test_fe.GetOrder() + trial_fe.GetOrder());
|
||||
@@ -2819,8 +2841,7 @@ void VectorDivergenceIntegrator::AssembleElementMatrix2(
|
||||
|
||||
elmat.SetSize (test_dof, dim*trial_dof);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
|
||||
Trans);
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
|
||||
elmat = 0.0;
|
||||
|
||||
@@ -2853,7 +2874,7 @@ void VectorDivergenceIntegrator::AssembleElementMatrix2(
|
||||
const IntegrationRule &VectorDivergenceIntegrator::GetRule(
|
||||
const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans)
|
||||
const ElementTransformation &Trans)
|
||||
{
|
||||
int order = Trans.OrderGrad(&trial_fe) + test_fe.GetOrder() + Trans.OrderJ();
|
||||
return IntRules.Get(trial_fe.GetGeomType(), order);
|
||||
@@ -2875,7 +2896,7 @@ void DivDivIntegrator::AssembleElementMatrix(
|
||||
#endif
|
||||
elmat.SetSize(dof);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = 2 * el.GetOrder() - 2; // <--- OK for RTk
|
||||
@@ -2922,7 +2943,7 @@ void DivDivIntegrator::AssembleElementMatrix2(
|
||||
#endif
|
||||
elmat.SetSize(te_nd,tr_nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(trial_fe, test_fe, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = 2 * max(test_fe.GetOrder(),
|
||||
@@ -2980,7 +3001,7 @@ void VectorDiffusionIntegrator::AssembleElementMatrix(
|
||||
elmat.SetSize(vdim * dof);
|
||||
pelmat.SetSize(dof);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
ir = &DiffusionIntegrator::GetRule(el,el);
|
||||
@@ -3067,7 +3088,8 @@ void VectorDiffusionIntegrator::AssembleElementVector(
|
||||
DenseMatrix mat_in(elfun.GetData(), dof, vdim);
|
||||
DenseMatrix mat_out(elvect.GetData(), dof, vdim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
if (ir == NULL)
|
||||
{
|
||||
ir = &DiffusionIntegrator::GetRule(el,el);
|
||||
@@ -3090,10 +3112,9 @@ void VectorDiffusionIntegrator::AssembleElementVector(
|
||||
VQ->Eval(vcoeff, Tr, ip);
|
||||
for (int k = 0; k < vdim; ++k)
|
||||
{
|
||||
pelmat *= w*vcoeff(k);
|
||||
const Vector vec_in(mat_in.GetColumn(k), dof);
|
||||
Vector vec_out(mat_out.GetColumn(k), dof);
|
||||
pelmat.AddMult(vec_in, vec_out);
|
||||
pelmat.AddMult_a(w*vcoeff(k), vec_in, vec_out);
|
||||
}
|
||||
}
|
||||
else if (MQ)
|
||||
@@ -3104,9 +3125,8 @@ void VectorDiffusionIntegrator::AssembleElementVector(
|
||||
Vector vec_out(mat_out.GetColumn(ii), dof);
|
||||
for (int jj = 0; jj < vdim; ++jj)
|
||||
{
|
||||
pelmat *= w*mcoeff(ii,jj);
|
||||
const Vector vec_in(mat_in.GetColumn(jj), dof);
|
||||
pelmat.Mult(vec_in, vec_out);
|
||||
pelmat.AddMult_a(w*mcoeff(ii,jj), vec_in, vec_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3152,7 +3172,7 @@ void ElasticityIntegrator::AssembleElementMatrix(
|
||||
|
||||
elmat.SetSize(dof * dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = 2 * Trans.OrderGrad(&el); // correct order?
|
||||
@@ -3161,7 +3181,7 @@ void ElasticityIntegrator::AssembleElementMatrix(
|
||||
|
||||
elmat = 0.0;
|
||||
|
||||
for (int i = 0; i < ir -> GetNPoints(); i++)
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(i);
|
||||
|
||||
@@ -3320,7 +3340,8 @@ real_t ElasticityIntegrator::ComputeFluxEnergy(const FiniteElement &fluxelem,
|
||||
// Use the same integration rule as in AssembleElementMatrix, replacing 'el'
|
||||
// with 'fluxelem' when 'IntRule' is not set.
|
||||
// Should we be using a different (more accurate) rule here?
|
||||
const IntegrationRule *ir = IntRule;
|
||||
|
||||
const IntegrationRule *ir = GetIntegrationRule(fluxelem, Trans);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int order = 2 * Trans.OrderGrad(&fluxelem);
|
||||
@@ -3381,7 +3402,6 @@ real_t ElasticityIntegrator::ComputeFluxEnergy(const FiniteElement &fluxelem,
|
||||
|
||||
energy += w * pt_e;
|
||||
}
|
||||
|
||||
return energy;
|
||||
}
|
||||
|
||||
@@ -3664,10 +3684,15 @@ void DGTraceIntegrator::AssembleFaceMatrix(const FiniteElement &trial_fe1,
|
||||
}
|
||||
|
||||
const IntegrationRule &DGTraceIntegrator::GetRule(
|
||||
Geometry::Type geom, int order, FaceElementTransformations &T)
|
||||
Geometry::Type geom, int order, const ElementTransformation &T)
|
||||
{
|
||||
int int_order = T.Elem1->OrderW() + 2*order;
|
||||
return IntRules.Get(geom, int_order);
|
||||
return IntRules.Get(geom, T.OrderW() + 2*order);
|
||||
}
|
||||
|
||||
const IntegrationRule &DGTraceIntegrator::GetRule(
|
||||
Geometry::Type geom, int order, const FaceElementTransformations &T)
|
||||
{
|
||||
return GetRule(geom, order, *T.Elem1);
|
||||
}
|
||||
|
||||
void DGDiffusionIntegrator::AssembleFaceMatrix(
|
||||
@@ -3719,7 +3744,7 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
|
||||
{
|
||||
const int order = (ndof2) ? max(el1.GetOrder(),
|
||||
el2.GetOrder()) : el1.GetOrder();
|
||||
ir = &GetRule(order, Trans);
|
||||
ir = &GetRule(order, Trans.GetGeometryType());
|
||||
}
|
||||
|
||||
// assemble: < {(Q \nabla u).n},[v] > --> elmat
|
||||
@@ -3898,11 +3923,17 @@ void DGDiffusionIntegrator::AssembleFaceMatrix(
|
||||
}
|
||||
|
||||
const IntegrationRule &DGDiffusionIntegrator::GetRule(
|
||||
int order, FaceElementTransformations &T)
|
||||
int order, Geometry::Type geom)
|
||||
{
|
||||
// order is typically the maximum of the order of the left and right elements
|
||||
// neighboring the given face.
|
||||
return IntRules.Get(T.GetGeometryType(), 2*order);
|
||||
return IntRules.Get(geom, 2*order);
|
||||
}
|
||||
|
||||
const IntegrationRule &DGDiffusionIntegrator::GetRule(
|
||||
int order, FaceElementTransformations &T)
|
||||
{
|
||||
return GetRule(order, T.GetGeometryType());
|
||||
}
|
||||
|
||||
// static method
|
||||
|
||||
+68
-34
@@ -2135,7 +2135,15 @@ public:
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
const ElementTransformation &Trans);
|
||||
protected:
|
||||
const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe,
|
||||
const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const override
|
||||
{
|
||||
return &GetRule(trial_fe, test_fe, trans);
|
||||
}
|
||||
};
|
||||
|
||||
/** Class for integrating the bilinear form $a(u,v) := (Q \nabla u, \nabla v)$ where $Q$
|
||||
@@ -2156,7 +2164,7 @@ public:
|
||||
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
|
||||
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
|
||||
static struct Kernels { Kernels(); } kernels;
|
||||
struct Kernels { Kernels(); };
|
||||
|
||||
protected:
|
||||
Coefficient *Q;
|
||||
@@ -2234,26 +2242,16 @@ private:
|
||||
|
||||
public:
|
||||
/// Construct a diffusion integrator with coefficient Q = 1
|
||||
DiffusionIntegrator(const IntegrationRule *ir = nullptr)
|
||||
: BilinearFormIntegrator(ir),
|
||||
Q(NULL), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL) { }
|
||||
DiffusionIntegrator(const IntegrationRule *ir = nullptr);
|
||||
|
||||
/// Construct a diffusion integrator with a scalar coefficient q
|
||||
DiffusionIntegrator(Coefficient &q, const IntegrationRule *ir = nullptr)
|
||||
: BilinearFormIntegrator(ir),
|
||||
Q(&q), VQ(NULL), MQ(NULL), maps(NULL), geom(NULL) { }
|
||||
DiffusionIntegrator(Coefficient &q, const IntegrationRule *ir = nullptr);
|
||||
|
||||
/// Construct a diffusion integrator with a vector coefficient q
|
||||
DiffusionIntegrator(VectorCoefficient &q,
|
||||
const IntegrationRule *ir = nullptr)
|
||||
: BilinearFormIntegrator(ir),
|
||||
Q(NULL), VQ(&q), MQ(NULL), maps(NULL), geom(NULL) { }
|
||||
DiffusionIntegrator(VectorCoefficient &q, const IntegrationRule *ir = nullptr);
|
||||
|
||||
/// Construct a diffusion integrator with a matrix coefficient q
|
||||
DiffusionIntegrator(MatrixCoefficient &q,
|
||||
const IntegrationRule *ir = nullptr)
|
||||
: BilinearFormIntegrator(ir),
|
||||
Q(NULL), VQ(NULL), MQ(&q), maps(NULL), geom(NULL) { }
|
||||
DiffusionIntegrator(MatrixCoefficient &q, const IntegrationRule *ir = nullptr);
|
||||
|
||||
/** Given a particular Finite Element computes the element stiffness matrix
|
||||
elmat. */
|
||||
@@ -2325,6 +2323,14 @@ public:
|
||||
ApplyPAKernels::Specialization<DIM,D1D,Q1D>::Add();
|
||||
DiagonalPAKernels::Specialization<DIM,D1D,Q1D>::Add();
|
||||
}
|
||||
protected:
|
||||
const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe,
|
||||
const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const override
|
||||
{
|
||||
return &GetRule(trial_fe, test_fe);
|
||||
}
|
||||
};
|
||||
|
||||
/** Class for local mass matrix assembling $a(u,v) := (Q u, v)$ */
|
||||
@@ -2356,15 +2362,13 @@ public:
|
||||
|
||||
MFEM_REGISTER_KERNELS(ApplyPAKernels, ApplyKernelType, (int, int, int));
|
||||
MFEM_REGISTER_KERNELS(DiagonalPAKernels, DiagonalKernelType, (int, int, int));
|
||||
static struct Kernels { Kernels(); } kernels;
|
||||
struct Kernels { Kernels(); };
|
||||
|
||||
public:
|
||||
MassIntegrator(const IntegrationRule *ir = NULL)
|
||||
: BilinearFormIntegrator(ir), Q(NULL), maps(NULL), geom(NULL) { }
|
||||
MassIntegrator(const IntegrationRule *ir = nullptr);
|
||||
|
||||
/// Construct a mass integrator with coefficient q
|
||||
MassIntegrator(Coefficient &q, const IntegrationRule *ir = NULL)
|
||||
: BilinearFormIntegrator(ir), Q(&q), maps(NULL), geom(NULL) { }
|
||||
MassIntegrator(Coefficient &q, const IntegrationRule *ir = NULL);
|
||||
|
||||
/** Given a particular Finite Element computes the element mass matrix
|
||||
elmat. */
|
||||
@@ -2398,7 +2402,7 @@ public:
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
const ElementTransformation &Trans);
|
||||
|
||||
bool SupportsCeed() const override { return DeviceCanUseCeed(); }
|
||||
|
||||
@@ -2410,6 +2414,15 @@ public:
|
||||
ApplyPAKernels::Specialization<DIM,D1D,Q1D>::Add();
|
||||
DiagonalPAKernels::Specialization<DIM,D1D,Q1D>::Add();
|
||||
}
|
||||
|
||||
protected:
|
||||
const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe,
|
||||
const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const override
|
||||
{
|
||||
return &GetRule(trial_fe, test_fe, trans);
|
||||
}
|
||||
};
|
||||
|
||||
/** Mass integrator $(u, v)$ restricted to the boundary of a domain */
|
||||
@@ -2470,13 +2483,22 @@ public:
|
||||
void AddMultTransposePA(const Vector &x, Vector &y) const override;
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &el,
|
||||
ElementTransformation &Trans);
|
||||
const ElementTransformation &Trans);
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
const ElementTransformation &Trans);
|
||||
|
||||
bool SupportsCeed() const override { return DeviceCanUseCeed(); }
|
||||
|
||||
protected:
|
||||
const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe,
|
||||
const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const override
|
||||
{
|
||||
return &GetRule(trial_fe, test_fe, trans);
|
||||
}
|
||||
};
|
||||
|
||||
// Alias for @ConvectionIntegrator.
|
||||
@@ -2941,7 +2963,16 @@ public:
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &trial_fe,
|
||||
const FiniteElement &test_fe,
|
||||
ElementTransformation &Trans);
|
||||
const ElementTransformation &Trans);
|
||||
|
||||
protected:
|
||||
const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe,
|
||||
const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const override
|
||||
{
|
||||
return &GetRule(trial_fe, test_fe, trans);
|
||||
}
|
||||
};
|
||||
|
||||
/// $(Q \nabla \cdot u, \nabla \cdot v)$ for Raviart-Thomas elements
|
||||
@@ -2984,19 +3015,17 @@ public:
|
||||
const Coefficient *GetCoefficient() const { return Q; }
|
||||
};
|
||||
|
||||
/** Integrator for
|
||||
$$
|
||||
(Q \nabla u, \nabla v) = \sum_i (Q \nabla u_i, \nabla v_i) e_i e_i^{\mathrm{T}}
|
||||
$$
|
||||
for vector FE spaces, where $e_i$ is the unit vector in the $i$-th direction.
|
||||
The resulting local element matrix is square, of size <tt> vdim*dof </tt>,
|
||||
/** Class for integrating the bilinear form $a(u,v) := (Q \nabla u, \nabla v)$,
|
||||
where $u=(u_1,\dots,u_n)$ and $v=(v_1,\dots,v_n)$, $u_i$ and $v_i$ are
|
||||
defined by scalar FE through standard transformation.
|
||||
See the constructors' documentation for all Coefficient options.
|
||||
The computed local element matrix is square, of size <tt> vdim*dof </tt>,
|
||||
where \c vdim is the vector dimension space and \c dof is the local degrees
|
||||
of freedom. The integrator is not aware of the true vector dimension and
|
||||
must use \c VectorCoefficient, \c MatrixCoefficient, or a caller-specified
|
||||
value to determine the vector space. For a scalar coefficient, the caller
|
||||
may manually specify the vector dimension or the vector dimension is assumed
|
||||
to be the spatial dimension (i.e. 2-dimension or 3-dimension).
|
||||
*/
|
||||
to be the spatial dimension (i.e. 2-dimension or 3-dimension). */
|
||||
class VectorDiffusionIntegrator : public BilinearFormIntegrator
|
||||
{
|
||||
protected:
|
||||
@@ -3292,7 +3321,10 @@ public:
|
||||
const bool add) override;
|
||||
|
||||
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
|
||||
FaceElementTransformations &T);
|
||||
const FaceElementTransformations &T);
|
||||
|
||||
static const IntegrationRule &GetRule(Geometry::Type geom, int order,
|
||||
const ElementTransformation &T);
|
||||
|
||||
private:
|
||||
void SetupPA(const FiniteElementSpace &fes, FaceType type);
|
||||
@@ -3381,6 +3413,8 @@ public:
|
||||
|
||||
const IntegrationRule &GetRule(int order, FaceElementTransformations &T);
|
||||
|
||||
const IntegrationRule &GetRule(int order, Geometry::Type geom);
|
||||
|
||||
private:
|
||||
void SetupPA(const FiniteElementSpace &fes, FaceType type);
|
||||
};
|
||||
|
||||
@@ -135,7 +135,7 @@ void InitBasis(const FiniteElementSpace &fes,
|
||||
const IntegrationRule &ir,
|
||||
Ceed ceed, CeedBasis *basis)
|
||||
{
|
||||
const mfem::FiniteElement &fe = *fes.GetFE(0);
|
||||
const mfem::FiniteElement &fe = *fes.GetTypicalFE();
|
||||
InitBasisImpl(fes, fe, ir, ceed, basis);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
const int first_index = indices[0];
|
||||
const mfem::FiniteElement &el = *fes.GetFE(first_index);
|
||||
auto &T = *fes.GetMesh()->GetElementTransformation(first_index);
|
||||
MFEM_ASSERT(!integ.GetIntegrationRule(),
|
||||
MFEM_ASSERT(!integ.GetIntRule(),
|
||||
"Mixed mesh integrators should not have an"
|
||||
" IntegrationRule.");
|
||||
const IntegrationRule &ir = GetRule(integ, el, el, T);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace ceed
|
||||
static void InitNativeRestr(const mfem::FiniteElementSpace &fes,
|
||||
Ceed ceed, CeedElemRestriction *restr)
|
||||
{
|
||||
const mfem::FiniteElement *fe = fes.GetFE(0);
|
||||
const mfem::FiniteElement *fe = fes.GetTypicalFE();
|
||||
const int P = fe->GetDof();
|
||||
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
|
||||
const mfem::Table &el_dof = fes.GetElementToDofTable();
|
||||
@@ -51,7 +51,7 @@ static void InitNativeRestr(const mfem::FiniteElementSpace &fes,
|
||||
static void InitLexicoRestr(const mfem::FiniteElementSpace &fes,
|
||||
Ceed ceed, CeedElemRestriction *restr)
|
||||
{
|
||||
const mfem::FiniteElement *fe = fes.GetFE(0);
|
||||
const mfem::FiniteElement *fe = fes.GetTypicalFE();
|
||||
const int P = fe->GetDof();
|
||||
CeedInt compstride = fes.GetOrdering()==Ordering::byVDIM ? 1 : fes.GetNDofs();
|
||||
const mfem::Table &el_dof = fes.GetElementToDofTable();
|
||||
@@ -75,7 +75,7 @@ static void InitLexicoRestr(const mfem::FiniteElementSpace &fes,
|
||||
static void InitRestrictionImpl(const mfem::FiniteElementSpace &fes,
|
||||
Ceed ceed, CeedElemRestriction *restr)
|
||||
{
|
||||
const mfem::FiniteElement *fe = fes.GetFE(0);
|
||||
const mfem::FiniteElement *fe = fes.GetTypicalFE();
|
||||
const mfem::TensorBasisElement * tfe =
|
||||
dynamic_cast<const mfem::TensorBasisElement *>(fe);
|
||||
if ( tfe && tfe->GetDofMap().Size()>0 ) // Native ordering using dof_map
|
||||
@@ -225,7 +225,7 @@ void InitRestriction(const FiniteElementSpace &fes,
|
||||
CeedElemRestriction *restr)
|
||||
{
|
||||
// Check for FES -> basis, restriction in hash tables
|
||||
const mfem::FiniteElement *fe = fes.GetFE(0);
|
||||
const mfem::FiniteElement *fe = fes.GetTypicalFE();
|
||||
const int P = fe->GetDof();
|
||||
const int nelem = fes.GetNE();
|
||||
const int ncomp = fes.GetVDim();
|
||||
|
||||
@@ -120,6 +120,10 @@ public:
|
||||
|
||||
virtual ~ComplexLinearForm();
|
||||
|
||||
/// Assign constant values to the ComplexLinearForm data.
|
||||
ComplexLinearForm &operator=(const std::complex<real_t> & value)
|
||||
{ *lfr = value.real(); *lfi = value.imag(); return *this; }
|
||||
|
||||
ComplexOperator::Convention GetConvention() const { return conv; }
|
||||
void SetConvention(const ComplexOperator::Convention &
|
||||
convention) { conv = convention; }
|
||||
@@ -466,6 +470,10 @@ public:
|
||||
|
||||
virtual ~ParComplexLinearForm();
|
||||
|
||||
/// Assign constant values to the ParComplexLinearForm data.
|
||||
ParComplexLinearForm &operator=(const std::complex<real_t> & value)
|
||||
{ *plfr = value.real(); *plfi = value.imag(); return *this; }
|
||||
|
||||
ComplexOperator::Convention GetConvention() const { return conv; }
|
||||
void SetConvention(const ComplexOperator::Convention &
|
||||
convention) { conv = convention; }
|
||||
|
||||
@@ -719,7 +719,7 @@ ConduitDataCollection::MeshToBlueprintMesh(Mesh *mesh,
|
||||
// copy out. Some other cases (sidre) may actually have contig
|
||||
// allocation but I am not sure how to detect this case from mfem
|
||||
int num_ele = mesh->GetNE();
|
||||
int geom = mesh->GetElementBaseGeometry(0);
|
||||
int geom = mesh->GetTypicalElementGeometry();
|
||||
int idxs_per_ele = Geometry::NumVerts[geom];
|
||||
int num_conn_idxs = num_ele * idxs_per_ele;
|
||||
|
||||
@@ -997,8 +997,7 @@ std::string
|
||||
ConduitDataCollection::MeshFilePattern(const std::string &relay_protocol)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << prefix_path
|
||||
<< name
|
||||
oss << name
|
||||
<< "_"
|
||||
<< to_padded_string(cycle, pad_digits_cycle)
|
||||
<< "/domain_%0"
|
||||
|
||||
+4
-2
@@ -24,7 +24,7 @@ DGMassInverse::DGMassInverse(FiniteElementSpace &fes_orig, Coefficient *coeff,
|
||||
fec(fes_orig.GetMaxElementOrder(),
|
||||
fes_orig.GetMesh()->Dimension(),
|
||||
btype,
|
||||
fes_orig.GetFE(0)->GetMapType()),
|
||||
fes_orig.GetTypicalFE()->GetMapType()),
|
||||
fes(fes_orig.GetMesh(), &fec)
|
||||
{
|
||||
MFEM_VERIFY(fes.IsDGSpace(), "Space must be DG.");
|
||||
@@ -42,7 +42,9 @@ DGMassInverse::DGMassInverse(FiniteElementSpace &fes_orig, Coefficient *coeff,
|
||||
{
|
||||
// original basis to solver basis
|
||||
const auto mode = DofToQuad::TENSOR;
|
||||
d2q = &fes_orig.GetFE(0)->GetDofToQuad(fes.GetFE(0)->GetNodes(), mode);
|
||||
const FiniteElement &fe_orig = *fes_orig.GetTypicalFE();
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
d2q = &fe_orig.GetDofToQuad(fe.GetNodes(), mode);
|
||||
|
||||
int n = d2q->ndof;
|
||||
Array<real_t> B_inv = d2q->B; // deep copy
|
||||
|
||||
@@ -41,8 +41,8 @@ void FillFaceMap(const int n_face_dofs_per_component,
|
||||
const std::vector<int> &n_dofs_per_dim,
|
||||
Array<int> &face_map)
|
||||
{
|
||||
const int n_components = offsets.size();
|
||||
const int face_dim = strides.size() / n_components;
|
||||
const int n_components = static_cast<int>(offsets.size());
|
||||
const int face_dim = static_cast<int>(strides.size()) / n_components;
|
||||
for (int comp = 0; comp < n_components; ++comp)
|
||||
{
|
||||
const int offset = offsets[comp];
|
||||
|
||||
+1
-1
@@ -276,7 +276,7 @@ public:
|
||||
UNKNOWN_MAP_TYPE = -1, /**< Used to distinguish an unset MapType variable
|
||||
from the known values below. */
|
||||
VALUE, /**< For scalar fields; preserves point values
|
||||
$ u(x) = \hat u(\hat x) $ */
|
||||
$ u(x) = \hat u(\hat x) $ @anchor map_type_value */
|
||||
INTEGRAL, /**< For scalar fields; preserves volume integrals
|
||||
$ u(x) = (1/w) \hat u(\hat x) $ */
|
||||
H_DIV, /**< For vector fields; preserves surface integrals of the
|
||||
|
||||
@@ -195,6 +195,17 @@ public:
|
||||
return var_orders[p]->FiniteElementForGeometry(geom);
|
||||
}
|
||||
|
||||
/// Variable order version of TraceFiniteElementForGeometry().
|
||||
/** The order parameter @a p represents the order of the highest-dimensional
|
||||
FiniteElement%s the fixed-order collection we want to query. In general,
|
||||
this order is different from the order of the returned FiniteElement. */
|
||||
const FiniteElement *GetTraceFE(Geometry::Type geom, int p) const
|
||||
{
|
||||
if (p == base_p) { return TraceFiniteElementForGeometry(geom); }
|
||||
if (p >= var_orders.Size() || !var_orders[p]) { InitVarOrder(p); }
|
||||
return var_orders[p]->TraceFiniteElementForGeometry(geom);
|
||||
}
|
||||
|
||||
/// Variable order version of DofForGeometry().
|
||||
/** The order parameter @a p represents the order of the highest-dimensional
|
||||
FiniteElement%s the fixed-order collection we want to query. In general,
|
||||
|
||||
+188
-3
@@ -146,6 +146,43 @@ void FiniteElementSpace::CopyProlongationAndRestriction(
|
||||
delete perm_mat_tr;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::SetProlongation(const SparseMatrix& p)
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
|
||||
"Attempting to set serial prolongation operator for "
|
||||
"parallel finite element space.");
|
||||
#endif
|
||||
|
||||
if (!cP)
|
||||
{
|
||||
cP = std::unique_ptr<SparseMatrix>(new SparseMatrix(p));
|
||||
}
|
||||
else
|
||||
{
|
||||
*cP = p;
|
||||
}
|
||||
cP_is_set = true;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::SetRestriction(const SparseMatrix& r)
|
||||
{
|
||||
#ifdef MFEM_USE_MPI
|
||||
MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
|
||||
"Attempting to set serial restriction operator for "
|
||||
"parallel finite element space.");
|
||||
#endif
|
||||
|
||||
if (!cR)
|
||||
{
|
||||
cR = std::unique_ptr<SparseMatrix>(new SparseMatrix(r));
|
||||
}
|
||||
else
|
||||
{
|
||||
*cR = r;
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::SetElementOrder(int i, int p)
|
||||
{
|
||||
MFEM_VERIFY(mesh_sequence == mesh->GetSequence(),
|
||||
@@ -669,6 +706,78 @@ void FiniteElementSpace::GetBoundaryTrueDofs(Array<int> &boundary_dofs,
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetExteriorVDofs(Array<int> &ext_vdofs,
|
||||
int component) const
|
||||
{
|
||||
Array<int> dofs;
|
||||
ext_vdofs.SetSize(GetVSize());
|
||||
ext_vdofs = 0;
|
||||
|
||||
Array<int> ext_face_marker;
|
||||
mesh->GetExteriorFaceMarker(ext_face_marker);
|
||||
for (int i = 0; i < ext_face_marker.Size(); i++)
|
||||
{
|
||||
if (ext_face_marker[i])
|
||||
{
|
||||
if (component < 0)
|
||||
{
|
||||
// Mark all components.
|
||||
GetFaceDofs(i, dofs);
|
||||
DofsToVDofs(dofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
GetFaceDofs(i, dofs);
|
||||
for (auto &d : dofs) { d = DofToVDof(d, component); }
|
||||
}
|
||||
MarkDofs(dofs, ext_vdofs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetExteriorTrueDofs(Array<int> &ext_tdof_list,
|
||||
int component) const
|
||||
{
|
||||
Array<int> ext_vdofs, ext_tdofs;
|
||||
GetExteriorVDofs(ext_vdofs, component);
|
||||
const SparseMatrix *R = GetConformingRestriction();
|
||||
if (!R)
|
||||
{
|
||||
ext_tdofs.MakeRef(ext_vdofs);
|
||||
}
|
||||
else
|
||||
{
|
||||
R->BooleanMult(ext_vdofs, ext_tdofs);
|
||||
#ifdef MFEM_DEBUG
|
||||
// Verify that in boolean arithmetic: P^T ext_dofs = R ext_dofs
|
||||
Array<int> ext_tdofs2(ext_tdofs.Size());
|
||||
GetConformingProlongation()->BooleanMultTranspose(ext_vdofs, ext_tdofs2);
|
||||
|
||||
int counter = 0;
|
||||
std::string error_msg = "failed dof: ";
|
||||
auto ext_tdofs_ = ext_tdofs.HostRead();
|
||||
auto ext_tdofs2_ = ext_tdofs2.HostRead();
|
||||
for (int i = 0; i < ext_tdofs2.Size(); ++i)
|
||||
{
|
||||
if (bool(ext_tdofs_[i]) != bool(ext_tdofs2_[i]))
|
||||
{
|
||||
error_msg += std::to_string(i) += "(R ";
|
||||
error_msg += std::to_string(bool(ext_tdofs_[i])) += " P^T ";
|
||||
error_msg += std::to_string(bool(ext_tdofs2_[i])) += ") ";
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_ASSERT(R->Height() == GetConformingProlongation()->Width(), "!");
|
||||
MFEM_ASSERT(R->Width() == GetConformingProlongation()->Height(), "!");
|
||||
MFEM_ASSERT(R->Width() == ext_vdofs.Size(), "!");
|
||||
MFEM_VERIFY(counter == 0, "internal MFEM error: counter = " << counter
|
||||
<< ' ' << error_msg);
|
||||
#endif
|
||||
}
|
||||
MarkerToList(ext_tdofs, ext_tdof_list);
|
||||
}
|
||||
|
||||
// static method
|
||||
void FiniteElementSpace::MarkerToList(const Array<int> &marker,
|
||||
Array<int> &list)
|
||||
@@ -1358,6 +1467,26 @@ int FiniteElementSpace::GetNConformingDofs() const
|
||||
return P ? (P->Width() / vdim) : ndofs;
|
||||
}
|
||||
|
||||
int FiniteElementSpace::GetVectorDim() const
|
||||
{
|
||||
const FiniteElement *fe = GetTypicalFE();
|
||||
if (fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
return GetVDim();
|
||||
}
|
||||
return GetVDim()*std::max(GetMesh()->SpaceDimension(), fe->GetRangeDim());
|
||||
}
|
||||
|
||||
int FiniteElementSpace::GetCurlDim() const
|
||||
{
|
||||
const FiniteElement *fe = GetTypicalFE();
|
||||
if (fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
return 2 * GetMesh()->SpaceDimension() - 3;
|
||||
}
|
||||
return GetVDim()*fe->GetCurlDim();
|
||||
}
|
||||
|
||||
const ElementRestrictionOperator *FiniteElementSpace::GetElementRestriction(
|
||||
ElementDofOrdering e_ordering) const
|
||||
{
|
||||
@@ -2657,7 +2786,7 @@ void FiniteElementSpace::Construct()
|
||||
else
|
||||
{
|
||||
// the simple case: all faces are of the same geometry and order
|
||||
uni_fdof = fec->GetNumDof(mesh->GetFaceGeometry(0), order);
|
||||
uni_fdof = fec->GetNumDof(mesh->GetTypicalFaceGeometry(), order);
|
||||
nfdofs = mesh->GetNFaces() * uni_fdof;
|
||||
var_face_dofs.Clear(); // ensure any old var_face_dof table is dumped.
|
||||
}
|
||||
@@ -3337,7 +3466,7 @@ void FiniteElementSpace::GetFaceInteriorDofs(int i, Array<int> &dofs) const
|
||||
}
|
||||
else
|
||||
{
|
||||
auto geom = mesh->GetFaceGeometry(0);
|
||||
auto geom = mesh->GetTypicalFaceGeometry();
|
||||
nf = fec->GetNumDof(geom, fec->GetOrder());
|
||||
base = i*nf;
|
||||
}
|
||||
@@ -3404,6 +3533,16 @@ const FiniteElement *FiniteElementSpace::GetFE(int i) const
|
||||
return FE;
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetTypicalFE() const
|
||||
{
|
||||
if (mesh->GetNE() > 0) { return GetFE(0); }
|
||||
|
||||
Geometry::Type geom = mesh->GetTypicalElementGeometry();
|
||||
const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
|
||||
MFEM_VERIFY(fe != nullptr, "Could not determine a typical FE!");
|
||||
return fe;
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetBE(int i) const
|
||||
{
|
||||
int order = fec->GetOrder();
|
||||
@@ -3479,7 +3618,12 @@ const FiniteElement *FiniteElementSpace::GetEdgeElement(int i,
|
||||
const FiniteElement *FiniteElementSpace::GetTraceElement(
|
||||
int i, Geometry::Type geom_type) const
|
||||
{
|
||||
return fec->TraceFiniteElementForGeometry(geom_type);
|
||||
return fec->GetTraceFE(geom_type, GetElementOrder(i));
|
||||
}
|
||||
|
||||
const FiniteElement *FiniteElementSpace::GetTypicalTraceElement() const
|
||||
{
|
||||
return fec->TraceFiniteElementForGeometry(mesh->GetTypicalFaceGeometry());
|
||||
}
|
||||
|
||||
FiniteElementSpace::~FiniteElementSpace()
|
||||
@@ -3797,6 +3941,47 @@ void FiniteElementSpace::UpdateMeshPointer(Mesh *new_mesh)
|
||||
mesh = new_mesh;
|
||||
}
|
||||
|
||||
void FiniteElementSpace::GetNodePositions(const Vector &mesh_nodes,
|
||||
Vector &fes_node_pos,
|
||||
int fes_nodes_ordering) const
|
||||
{
|
||||
Mesh *m = GetMesh();
|
||||
const int NE = m->GetNE();
|
||||
|
||||
if (NE == 0) { fes_node_pos.SetSize(0); return; }
|
||||
|
||||
const int dim = m->Dimension();
|
||||
Array<int> dofs;
|
||||
Vector e_xyz;
|
||||
fes_node_pos.SetSize(GetNDofs() * dim);
|
||||
const FiniteElementSpace *mesh_fes = m->GetNodalFESpace();
|
||||
FiniteElementSpace vector_fes(m, FEColl(), dim, fes_nodes_ordering);
|
||||
|
||||
for (int e = 0; e < NE; e++)
|
||||
{
|
||||
mesh_fes->GetElementVDofs(e, dofs);
|
||||
const int mdof_cnt = dofs.Size() / dim;
|
||||
mesh_nodes.GetSubVector(dofs, e_xyz); //e_xyz is ordered by nodes here
|
||||
|
||||
auto ir = GetFE(e)->GetNodes();
|
||||
const int fdof_cnt = ir.GetNPoints();
|
||||
Vector mesh_shape(mdof_cnt), gf_xyz(fdof_cnt * dim);
|
||||
for (int q = 0; q < fdof_cnt; q++)
|
||||
{
|
||||
mesh_fes->GetFE(e)->CalcShape(ir.IntPoint(q), mesh_shape);
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
Vector x(e_xyz.GetData() + d*mdof_cnt, mdof_cnt);
|
||||
gf_xyz(d*fdof_cnt + q) = x * mesh_shape; // order by nodes
|
||||
}
|
||||
}
|
||||
|
||||
// reuse/resize dofs.
|
||||
vector_fes.GetElementVDofs(e, dofs);
|
||||
fes_node_pos.SetSubVector(dofs, gf_xyz);
|
||||
}
|
||||
}
|
||||
|
||||
void FiniteElementSpace::Save(std::ostream &os) const
|
||||
{
|
||||
int fes_format = 90; // the original format, v0.9
|
||||
|
||||
+71
-7
@@ -203,7 +203,7 @@ class FaceQuadratureInterpolator;
|
||||
@par
|
||||
%Vector dofs do not represent a specific index space the way the three
|
||||
previous types of dofs do. Rather they are related to modifications of
|
||||
these other index spaces to accomodate multiple copies of the underlying
|
||||
these other index spaces to accommodate multiple copies of the underlying
|
||||
function spaces.
|
||||
@par
|
||||
When using @b vdofs, i.e. when @b vdim != 1, the FiniteElementSpace only
|
||||
@@ -587,6 +587,14 @@ public:
|
||||
bool Conforming() const { return mesh->Conforming() && cP == NULL; }
|
||||
bool Nonconforming() const { return mesh->Nonconforming() || cP != NULL; }
|
||||
|
||||
/** Set the prolongation operator of the space to an arbitrary sparse matrix,
|
||||
creating a copy of the argument. */
|
||||
void SetProlongation(const SparseMatrix& p);
|
||||
|
||||
/** Set the restriction operator of the space to an arbitrary sparse matrix,
|
||||
creating a copy of the argument. */
|
||||
void SetRestriction(const SparseMatrix& r);
|
||||
|
||||
/// Sets the order of the i'th finite element.
|
||||
/** By default, all elements are assumed to be of fec->GetOrder(). Once
|
||||
SetElementOrder is called, the space becomes a variable order space. */
|
||||
@@ -729,7 +737,9 @@ public:
|
||||
/// Returns the polynomial degree of the i'th face finite element
|
||||
int GetFaceOrder(int face, int variant = 0) const;
|
||||
|
||||
/// Returns vector dimension.
|
||||
/// Returns the vector dimension of the finite element space.
|
||||
/** Since the finite elements could be vector-valued, this may not be the
|
||||
dimension of an actual vector in the space; see GetVectorDim(). */
|
||||
inline int GetVDim() const { return vdim; }
|
||||
|
||||
/// @brief Returns number of degrees of freedom.
|
||||
@@ -748,6 +758,22 @@ public:
|
||||
|
||||
int GetConformingVSize() const { return vdim * GetNConformingDofs(); }
|
||||
|
||||
/// Return the total dimension of a vector in the space
|
||||
/** This accounts for the vectorization of elements and cases where the
|
||||
elements themselves are vector-valued; see FiniteElement:GetRangeDim().
|
||||
If the finite elements are FiniteElement::SCALAR, this equals GetVDim().
|
||||
|
||||
Note: For vector-valued elements, the results pads up the range dimension
|
||||
to the spatial dimension. E.g., consider a stack of 5 vector-valued
|
||||
elements each representing 2D vectors, living in a 3 dimensional space.
|
||||
Then this fucntion would give 15, not 10.
|
||||
*/
|
||||
int GetVectorDim() const;
|
||||
|
||||
/// Return the dimension of the curl of a GridFunction defined on this space.
|
||||
/** Note: This assumes a space dimension of 2 or 3 only. */
|
||||
int GetCurlDim() const;
|
||||
|
||||
/// Return the ordering method.
|
||||
inline Ordering::Type GetOrdering() const { return ordering; }
|
||||
|
||||
@@ -1198,6 +1224,13 @@ public:
|
||||
an empty partition. */
|
||||
virtual const FiniteElement *GetFE(int i) const;
|
||||
|
||||
/** @brief Return GetFE(0) if the local mesh is not empty; otherwise return a
|
||||
typical FE based on the Geometry types in the global mesh.
|
||||
|
||||
This method can be used as a replacement for GetFE(0) that will be valid
|
||||
even if the local mesh is empty. */
|
||||
const FiniteElement *GetTypicalFE() const;
|
||||
|
||||
/** @brief Returns pointer to the FiniteElement in the FiniteElementCollection
|
||||
associated with i'th boundary face in the mesh object. */
|
||||
const FiniteElement *GetBE(int i) const;
|
||||
@@ -1215,6 +1248,12 @@ public:
|
||||
/// Return the trace element from element 'i' to the given 'geom_type'
|
||||
const FiniteElement *GetTraceElement(int i, Geometry::Type geom_type) const;
|
||||
|
||||
/// @brief Return a "typical" trace element.
|
||||
///
|
||||
/// This can be used in situations where the local mesh partition may be
|
||||
/// empty.
|
||||
const FiniteElement *GetTypicalTraceElement() const;
|
||||
|
||||
/** @brief Mark degrees of freedom associated with boundary elements with
|
||||
the specified boundary attributes (marked in 'bdr_attr_is_ess').
|
||||
For spaces with 'vdim' > 1, the 'component' parameter can be used
|
||||
@@ -1238,6 +1277,18 @@ public:
|
||||
marked as essential. */
|
||||
void GetBoundaryTrueDofs(Array<int> &boundary_dofs, int component = -1);
|
||||
|
||||
/** @brief Mark degrees of freedom associated with exterior faces of the
|
||||
mesh. For spaces with 'vdim' > 1, the 'component' parameter can be used
|
||||
to restricts the marked vDOFs to the specified component. */
|
||||
virtual void GetExteriorVDofs(Array<int> &exterior_vdofs,
|
||||
int component = -1) const;
|
||||
|
||||
/** @brief Get a list of all true dofs on the exterior of the mesh,
|
||||
@a exterior_dofs. For spaces with 'vdim' > 1, the 'component' parameter
|
||||
can be used to restricts the marked tDOFs to the specified component. */
|
||||
virtual void GetExteriorTrueDofs(Array<int> &exterior_dofs,
|
||||
int component = -1) const;
|
||||
|
||||
/// Convert a Boolean marker array to a list containing all marked indices.
|
||||
static void MarkerToList(const Array<int> &marker, Array<int> &list);
|
||||
|
||||
@@ -1361,6 +1412,18 @@ public:
|
||||
Update(false);
|
||||
}
|
||||
|
||||
/** @brief Compute the space's node positions w.r.t. given mesh positions.
|
||||
The function uses FiniteElement::GetNodes() to obtain the reference DOF
|
||||
positions of each finite element.
|
||||
|
||||
@param[in] mesh_nodes Mesh positions. Assumes that it has the same
|
||||
topology & ordering as the mesh of the FE space,
|
||||
i.e, same size as this->GetMesh()->GetNodes().
|
||||
@param[out] fes_node_pos Positions of the FE space's nodes.
|
||||
@param[in] fes_nodes_ordering Ordering of fes_node_pos. */
|
||||
void GetNodePositions(const Vector &mesh_nodes, Vector &fes_node_pos,
|
||||
int fes_nodes_ordering = Ordering::byNODES) const;
|
||||
|
||||
/// Save finite element space to output stream @a out.
|
||||
void Save(std::ostream &out) const;
|
||||
|
||||
@@ -1371,18 +1434,19 @@ public:
|
||||
virtual ~FiniteElementSpace();
|
||||
};
|
||||
|
||||
/// @brief Return true if the mesh contains only one topology and the elements are tensor elements.
|
||||
/// @brief Return true if the mesh contains only one topology and the elements
|
||||
/// are tensor elements.
|
||||
inline bool UsesTensorBasis(const FiniteElementSpace& fes)
|
||||
{
|
||||
Mesh & mesh = *fes.GetMesh();
|
||||
const bool mixed = mesh.GetNumGeometries(mesh.Dimension()) > 1;
|
||||
// Potential issue: empty local mesh --> no element 0.
|
||||
return !mixed &&
|
||||
dynamic_cast<const mfem::TensorBasisElement *>(fes.GetFE(0))!=nullptr;
|
||||
dynamic_cast<const mfem::TensorBasisElement *>(
|
||||
fes.GetTypicalFE()) != nullptr;
|
||||
}
|
||||
|
||||
/// @brief Return LEXICOGRAPHIC if mesh contains only one topology and the elements are tensor
|
||||
/// elements, otherwise, return NATIVE.
|
||||
/// @brief Return LEXICOGRAPHIC if mesh contains only one topology and the
|
||||
/// elements are tensor elements, otherwise, return NATIVE.
|
||||
ElementDofOrdering GetEVectorOrdering(const FiniteElementSpace& fes);
|
||||
|
||||
}
|
||||
|
||||
+62
-103
@@ -324,45 +324,12 @@ void GridFunction::ComputeFlux(BilinearFormIntegrator &blfi,
|
||||
|
||||
int GridFunction::VectorDim() const
|
||||
{
|
||||
const FiniteElement *fe;
|
||||
if (!fes->GetNE())
|
||||
{
|
||||
static const Geometry::Type geoms[3] =
|
||||
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
|
||||
fe = fes->FEColl()->
|
||||
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fe = fes->GetFE(0);
|
||||
}
|
||||
if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
return fes->GetVDim();
|
||||
}
|
||||
return fes->GetVDim()*std::max(fes->GetMesh()->SpaceDimension(),
|
||||
fe->GetRangeDim());
|
||||
return fes->GetVectorDim();
|
||||
}
|
||||
|
||||
int GridFunction::CurlDim() const
|
||||
{
|
||||
const FiniteElement *fe;
|
||||
if (!fes->GetNE())
|
||||
{
|
||||
static const Geometry::Type geoms[3] =
|
||||
{ Geometry::SEGMENT, Geometry::TRIANGLE, Geometry::TETRAHEDRON };
|
||||
fe = fes->FEColl()->
|
||||
FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fe = fes->GetFE(0);
|
||||
}
|
||||
if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
return 2 * fes->GetMesh()->SpaceDimension() - 3;
|
||||
}
|
||||
return fes->GetVDim()*fe->GetCurlDim();
|
||||
return fes->GetCurlDim();
|
||||
}
|
||||
|
||||
void GridFunction::GetTrueDofs(Vector &tv) const
|
||||
@@ -1793,8 +1760,8 @@ void GridFunction::ProjectGridFunction(const GridFunction &src)
|
||||
{
|
||||
// Assuming that the projection matrix is the same for all elements
|
||||
sameP = true;
|
||||
fes->GetFE(0)->Project(*src.fes->GetFE(0),
|
||||
*mesh->GetElementTransformation(0), P);
|
||||
fes->GetTypicalFE()->Project(*src.fes->GetTypicalFE(),
|
||||
*mesh->GetTypicalElementTransformation(), P);
|
||||
}
|
||||
const int vdim = fes->GetVDim();
|
||||
MFEM_VERIFY(vdim == src.fes->GetVDim(), "incompatible vector dimensions!");
|
||||
@@ -2456,7 +2423,6 @@ void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
|
||||
{
|
||||
if (fes->GetNURBSext() == NULL)
|
||||
{
|
||||
|
||||
int i;
|
||||
Array<int> vdofs;
|
||||
Vector vals;
|
||||
@@ -2474,9 +2440,7 @@ void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
|
||||
}
|
||||
SetSubVector(vdofs, vals);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
// Define and assemble linear form
|
||||
@@ -2825,6 +2789,7 @@ real_t GridFunction::ComputeL2Error(
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
real_t elem_error = 0.0;
|
||||
for (j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
@@ -2843,12 +2808,14 @@ real_t GridFunction::ComputeL2Error(
|
||||
a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k);
|
||||
}
|
||||
a -= exsol[d]->Eval(*transf, ip);
|
||||
error += ip.weight * transf->Weight() * a * a;
|
||||
elem_error += ip.weight * transf->Weight() * a * a;
|
||||
}
|
||||
}
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeL2Error(
|
||||
@@ -2875,6 +2842,7 @@ real_t GridFunction::ComputeL2Error(
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
real_t elem_error = 0.0;
|
||||
T = fes->GetElementTransformation(i);
|
||||
GetVectorValues(*T, *ir, vals);
|
||||
exsol.Eval(exact_vals, *T, *ir);
|
||||
@@ -2885,11 +2853,12 @@ real_t GridFunction::ComputeL2Error(
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
T->SetIntPoint(&ip);
|
||||
error += ip.weight * T->Weight() * (loc_errs(j) * loc_errs(j));
|
||||
elem_error += ip.weight * T->Weight() * (loc_errs(j) * loc_errs(j));
|
||||
}
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeElementGradError(int ielem,
|
||||
@@ -2927,7 +2896,7 @@ real_t GridFunction::ComputeElementGradError(int ielem,
|
||||
vec-=grad;
|
||||
error += ip.weight * Tr->Weight() * (vec * vec);
|
||||
}
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(fabs(error));
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeGradError(VectorCoefficient *exgrad,
|
||||
@@ -2957,6 +2926,7 @@ real_t GridFunction::ComputeGradError(VectorCoefficient *exgrad,
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
real_t elem_error = 0.0;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
@@ -2964,10 +2934,12 @@ real_t GridFunction::ComputeGradError(VectorCoefficient *exgrad,
|
||||
GetGradient(*Tr,grad);
|
||||
exgrad->Eval(vec,*Tr,ip);
|
||||
vec-=grad;
|
||||
error += ip.weight * Tr->Weight() * (vec * vec);
|
||||
elem_error += ip.weight * Tr->Weight() * (vec * vec);
|
||||
}
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeCurlError(VectorCoefficient *excurl,
|
||||
@@ -2997,6 +2969,7 @@ real_t GridFunction::ComputeCurlError(VectorCoefficient *excurl,
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
real_t elem_error = 0.0;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
@@ -3004,11 +2977,13 @@ real_t GridFunction::ComputeCurlError(VectorCoefficient *excurl,
|
||||
GetCurl(*Tr,curl);
|
||||
excurl->Eval(vec,*Tr,ip);
|
||||
vec-=curl;
|
||||
error += ip.weight * Tr->Weight() * ( vec * vec );
|
||||
elem_error += ip.weight * Tr->Weight() * ( vec * vec );
|
||||
}
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeDivError(
|
||||
@@ -3035,16 +3010,19 @@ real_t GridFunction::ComputeDivError(
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
fes->GetElementDofs(i, dofs);
|
||||
real_t elem_error = 0.0;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
Tr->SetIntPoint (&ip);
|
||||
a = GetDivergence(*Tr) - exdiv->Eval(*Tr, ip);
|
||||
error += ip.weight * Tr->Weight() * a * a;
|
||||
elem_error += ip.weight * Tr->Weight() * a * a;
|
||||
}
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
@@ -3145,6 +3123,7 @@ real_t GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
|
||||
}
|
||||
}
|
||||
real_t face_error = 0.0;
|
||||
face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
|
||||
transf = face_elem_transf;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
@@ -3152,13 +3131,15 @@ real_t GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
real_t nu = jump_scaling.Eval(h, p);
|
||||
error += (ip.weight * nu * ell_coeff_val(j) *
|
||||
transf->Weight() *
|
||||
err_val(j) * err_val(j));
|
||||
face_error += (ip.weight * nu * ell_coeff_val(j) *
|
||||
transf->Weight() *
|
||||
err_val(j) * err_val(j));
|
||||
}
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(face_error);
|
||||
}
|
||||
|
||||
return (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
return sqrt(error);
|
||||
}
|
||||
|
||||
real_t GridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
@@ -3309,6 +3290,7 @@ real_t GridFunction::ComputeW11Error(
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
real_t elem_error = 0.0;
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
@@ -3325,8 +3307,9 @@ real_t GridFunction::ComputeW11Error(
|
||||
fe->CalcShape(ip, shape);
|
||||
transf->SetIntPoint(&ip);
|
||||
a = (el_dofs * shape) - (exsol->Eval(*transf, ip));
|
||||
error += ip.weight * transf->Weight() * fabs(a);
|
||||
elem_error += ip.weight * transf->Weight() * fabs(a);
|
||||
}
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
|
||||
if (norm_type & 2) // W^1_1 seminorm
|
||||
@@ -3349,6 +3332,7 @@ real_t GridFunction::ComputeW11Error(
|
||||
{
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
real_t elem_error = 0.0;
|
||||
fes->GetElementVDofs(i, vdofs);
|
||||
for (k = 0; k < fdof; k++)
|
||||
if (vdofs[k] >= 0)
|
||||
@@ -3369,8 +3353,9 @@ real_t GridFunction::ComputeW11Error(
|
||||
Mult(dshape, Jinv, dshapet);
|
||||
dshapet.MultTranspose(el_dofs, a_grad);
|
||||
e_grad -= a_grad;
|
||||
error += ip.weight * transf->Weight() * e_grad.Norml1();
|
||||
elem_error += ip.weight * transf->Weight() * e_grad.Norml1();
|
||||
}
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -3400,6 +3385,7 @@ real_t GridFunction::ComputeLpError(const real_t p, Coefficient &exsol,
|
||||
int intorder = 2*fe->GetOrder() + 3; // <----------
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
real_t elem_error = 0.0;
|
||||
GetValues(i, *ir, vals);
|
||||
T = fes->GetElementTransformation(i);
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
@@ -3414,7 +3400,7 @@ real_t GridFunction::ComputeLpError(const real_t p, Coefficient &exsol,
|
||||
{
|
||||
diff *= weight->Eval(*T, ip);
|
||||
}
|
||||
error += ip.weight * T->Weight() * diff;
|
||||
elem_error += ip.weight * T->Weight() * diff;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3425,19 +3411,16 @@ real_t GridFunction::ComputeLpError(const real_t p, Coefficient &exsol,
|
||||
error = std::max(error, diff);
|
||||
}
|
||||
}
|
||||
if (p < infinity())
|
||||
{
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
}
|
||||
|
||||
if (p < infinity())
|
||||
{
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
if (error < 0.)
|
||||
{
|
||||
error = -pow(-error, 1./p);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = pow(error, 1./p);
|
||||
}
|
||||
error = pow(error, 1./p);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -3497,14 +3480,7 @@ void GridFunction::ComputeElementLpErrors(const real_t p, Coefficient &exsol,
|
||||
if (p < infinity())
|
||||
{
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
if (error[i] < 0.)
|
||||
{
|
||||
error[i] = -pow(-error[i], 1./p);
|
||||
}
|
||||
else
|
||||
{
|
||||
error[i] = pow(error[i], 1./p);
|
||||
}
|
||||
error[i] = pow(fabs(error[i]), 1./p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3533,6 +3509,7 @@ real_t GridFunction::ComputeLpError(const real_t p, VectorCoefficient &exsol,
|
||||
int intorder = 2*fe->GetOrder() + 3; // <----------
|
||||
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
|
||||
}
|
||||
real_t elem_error = 0.0;
|
||||
T = fes->GetElementTransformation(i);
|
||||
GetVectorValues(*T, *ir, vals);
|
||||
exsol.Eval(exact_vals, *T, *ir);
|
||||
@@ -3571,7 +3548,7 @@ real_t GridFunction::ComputeLpError(const real_t p, VectorCoefficient &exsol,
|
||||
{
|
||||
errj *= weight->Eval(*T, ip);
|
||||
}
|
||||
error += ip.weight * T->Weight() * errj;
|
||||
elem_error += ip.weight * T->Weight() * errj;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3582,19 +3559,16 @@ real_t GridFunction::ComputeLpError(const real_t p, VectorCoefficient &exsol,
|
||||
error = std::max(error, errj);
|
||||
}
|
||||
}
|
||||
if (p < infinity())
|
||||
{
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(elem_error);
|
||||
}
|
||||
}
|
||||
|
||||
if (p < infinity())
|
||||
{
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
if (error < 0.)
|
||||
{
|
||||
error = -pow(-error, 1./p);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = pow(error, 1./p);
|
||||
}
|
||||
error = pow(error, 1./p);
|
||||
}
|
||||
|
||||
return error;
|
||||
@@ -3681,14 +3655,7 @@ void GridFunction::ComputeElementLpErrors(const real_t p,
|
||||
if (p < infinity())
|
||||
{
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
if (error[i] < 0.)
|
||||
{
|
||||
error[i] = -pow(-error[i], 1./p);
|
||||
}
|
||||
else
|
||||
{
|
||||
error[i] = pow(error[i], 1./p);
|
||||
}
|
||||
error[i] = pow(fabs(error[i]), 1./p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4490,7 +4457,6 @@ real_t ComputeElementLpDistance(real_t p, int i,
|
||||
int nip = ir->GetNPoints();
|
||||
Vector val1, val2;
|
||||
|
||||
|
||||
ElementTransformation *T = fes1->GetElementTransformation(i);
|
||||
for (int j = 0; j < nip; j++)
|
||||
{
|
||||
@@ -4516,14 +4482,7 @@ real_t ComputeElementLpDistance(real_t p, int i,
|
||||
if (p < infinity())
|
||||
{
|
||||
// Negative quadrature weights may cause the norm to be negative
|
||||
if (norm < 0.)
|
||||
{
|
||||
norm = -pow(-norm, 1./p);
|
||||
}
|
||||
else
|
||||
{
|
||||
norm = pow(norm, 1./p);
|
||||
}
|
||||
norm = pow(fabs(norm), 1./p);
|
||||
}
|
||||
|
||||
return norm;
|
||||
|
||||
+811
-32
@@ -123,7 +123,10 @@ public:
|
||||
|
||||
FiniteElementCollection *OwnFEC() { return fec_owned; }
|
||||
|
||||
/// Shortcut for calling FiniteElementSpace::GetVectorDim() on the underlying #fes
|
||||
int VectorDim() const;
|
||||
|
||||
/// Shortcut for calling FiniteElementSpace::GetCurlDim() on the underlying #fes
|
||||
int CurlDim() const;
|
||||
|
||||
/// Read only access to the (optional) internal true-dof Vector.
|
||||
@@ -500,49 +503,232 @@ public:
|
||||
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
|
||||
const Array<int> &bdr_attr);
|
||||
|
||||
/// @brief Returns ||exsol - u_h||_L2 for scalar or vector H1 or L2 elements
|
||||
///
|
||||
/// @param[in] exsol Pointer to an array of scalar Coefficient objects,
|
||||
/// one for each component of the vector field. The
|
||||
/// length of the array should be at least equal to
|
||||
/// FiniteElementSpace::GetVDim().
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
/// @param[in] elems Optional pointer to a marker array, with a length
|
||||
/// equal to the number of local elements, indicating
|
||||
/// which elements to integrate over. Only those elements
|
||||
/// corresponding to non-zero entries in @a elems will
|
||||
/// contribute to the computed L2 error.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeL2Error(Coefficient *exsol[],
|
||||
const IntegrationRule *irs[] = NULL,
|
||||
const Array<int> *elems = NULL) const;
|
||||
|
||||
/// Returns ||grad u_ex - grad u_h||_L2 in element ielem for H1 or L2 elements
|
||||
/// @brief Returns ||grad u_ex - grad u_h||_L2 in element ielem for
|
||||
/// H1 or L2 elements
|
||||
///
|
||||
/// @param[in] ielem Index of the element in which to compute the L2 error.
|
||||
/// @param[in] exgrad Pointer to a VectorCoefficient object reproducing the
|
||||
/// expected gradient of the scalar field, grad u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeElementGradError(int ielem, VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns ||u_ex - u_h||_L2 for H1 or L2 elements
|
||||
/* The @a elems input variable expects a list of markers:
|
||||
an elem marker equal to 1 will compute the L2 error on that element
|
||||
an elem marker equal to 0 will not compute the L2 error on that element */
|
||||
/// @brief Returns ||u_ex - u_h||_L2 for H1 or L2 elements
|
||||
///
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated values
|
||||
/// of the scalar field, u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
/// @param[in] elems Optional pointer to a marker array, with a length
|
||||
/// equal to the number of local elements, indicating
|
||||
/// which elements to integrate over. Only those elements
|
||||
/// corresponding to non-zero entries in @a elems will
|
||||
/// contribute to the computed L2 error.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeL2Error(Coefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL,
|
||||
const Array<int> *elems = NULL) const
|
||||
{ return GridFunction::ComputeLpError(2.0, exsol, NULL, irs, elems); }
|
||||
|
||||
/// @brief Returns ||u_ex - u_h||_L2 for vector fields
|
||||
///
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the anticipated
|
||||
/// values of the vector field, u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
/// @param[in] elems Optional pointer to a marker array, with a length
|
||||
/// equal to the number of local elements, indicating
|
||||
/// which elements to integrate over. Only those elements
|
||||
/// corresponding to non-zero entries in @a elems will
|
||||
/// contribute to the computed L2 error.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeL2Error(VectorCoefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL,
|
||||
const Array<int> *elems = NULL) const;
|
||||
|
||||
/// Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
|
||||
/// @brief Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
|
||||
///
|
||||
/// @param[in] exgrad Pointer to a VectorCoefficient object reproducing the
|
||||
/// expected gradient of the scalar field, grad u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note This function only computes the error of the gradient in the
|
||||
/// interior of the elements. In the context of discontinuous
|
||||
/// Galerkin (DG) methods it may also be desirable to compute the
|
||||
/// error in the jumps across element interfaces using
|
||||
/// ComputeDGFaceJumpError().
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeGradError(VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns ||curl u_ex - curl u_h||_L2 for ND elements
|
||||
/// @brief Returns ||curl u_ex - curl u_h||_L2 for ND elements
|
||||
///
|
||||
/// @param[in] excurl Pointer to a VectorCoefficient object reproducing the
|
||||
/// expected curl of the vector field, curl u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeCurlError(VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns ||div u_ex - div u_h||_L2 for RT elements
|
||||
/// @brief Returns ||div u_ex - div u_h||_L2 for RT elements
|
||||
///
|
||||
/// @param[in] exdiv Pointer to a Coefficient object reproducing the
|
||||
/// expected divergence of the vector field, div u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeDivError(Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the Face Jumps error for L2 elements. The error can be weighted
|
||||
/// by a constant nu, by nu/h, or nu*p^2/h, depending on the value of
|
||||
/// @a jump_scaling.
|
||||
/// @brief Returns the Face Jumps error for L2 elements.
|
||||
///
|
||||
/// Computes:
|
||||
/// $$\sqrt{\sum_{f\in faces}\int_f js(f) ell(f)
|
||||
/// (2 u_{ex} - u_1 - u_2)^2}$$
|
||||
///
|
||||
/// Where js[f] is the jump_scaling evaluated on the face f and ell is the
|
||||
/// average of ell_coef evaluated in the two elements sharing the face f.
|
||||
///
|
||||
/// @param[in] exsol Pointer to a Coefficient object reproducing the
|
||||
/// anticipated values of the scalar field, u_ex.
|
||||
/// @param[in] ell_coeff Pointer to a Coefficient object used to compute
|
||||
/// the averaged value ell in the above integral.
|
||||
/// @param[in] jump_scaling Can be configured to provide scaling by
|
||||
/// nu, nu/h, or nu*p^2/h
|
||||
/// @param[in] irs Optional pointer to an array of custom
|
||||
/// integration rules e.g. higher order than the
|
||||
/// default rules. If present the array will be
|
||||
/// indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of faces.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
class JumpScaling jump_scaling,
|
||||
const IntegrationRule *irs[] = NULL)
|
||||
const;
|
||||
|
||||
/// Returns the Face Jumps error for L2 elements, with 1/h scaling.
|
||||
/// @brief Returns the Face Jumps error for L2 elements, with 1/h scaling.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @deprecated See @ref ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
/// Coefficient *ell_coeff,
|
||||
/// class JumpScaling jump_scaling,
|
||||
/// const IntegrationRule *irs[]) const
|
||||
/// for the preferred implementation.
|
||||
MFEM_DEPRECATED
|
||||
real_t ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
Coefficient *ell_coeff,
|
||||
@@ -559,98 +745,589 @@ public:
|
||||
Coefficient *ell_coef, real_t Nu,
|
||||
int norm_type) const;
|
||||
|
||||
/// Returns the error measured in H1-norm for H1 elements or in "broken"
|
||||
/// H1-norm for L2 elements
|
||||
/// @brief Returns the error measured in H1-norm for H1 or L2 elements
|
||||
///
|
||||
/// Computes the norm using the $L^2$ norms of the function and its gradient
|
||||
/// $$\sqrt{norm\_u^2 + norm\_du^2}$$
|
||||
/// Where
|
||||
/// $$norm\_u = \|u_{ex} - u_h\|_{L^2}$$
|
||||
/// and
|
||||
/// $$norm\_du = \|du_{ex} - \nabla u_h\|_{L^2}$$
|
||||
///
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated values
|
||||
/// of the scalar field, u_ex.
|
||||
/// @param[in] exgrad VectorCoefficient object reproducing the anticipated
|
||||
/// values of the gradient of the scalar field, du_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @note For L2 elements this returns what could be called a "broken"
|
||||
/// H1-norm.
|
||||
virtual real_t ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the error measured in H(div)-norm for RT elements
|
||||
/// @brief Returns the error measured in H(div)-norm for RT elements
|
||||
///
|
||||
/// Computes the norm using the $L^2$ norms of the function and its
|
||||
/// divergence
|
||||
/// $$\sqrt{norm\_u^2 + norm\_du^2}$$
|
||||
/// Where
|
||||
/// $$norm\_u = \|u_{ex} - u_h\|_{L^2}$$
|
||||
/// and
|
||||
/// $$norm\_du = \|du_{ex} - \nabla\cdot u_h\|_{L^2}$$
|
||||
///
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the anticipated
|
||||
/// values of the vector field, u_ex.
|
||||
/// @param[in] exdiv VectorCoefficient object reproducing the anticipated
|
||||
/// values of the divergence of the vector field, du_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeHDivError(VectorCoefficient *exsol,
|
||||
Coefficient *exdiv,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// Returns the error measured in H(curl)-norm for ND elements
|
||||
/// @brief Returns the error measured in H(curl)-norm for ND elements
|
||||
///
|
||||
/// Computes the norm using the $L^2$ norms of the function and its curl
|
||||
/// $$\sqrt{norm\_u^2 + norm\_du^2}$$
|
||||
/// Where
|
||||
/// $$norm\_u = \|u_{ex} - u_h\|_{L^2}$$
|
||||
/// and
|
||||
/// $$norm\_du = \|du_{ex} - \nabla\times u_h\|_{L^2}$$
|
||||
///
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the anticipated
|
||||
/// values of the vector field, u_ex.
|
||||
/// @param[in] excurl VectorCoefficient object reproducing the anticipated
|
||||
/// values of the curl of the vector field, du_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeHCurlError(VectorCoefficient *exsol,
|
||||
VectorCoefficient *excurl,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// @brief Returns Max|u_ex - u_h| error for H1 or L2 elements
|
||||
///
|
||||
/// Compute the $L^\infty$ error across the entire domain.
|
||||
///
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated
|
||||
/// values of the scalar field, u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note Uses ComputeLpError internally. See the ComputeLpError
|
||||
/// documentation for generalizations of this error computation.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
virtual real_t ComputeMaxError(Coefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return ComputeLpError(infinity(), exsol, NULL, irs);
|
||||
}
|
||||
|
||||
/// @brief Returns Max|u_ex - u_h| error for scalar or vector fields
|
||||
///
|
||||
/// Compute the $L^\infty$ error across the entire domain.
|
||||
///
|
||||
/// Computes:
|
||||
/// $$max_{elems} (max_{elem} |scalar\_error|)$$
|
||||
///
|
||||
/// Where
|
||||
/// $$scalar\_error = max_{d=0\ldots vdim}|u_{ex}[d] - u_h[d]|$$
|
||||
///
|
||||
/// @param[in] exsol Pointer to an array of scalar Coefficient objects,
|
||||
/// one for each component of the vector field. The
|
||||
/// length of the array should be at least equal to
|
||||
/// FiniteElementSpace::GetVDim().
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note This implementation of the max error of a vector field computes
|
||||
/// the max norm over vector components rather than the magnitude of
|
||||
/// the vector.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
virtual real_t ComputeMaxError(Coefficient *exsol[],
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// @brief Returns Max|u_ex - u_h| error for vector fields
|
||||
///
|
||||
/// Compute the $L^\infty$ error across the entire domain.
|
||||
///
|
||||
/// Computes:
|
||||
/// $$max_{elems} (max_{elem} |scalar\_error|)$$
|
||||
///
|
||||
/// Where
|
||||
/// $$scalar\_error = \sqrt{(u_{ex} - u_h) \cdot (u_{ex} - u_h)}$$
|
||||
///
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the
|
||||
/// anticipated values of the vector field, u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note Uses ComputeLpError internally. See the ComputeLpError
|
||||
/// documentation for generalizations of this error computation.
|
||||
///
|
||||
/// @note Computes the maximum magnitude of the difference vector not the
|
||||
/// component-wise maximum difference of the vector fields.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
virtual real_t ComputeMaxError(VectorCoefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{
|
||||
return ComputeLpError(infinity(), exsol, NULL, NULL, irs);
|
||||
}
|
||||
|
||||
virtual real_t ComputeL1Error(Coefficient *exsol[],
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{ return ComputeW11Error(*exsol, NULL, 1, NULL, irs); }
|
||||
|
||||
/// @brief Returns ||u_ex - u_h||_L1 for H1 or L2 elements
|
||||
///
|
||||
/// Computes:
|
||||
/// $$\sum_{elems} \int_{elem} |u_{ex} - u_h|$$
|
||||
///
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated values
|
||||
/// of the scalar field, u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @note Uses ComputeLpError internally. See the ComputeLpError
|
||||
/// documentation for generalizations of this error computation.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
virtual real_t ComputeL1Error(Coefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{ return ComputeLpError(1.0, exsol, NULL, irs); }
|
||||
|
||||
/// @brief Returns ||u_ex - u_h||_L1 for H1 or L2 elements
|
||||
///
|
||||
/// Computes:
|
||||
/// $$\sum_{elems} \int_{elem} |u_{ex} - u_h|$$
|
||||
///
|
||||
/// @param[in] exsol Pointer to an array of Coefficient objects
|
||||
/// reproducing the anticipated values of the scalar
|
||||
/// field, u_ex. Only the first entry of this array will
|
||||
/// be accessed.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @note Uses ComputeW11Error internally. See the ComputeW11Error
|
||||
/// documentation for generalizations of this error computation.
|
||||
///
|
||||
/// @warning While this function is nominally equivalent to ComputeLpError,
|
||||
/// with appropriate arguments, the returned errors may differ
|
||||
/// noticeably because ComputeLpError uses a higher order
|
||||
/// integration rule by default.
|
||||
///
|
||||
/// @deprecated See @ref ComputeL1Error(Coefficient &exsol,
|
||||
/// const IntegrationRule *irs[]) const
|
||||
/// for the preferred implementation.
|
||||
MFEM_DEPRECATED
|
||||
virtual real_t ComputeL1Error(Coefficient *exsol[],
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{ return ComputeW11Error(*exsol, NULL, 1, NULL, irs); }
|
||||
|
||||
/// @brief Returns $W^1_1$ norm (or portions thereof) for H1 or L2 elements
|
||||
///
|
||||
/// Computes for norm_type == 1 the $L^1$ norm of $u$:
|
||||
/// $$(\sum_{elems} \int_{elem} |u_{ex} - u_h|$$
|
||||
///
|
||||
/// Computes for norm_type == 2 the $L^1$ semi-norm of $\nabla u$:
|
||||
/// $$(\sum_{elems} \int_{elem} |du_{ex} - \nabla u_h|$$
|
||||
///
|
||||
/// Computes for norm_type == 3 the $W^1_1$ norm of $u$:
|
||||
/// $$(\sum_{elems} \int_{elem} |u_{ex} - u_h| + |du_{ex} - \nabla u_h|$$
|
||||
///
|
||||
/// @param[in] exsol Pointer to Coefficient object reproducing the
|
||||
/// anticipated values of the scalar field, u_ex.
|
||||
/// @param[in] exgrad Pointer to VectorCoefficient object reproducing the
|
||||
/// anticipated values of the gradient of the scalar
|
||||
/// field, du_ex.
|
||||
/// @param[in] norm_type Integer value of 1, 2, or 3 indicating the type of
|
||||
/// norm to compute (see above).
|
||||
/// @param[in] elems Optional pointer to a marker array, with a length
|
||||
/// equal to the number of local elements, indicating
|
||||
/// which elements to integrate over. Only those
|
||||
/// elements corresponding to non-zero entries in
|
||||
/// @a elems will contribute to the computed $W^1_1$
|
||||
/// error.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeW11Error(Coefficient *exsol, VectorCoefficient *exgrad,
|
||||
int norm_type, const Array<int> *elems = NULL,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/// @brief Returns ||u_ex - u_h||_L1 for vector fields
|
||||
///
|
||||
/// Computes:
|
||||
/// $$\sum_{elems} \int_{elem} |scalar\_error|$$
|
||||
///
|
||||
/// Where
|
||||
/// $$scalar\_error = \sqrt{(u_{ex} - u_h) \cdot (u_{ex} - u_h)}$$
|
||||
///
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the anticipated
|
||||
/// values of the vector field, u_ex.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @note Uses ComputeLpError internally. See the ComputeLpError
|
||||
/// documentation for generalizations of this error computation.
|
||||
virtual real_t ComputeL1Error(VectorCoefficient &exsol,
|
||||
const IntegrationRule *irs[] = NULL) const
|
||||
{ return ComputeLpError(1.0, exsol, NULL, NULL, irs); }
|
||||
|
||||
/* The @a elems input variable expects a list of markers:
|
||||
an elem marker equal to 1 will compute the L2 error on that element
|
||||
an elem marker equal to 0 will not compute the L2 error on that element */
|
||||
/// @brief Returns ||u_ex - u_h||_Lp for H1 or L2 elements
|
||||
///
|
||||
/// Computes:
|
||||
/// $$(\sum_{elems} \int_{elem} w \, |u_{ex} - u_h|^p)^{1/p}$$
|
||||
///
|
||||
/// @param[in] p Real value indicating the exponent of the $L^p$ norm.
|
||||
/// To avoid domain errors p should have a positive value,
|
||||
/// either finite or infinite.
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated values
|
||||
/// of the scalar field, u_ex.
|
||||
/// @param[in] weight Optional pointer to a Coefficient object reproducing
|
||||
/// a weighting function, w.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
/// @param[in] elems Optional pointer to a marker array, with a length
|
||||
/// equal to the number of local elements, indicating
|
||||
/// which elements to integrate over. Only those elements
|
||||
/// corresponding to non-zero entries in @a elems will
|
||||
/// contribute to the computed L2 error.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeLpError(const real_t p, Coefficient &exsol,
|
||||
Coefficient *weight = NULL,
|
||||
const IntegrationRule *irs[] = NULL,
|
||||
const Array<int> *elems = NULL) const;
|
||||
|
||||
/** Compute the Lp error in each element of the mesh and store the results in
|
||||
the Vector @a error. The result should be of length number of elements,
|
||||
for example an L2 GridFunction of order zero using map type VALUE. */
|
||||
/// @brief Returns ||u_ex - u_h||_Lp elementwise for H1 or L2 elements
|
||||
///
|
||||
/// Compute the Lp error in each element of the mesh and store the results in
|
||||
/// the Vector @a error. The result should be of length number of elements,
|
||||
/// for example an L2 GridFunction of order zero using map type @ref
|
||||
/// map_type_value "VALUE".
|
||||
///
|
||||
/// Computes:
|
||||
/// $$(\int_{elem} w \, |u_{ex} - u_h|^p)^{1/p}$$
|
||||
///
|
||||
/// @param[in] p Real value indicating the exponent of the $L^p$
|
||||
/// norm. To avoid domain errors p should have a
|
||||
/// positive value, either finite or infinite.
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated
|
||||
/// values of the scalar field, u_ex.
|
||||
/// @param[in,out] error Vector to contain the element-wise $L^p$ errors
|
||||
/// @param[in] weight Optional pointer to a Coefficient object
|
||||
/// reproducing a weighting function, w.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual void ComputeElementLpErrors(const real_t p, Coefficient &exsol,
|
||||
Vector &error,
|
||||
Coefficient *weight = NULL,
|
||||
const IntegrationRule *irs[] = NULL
|
||||
) const;
|
||||
|
||||
/// @brief Returns ||u_ex - u_h||_L1 elementwise for H1 or L2 elements
|
||||
///
|
||||
/// Compute the $L^1$ error in each element of the mesh and store the
|
||||
/// results in the Vector @a error. The result should be of length number of
|
||||
/// elements, for example an L2 GridFunction of order zero using map type
|
||||
/// @ref map_type_value "VALUE".
|
||||
///
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated
|
||||
/// values of the scalar field, u_ex.
|
||||
/// @param[in,out] error Vector to contain the element-wise $L^1$ errors
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @note Uses ComputeElementLpError internally. See the
|
||||
/// ComputeElementLpError documentation for generalizations of this
|
||||
/// error computation.
|
||||
virtual void ComputeElementL1Errors(Coefficient &exsol,
|
||||
Vector &error,
|
||||
const IntegrationRule *irs[] = NULL
|
||||
) const
|
||||
{ ComputeElementLpErrors(1.0, exsol, error, NULL, irs); }
|
||||
|
||||
/// @brief Returns ||u_ex - u_h||_L2 elementwise for H1 or L2 elements
|
||||
///
|
||||
/// Compute the $L^2$ error in each element of the mesh and store the results
|
||||
/// in the Vector @a error. The result should be of length number of
|
||||
/// elements, for example an L2 GridFunction of order zero using map type
|
||||
/// @ref map_type_value "VALUE".
|
||||
///
|
||||
/// Computes:
|
||||
/// $$(\int_{elem} |u_{ex} - u_h|^2)^{1/2}$$
|
||||
///
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated
|
||||
/// values of the scalar field, u_ex.
|
||||
/// @param[in,out] error Vector to contain the element-wise $L^2$ errors
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @note Uses ComputeElementLpError internally. See the
|
||||
/// ComputeElementLpError documentation for generalizations of this
|
||||
/// error computation.
|
||||
virtual void ComputeElementL2Errors(Coefficient &exsol,
|
||||
Vector &error,
|
||||
const IntegrationRule *irs[] = NULL
|
||||
) const
|
||||
{ ComputeElementLpErrors(2.0, exsol, error, NULL, irs); }
|
||||
|
||||
/// @brief Returns Max|u_ex - u_h| elementwise for H1 or L2 elements
|
||||
///
|
||||
/// Compute the $L^\infty$ error in each element of the mesh and store the
|
||||
/// results in the Vector @a error. The result should be of length number of
|
||||
/// elements, for example an L2 GridFunction of order zero using map type
|
||||
/// @ref map_type_value "VALUE".
|
||||
///
|
||||
/// @param[in] exsol Coefficient object reproducing the anticipated
|
||||
/// values of the scalar field, u_ex.
|
||||
/// @param[in,out] error Vector to contain the element-wise $L^\infty$
|
||||
/// errors
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Uses ComputeElementLpError internally. See the
|
||||
/// ComputeElementLpError documentation for generalizations of this
|
||||
/// error computation.
|
||||
virtual void ComputeElementMaxErrors(Coefficient &exsol,
|
||||
Vector &error,
|
||||
const IntegrationRule *irs[] = NULL
|
||||
) const
|
||||
{ ComputeElementLpErrors(infinity(), exsol, error, NULL, irs); }
|
||||
|
||||
/** When given a vector weight, compute the pointwise (scalar) error as the
|
||||
dot product of the vector error with the vector weight. Otherwise, the
|
||||
scalar error is the l_2 norm of the vector error. */
|
||||
/// @brief Returns ||u_ex - u_h||_Lp for vector fields
|
||||
///
|
||||
/// When given a vector weight, compute the pointwise (scalar) error as the
|
||||
/// dot product of the vector error with the vector weight. Otherwise, the
|
||||
/// scalar error is the l_2 norm of the vector error.
|
||||
///
|
||||
/// Computes:
|
||||
/// $$(\sum_{elems} \int_{elem} w \, |scalar\_error|^p)^{1/p}$$
|
||||
///
|
||||
/// Where
|
||||
/// $$scalar\_error = |v\_weight \cdot (u_{ex} - u_h)|$$
|
||||
/// or
|
||||
/// $$scalar\_error = \sqrt{(u_{ex} - u_h) \cdot (u_{ex} - u_h)}$$
|
||||
///
|
||||
/// @param[in] p Real value indicating the exponent of the $L^p$
|
||||
/// norm. To avoid domain errors p should have a
|
||||
/// positive value, either finite or infinite.
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the anticipated
|
||||
/// values of the vector field, u_ex.
|
||||
/// @param[in] weight Optional pointer to a Coefficient object reproducing
|
||||
/// a weighting function, w.
|
||||
/// @param[in] v_weight Optional pointer to a VectorCoefficient object
|
||||
/// reproducing a weighting vector as shown above.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual real_t ComputeLpError(const real_t p, VectorCoefficient &exsol,
|
||||
Coefficient *weight = NULL,
|
||||
VectorCoefficient *v_weight = NULL,
|
||||
const IntegrationRule *irs[] = NULL) const;
|
||||
|
||||
/** Compute the Lp error in each element of the mesh and store the results in
|
||||
the Vector @ error. The result should be of length number of elements,
|
||||
for example an L2 GridFunction of order zero using map type VALUE. */
|
||||
/// @brief Returns ||u_ex - u_h||_Lp elementwise for vector fields
|
||||
///
|
||||
/// Compute the $L^p$ error in each element of the mesh and store the results
|
||||
/// in the Vector @a error. The result should be of length number of
|
||||
/// elements, for example an L2 GridFunction of order zero using map type
|
||||
/// @ref map_type_value "VALUE".
|
||||
///
|
||||
/// Computes:
|
||||
/// $$(\int_{elem} w \, |scalar\_error|^p)^{1/p}$$
|
||||
///
|
||||
/// Where
|
||||
/// $$scalar\_error = |v\_weight \cdot (u_{ex} - u_h)|$$
|
||||
/// or
|
||||
/// $$scalar\_error = \sqrt{(u_{ex} - u_h) \cdot (u_{ex} - u_h)}$$
|
||||
///
|
||||
/// @param[in] p Real value indicating the exponent of the $L^p$
|
||||
/// norm. To avoid domain errors p should have a
|
||||
/// positive value, either finite or infinite.
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the
|
||||
/// anticipated values of the vector field, u_ex.
|
||||
/// @param[in,out] error Vector to contain the element-wise $L^p$ errors
|
||||
/// @param[in] weight Optional pointer to a Coefficient object
|
||||
/// reproducing a weighting function, w.
|
||||
/// @param[in] v_weight Optional pointer to a VectorCoefficient object
|
||||
/// reproducing a weighting vector as shown above.
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
virtual void ComputeElementLpErrors(const real_t p, VectorCoefficient &exsol,
|
||||
Vector &error,
|
||||
Coefficient *weight = NULL,
|
||||
@@ -658,18 +1335,120 @@ public:
|
||||
const IntegrationRule *irs[] = NULL
|
||||
) const;
|
||||
|
||||
/// @brief Returns ||u_ex - u_h||_L1 elementwise for vector fields
|
||||
///
|
||||
/// Compute the $L^1$ error in each element of the mesh and store the
|
||||
/// results in the Vector @a error. The result should be of length number of
|
||||
/// elements, for example an L2 GridFunction of order zero using map type
|
||||
/// @ref map_type_value "VALUE".
|
||||
///
|
||||
/// Computes:
|
||||
/// $$\int_{elem} |scalar\_error|$$
|
||||
///
|
||||
/// Where
|
||||
/// $$scalar\_error = \sqrt{(u_{ex} - u_h) \cdot (u_{ex} - u_h)}$$
|
||||
///
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the
|
||||
/// anticipated values of the vector field, u_ex.
|
||||
/// @param[in,out] error Vector to contain the element-wise $L^1$ errors
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @note Uses ComputeElementLpError internally. See the
|
||||
/// ComputeElementLpError documentation for generalizations of this
|
||||
/// error computation.
|
||||
virtual void ComputeElementL1Errors(VectorCoefficient &exsol,
|
||||
Vector &error,
|
||||
const IntegrationRule *irs[] = NULL
|
||||
) const
|
||||
{ ComputeElementLpErrors(1.0, exsol, error, NULL, NULL, irs); }
|
||||
|
||||
/// @brief Returns ||u_ex - u_h||_L2 elementwise for vector fields
|
||||
///
|
||||
/// Compute the $L^2$ error in each element of the mesh and store the
|
||||
/// results in the Vector @a error. The result should be of length number of
|
||||
/// elements, for example an L2 GridFunction of order zero using map type
|
||||
/// @ref map_type_value "VALUE".
|
||||
///
|
||||
/// Computes:
|
||||
/// $$(\int_{elem} |scalar\_error|^2)^{1/2}$$
|
||||
///
|
||||
/// Where
|
||||
/// $$scalar\_error = \sqrt{(u_{ex} - u_h) \cdot (u_{ex} - u_h)}$$
|
||||
///
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the
|
||||
/// anticipated values of the vector field, u_ex.
|
||||
/// @param[in,out] error Vector to contain the element-wise $L^2$ errors
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Quadratures with negative weights (as in some simplex integration
|
||||
/// rules in MFEM) can produce negative integrals even with
|
||||
/// non-negative integrands. To avoid returning negative errors this
|
||||
/// function uses the absolute values of the element-wise integrals.
|
||||
/// This may lead to results which are not entirely consistent with
|
||||
/// such integration rules.
|
||||
///
|
||||
/// @note Uses ComputeElementLpError internally. See the
|
||||
/// ComputeElementLpError documentation for generalizations of this
|
||||
/// error computation.
|
||||
virtual void ComputeElementL2Errors(VectorCoefficient &exsol,
|
||||
Vector &error,
|
||||
const IntegrationRule *irs[] = NULL
|
||||
) const
|
||||
{ ComputeElementLpErrors(2.0, exsol, error, NULL, NULL, irs); }
|
||||
|
||||
/// @brief Returns Max|u_ex - u_h| elementwise for vector fields
|
||||
///
|
||||
/// Compute the $L^\infty$ error in each element of the mesh and store the
|
||||
/// results in the Vector @a error. The result should be of length number of
|
||||
/// elements, for example an L2 GridFunction of order zero using map type
|
||||
/// @ref map_type_value "VALUE".
|
||||
///
|
||||
/// Computes:
|
||||
/// $$max_{elem} |scalar\_error|$$
|
||||
///
|
||||
/// Where
|
||||
/// $$scalar\_error = \sqrt{(u_{ex} - u_h) \cdot (u_{ex} - u_h)}$$
|
||||
///
|
||||
/// @param[in] exsol VectorCoefficient object reproducing the
|
||||
/// anticipated values of the vector field, u_ex.
|
||||
/// @param[in,out] error Vector to contain the element-wise $L^\infty$
|
||||
/// errors
|
||||
/// @param[in] irs Optional pointer to an array of custom integration
|
||||
/// rules e.g. higher order than the default rules. If
|
||||
/// present the array will be indexed by
|
||||
/// Geometry::Type.
|
||||
///
|
||||
/// @note If an array of integration rules is provided through @a irs, be
|
||||
/// sure to include valid rules for each element type that may occur
|
||||
/// in the list of elements.
|
||||
///
|
||||
/// @note Uses ComputeElementLpError internally. See the
|
||||
/// ComputeElementLpError documentation for generalizations of this
|
||||
/// error computation.
|
||||
///
|
||||
/// @note Computes the maximum magnitude of the difference vector not the
|
||||
/// component-wise maximum difference of the vector fields.
|
||||
virtual void ComputeElementMaxErrors(VectorCoefficient &exsol,
|
||||
Vector &error,
|
||||
const IntegrationRule *irs[] = NULL
|
||||
|
||||
+1138
-50
File diff suppressed because it is too large
Load Diff
+106
-12
@@ -20,9 +20,9 @@
|
||||
namespace gslib
|
||||
{
|
||||
struct comm;
|
||||
struct findpts_data_2;
|
||||
struct findpts_data_3;
|
||||
struct crystal;
|
||||
struct hash_data_3;
|
||||
struct hash_data_2;
|
||||
struct gs_data;
|
||||
}
|
||||
|
||||
@@ -71,18 +71,16 @@ public:
|
||||
protected:
|
||||
Mesh *mesh;
|
||||
Array<Mesh *> mesh_split; // Meshes used to split simplices.
|
||||
// IntegrationRules for simplex->Quad/Hex and to project to highest polynomial
|
||||
// order in-case of p-refinement.
|
||||
// IntegrationRules for simplex->Quad/Hex and to project to p_max in-case of
|
||||
// p-refinement.
|
||||
Array<IntegrationRule *> ir_split;
|
||||
Array<FiniteElementSpace *>
|
||||
fes_rst_map; // FESpaces to map info Quad/Hex->Simplex
|
||||
Array<GridFunction *> gf_rst_map; // GridFunctions to map info Quad/Hex->Simplex
|
||||
Array<FiniteElementSpace *> fes_rst_map; //FESpaces to map Quad/Hex->Simplex
|
||||
Array<GridFunction *> gf_rst_map; // GridFunctions to map Quad/Hex->Simplex
|
||||
FiniteElementCollection *fec_map_lin;
|
||||
struct gslib::findpts_data_2 *fdata2D; // gslib's internal data
|
||||
struct gslib::findpts_data_3 *fdata3D; // gslib's internal data
|
||||
void *fdataD;
|
||||
struct gslib::crystal *cr; // gslib's internal data
|
||||
struct gslib::comm *gsl_comm; // gslib's internal data
|
||||
int dim, points_cnt;
|
||||
int dim, points_cnt; // mesh dimension and number of points
|
||||
Array<unsigned int> gsl_code, gsl_proc, gsl_elem, gsl_mfem_elem;
|
||||
Vector gsl_mesh, gsl_ref, gsl_dist, gsl_mfem_ref;
|
||||
Array<unsigned int> recv_proc, recv_index; // data for custom interpolation
|
||||
@@ -91,9 +89,28 @@ protected:
|
||||
AvgType avgtype; // average type used for L2 functions
|
||||
Array<int> split_element_map;
|
||||
Array<int> split_element_index;
|
||||
int NE_split_total;
|
||||
// Tolerance to ignore points just outside elements at the boundary.
|
||||
int NE_split_total; // total number of elements after mesh splitting
|
||||
int mesh_points_cnt; // number of mesh nodes
|
||||
// Tolerance to ignore points found beyond the mesh boundary.
|
||||
// i.e. if ||x*-x(r)||_2^2 > bdr_tol, we mark point as not found.
|
||||
double bdr_tol;
|
||||
// Use CPU functions for mesh/gridfunction on device for gslib1.0.7
|
||||
bool gpu_to_cpu_fallback = false;
|
||||
|
||||
// Device specific data used for FindPoints
|
||||
struct
|
||||
{
|
||||
bool setup_device = false;
|
||||
bool find_device = false;
|
||||
int local_hash_size, dof1d, dof1d_sol, h_o_size, h_nx;
|
||||
double newt_tol; // Tolerance specified during setup for Newton solve
|
||||
struct gslib::crystal *cr;
|
||||
struct gslib::hash_data_3 *hash3;
|
||||
struct gslib::hash_data_2 *hash2;
|
||||
mutable Vector bb, wtend, gll1d, lagcoeff, gll1d_sol, lagcoeff_sol;
|
||||
mutable Array<unsigned int> loc_hash_offset;
|
||||
mutable Vector loc_hash_min, loc_hash_fac;
|
||||
} DEV;
|
||||
|
||||
/// Use GSLIB for communication and interpolation
|
||||
virtual void InterpolateH1(const GridFunction &field_in, Vector &field_out);
|
||||
@@ -120,6 +137,63 @@ protected:
|
||||
/// during the setup phase.
|
||||
virtual void MapRefPosAndElemIndices();
|
||||
|
||||
// Device functions
|
||||
// FindPoints locally on device for 3D.
|
||||
void FindPointsLocal3(const Vector &point_pos,
|
||||
int point_pos_ordering,
|
||||
Array<unsigned int> &gsl_code_dev_l,
|
||||
Array<unsigned int> &gsl_elem_dev_l,
|
||||
Vector &gsl_ref_l,
|
||||
Vector &gsl_dist_l,
|
||||
int npt);
|
||||
|
||||
// FindPoints locally on device for 2D.
|
||||
void FindPointsLocal2(const Vector &point_pos,
|
||||
int point_pos_ordering,
|
||||
Array<unsigned int> &gsl_code_dev_l,
|
||||
Array<unsigned int> &gsl_elem_dev_l,
|
||||
Vector &gsl_ref_l,
|
||||
Vector &gsl_dist_l,
|
||||
int npt);
|
||||
|
||||
// Interpolate on device for 3D.
|
||||
void InterpolateLocal3(const Vector &field_in,
|
||||
Array<int> &gsl_elem_dev_l,
|
||||
Vector &gsl_ref_l,
|
||||
Vector &field_out,
|
||||
int npt, int ncomp,
|
||||
int nel, int dof1dsol);
|
||||
// Interpolate on device for 2D.
|
||||
void InterpolateLocal2(const Vector &field_in,
|
||||
Array<int> &gsl_elem_dev_l,
|
||||
Vector &gsl_ref_l,
|
||||
Vector &field_out,
|
||||
int npt, int ncomp,
|
||||
int nel, int dof1dsol);
|
||||
|
||||
// Prepare data for device functions.
|
||||
void SetupDevice();
|
||||
|
||||
/** Searches positions given in physical space by @a point_pos.
|
||||
These positions can be ordered byNodes: (XXX...,YYY...,ZZZ) or
|
||||
byVDim: (XYZ,XYZ,....XYZ) specified by @a point_pos_ordering. */
|
||||
void FindPointsOnDevice(const Vector &point_pos,
|
||||
int point_pos_ordering = Ordering::byNODES);
|
||||
|
||||
/** Interpolation of field values at prescribed reference space positions.
|
||||
@param[in] field_in_evec E-vector of gridfunction to be interpolated.
|
||||
Assumed ordering is NDOFSxVDIMxNEL
|
||||
@param[in] nel Number of elements in the mesh.
|
||||
@param[in] ncomp Number of components in the field.
|
||||
@param[in] dof1dsol Number of degrees of freedom in each reference
|
||||
space direction.
|
||||
@param[in] ordering Ordering of the out field values: byNodes/byVDIM
|
||||
|
||||
@param[out] field_out Interpolated values. For points that are not found
|
||||
the value is set to #default_interp_value. */
|
||||
void InterpolateOnDevice(const Vector &field_in_evec, Vector &field_out,
|
||||
const int nel, const int ncomp,
|
||||
const int dof1dsol, const int ordering);
|
||||
public:
|
||||
FindPointsGSLIB();
|
||||
|
||||
@@ -213,6 +287,10 @@ public:
|
||||
bdr_tol = bdr_tol_;
|
||||
}
|
||||
|
||||
/// Enable/Disable use of CPU functions for GPU data if the gslib version
|
||||
/// is older.
|
||||
virtual void SetGPUtoCPUFallback(bool mode) { gpu_to_cpu_fallback = mode; }
|
||||
|
||||
/** Cleans up memory allocated internally by gslib.
|
||||
Note that in parallel, this must be called before MPI_Finalize(), as it
|
||||
calls MPI_Comm_free() for internal gslib communicators. */
|
||||
@@ -272,6 +350,22 @@ public:
|
||||
const int ordering,
|
||||
Vector &field_out) const;
|
||||
///@}
|
||||
|
||||
/// Return the axis-aligned bounding boxes (AABB) computed during \ref Setup.
|
||||
/// The size of the returned vector is (nel x nverts x dim), where nel is the
|
||||
/// number of elements (after splitting for simplcies), nverts is number of
|
||||
/// vertices (4 in 2D, 8 in 3D), and dim is the spatial dimension.
|
||||
void GetAxisAlignedBoundingBoxes(Vector &aabb);
|
||||
|
||||
/// Return the oriented bounding boxes (OBB) computed during \ref Setup.
|
||||
/// Each OBB is represented using the inverse transformation (A^{-1}) and
|
||||
/// its center (x_c), such that a point x is inside the OBB if:
|
||||
/// -1 <= A^{-1}(x-x_c) <= 1.
|
||||
/// The inverse transformation is returned in \p obbA, a DenseTensor of
|
||||
/// size (dim x dim x nel), and the OBB centers are returned in \p obbC,
|
||||
/// a vector of size (nel x dim). The vertices of the OBBs are returned in
|
||||
/// \p obbV, a vector of size (nel x nverts x dim) .
|
||||
void GetOrientedBoundingBoxes(DenseTensor &obbA, Vector &obbC, Vector &obbV);
|
||||
};
|
||||
|
||||
/** \brief OversetFindPointsGSLIB enables use of findpts for arbitrary number of
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,167 @@
|
||||
// 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.
|
||||
|
||||
#include "../gslib.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
|
||||
#ifdef MFEM_USE_GSLIB
|
||||
|
||||
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
#include "gslib.h"
|
||||
#ifndef GSLIB_RELEASE_VERSION //gslib v1.0.7
|
||||
#define GSLIB_RELEASE_VERSION 10007
|
||||
#endif
|
||||
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
namespace mfem
|
||||
{
|
||||
#if GSLIB_RELEASE_VERSION >= 10009
|
||||
#define CODE_INTERNAL 0
|
||||
#define CODE_BORDER 1
|
||||
#define CODE_NOT_FOUND 2
|
||||
|
||||
static MFEM_HOST_DEVICE void lagrange_eval(double *p0, double x,
|
||||
int i, int p_Nq,
|
||||
double *z, double *lagrangeCoeff)
|
||||
{
|
||||
double p_i = (1 << (p_Nq - 1));
|
||||
for (int j = 0; j < p_Nq; ++j)
|
||||
{
|
||||
double d_j = x - z[j];
|
||||
p_i *= j == i ? 1 : d_j;
|
||||
}
|
||||
p0[i] = lagrangeCoeff[i] * p_i;
|
||||
}
|
||||
|
||||
template<int T_D1D = 0>
|
||||
static void InterpolateLocal2DKernel(const double *const gf_in,
|
||||
int *const el,
|
||||
double *const r,
|
||||
double *const int_out,
|
||||
const int npt,
|
||||
const int ncomp,
|
||||
const int nel,
|
||||
const int gf_offset,
|
||||
double *gll1D,
|
||||
double *lagcoeff,
|
||||
const int pN = 0)
|
||||
{
|
||||
const int Nfields = ncomp;
|
||||
const int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
const int D1D = T_D1D ? T_D1D : pN;
|
||||
const int p_Np = D1D*D1D;
|
||||
MFEM_VERIFY(MD1 <= DofQuadLimits::MAX_D1D,
|
||||
"Increase Max allowable polynomial order.");
|
||||
MFEM_VERIFY(D1D != 0, "Polynomial order not specified.");
|
||||
mfem::forall_2D(npt, D1D, D1D, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
MFEM_SHARED double wtr[2*MD1];
|
||||
MFEM_SHARED double sums[MD1*MD1];
|
||||
|
||||
// Evaluate basis functions at the reference space coordinates
|
||||
MFEM_FOREACH_THREAD(j,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(k,y,2)
|
||||
{
|
||||
lagrange_eval(wtr + k*D1D, r[2*i+k], j, D1D, gll1D, lagcoeff);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int fld = 0; fld < Nfields; ++fld)
|
||||
{
|
||||
// If using GetNodalValues, ordering is NDOFSxNELxVDIM
|
||||
// const int elemOffset = el[i] * p_Np + fld * gf_offset;
|
||||
//if using R->Mult for L -> E-Vec use below: NDOFSxVDIMxNEL
|
||||
const int elemOffset = el[i] * p_Np * Nfields + fld * p_Np;
|
||||
MFEM_FOREACH_THREAD(j,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(k,y,D1D)
|
||||
{
|
||||
sums[j + k*D1D] = gf_in[elemOffset + j + k * D1D] *
|
||||
wtr[D1D+k] *
|
||||
wtr[j];
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
// MFEM_FOREACH_THREAD(j,x,D1D)
|
||||
MFEM_FOREACH_THREAD(j,x,1)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(k,y,1)
|
||||
{
|
||||
double sumv = 0.0;
|
||||
for (int jj = 0; jj < D1D*D1D; ++jj)
|
||||
{
|
||||
sumv += sums[jj];
|
||||
}
|
||||
int_out[i + fld * npt] = sumv;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::InterpolateLocal2(const Vector &field_in,
|
||||
Array<int> &gsl_elem_dev_l,
|
||||
Vector &gsl_ref_l,
|
||||
Vector &field_out,
|
||||
int npt, int ncomp,
|
||||
int nel, int dof1Dsol)
|
||||
{
|
||||
if (npt == 0) { return; }
|
||||
const int gf_offset = field_in.Size()/ncomp;
|
||||
auto pfin = field_in.Read();
|
||||
auto pgsl = gsl_elem_dev_l.ReadWrite();
|
||||
auto pgslr = gsl_ref_l.ReadWrite();
|
||||
auto pfout = field_out.Write();
|
||||
auto pgll = DEV.gll1d_sol.ReadWrite();
|
||||
auto plcf = DEV.lagcoeff_sol.ReadWrite();
|
||||
switch (dof1Dsol)
|
||||
{
|
||||
case 2: return InterpolateLocal2DKernel<2>(pfin, pgsl, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf);
|
||||
case 3: return InterpolateLocal2DKernel<3>(pfin, pgsl, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf);
|
||||
case 4: return InterpolateLocal2DKernel<4>(pfin, pgsl, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf);
|
||||
case 5: return InterpolateLocal2DKernel<5>(pfin, pgsl, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf);
|
||||
default: return InterpolateLocal2DKernel(pfin, pgsl, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf, dof1Dsol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#undef CODE_INTERNAL
|
||||
#undef CODE_BORDER
|
||||
#undef CODE_NOT_FOUND
|
||||
#else
|
||||
void FindPointsGSLIB::InterpolateLocal2(const Vector &field_in,
|
||||
Array<int> &gsl_elem_dev_l,
|
||||
Vector &gsl_ref_l,
|
||||
Vector &field_out,
|
||||
int npt, int ncomp,
|
||||
int nel, int dof1Dsol) {};
|
||||
#endif
|
||||
} // namespace mfem
|
||||
|
||||
#endif //ifdef MFEM_USE_GSLIB
|
||||
@@ -0,0 +1,172 @@
|
||||
// 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.
|
||||
|
||||
#include "../gslib.hpp"
|
||||
#include "../../general/forall.hpp"
|
||||
|
||||
#ifdef MFEM_USE_GSLIB
|
||||
|
||||
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
#include "gslib.h"
|
||||
#ifndef GSLIB_RELEASE_VERSION //gslib v1.0.7
|
||||
#define GSLIB_RELEASE_VERSION 10007
|
||||
#endif
|
||||
#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
namespace mfem
|
||||
{
|
||||
#if GSLIB_RELEASE_VERSION >= 10009
|
||||
#define CODE_INTERNAL 0
|
||||
#define CODE_BORDER 1
|
||||
#define CODE_NOT_FOUND 2
|
||||
|
||||
static MFEM_HOST_DEVICE void lagrange_eval(double *p0, double x,
|
||||
int i, int p_Nq,
|
||||
double *z, double *lagrangeCoeff)
|
||||
{
|
||||
double p_i = (1 << (p_Nq - 1));
|
||||
for (int j = 0; j < p_Nq; ++j)
|
||||
{
|
||||
double d_j = x - z[j];
|
||||
p_i *= j == i ? 1 : d_j;
|
||||
}
|
||||
p0[i] = lagrangeCoeff[i] * p_i;
|
||||
}
|
||||
|
||||
template<int T_D1D = 0>
|
||||
static void InterpolateLocal3DKernel(const double *const gf_in,
|
||||
int *const el,
|
||||
double *const r,
|
||||
double *const int_out,
|
||||
const int npt,
|
||||
const int ncomp,
|
||||
const int nel,
|
||||
const int gf_offset,
|
||||
double *gll1D,
|
||||
double *lagcoeff,
|
||||
const int pN = 0)
|
||||
{
|
||||
const int Nfields = ncomp;
|
||||
const int MD1 = T_D1D ? T_D1D : DofQuadLimits::MAX_D1D;
|
||||
const int D1D = T_D1D ? T_D1D : pN;
|
||||
const int p_Np = D1D*D1D*D1D;
|
||||
MFEM_VERIFY(MD1 <= DofQuadLimits::MAX_D1D,
|
||||
"Increase Max allowable polynomial order.");
|
||||
MFEM_VERIFY(D1D != 0, "Polynomial order not specified.");
|
||||
#define MAXC(a, b) (((a) > (b)) ? (a) : (b))
|
||||
const int nThreadsy = MAXC(D1D, 3);
|
||||
mfem::forall_2D(npt, D1D, nThreadsy, [=] MFEM_HOST_DEVICE (int i)
|
||||
{
|
||||
MFEM_SHARED double wtr[3*MD1];
|
||||
MFEM_SHARED double sums[MD1*MD1];
|
||||
|
||||
// Evaluate basis functions at the reference space coordinates
|
||||
MFEM_FOREACH_THREAD(j,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(k,y,3)
|
||||
{
|
||||
lagrange_eval(wtr + k*D1D, r[3*i+k], j, D1D, gll1D, lagcoeff);
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
for (int fld = 0; fld < Nfields; ++fld)
|
||||
{
|
||||
// If using GetNodalValues, ordering is NDOFSxNELxVDIM
|
||||
// const int elemOffset = el[i] * p_Np + fld * gf_offset;
|
||||
//if using R->Mult for L -> E-Vec use below.
|
||||
const int elemOffset = el[i] * p_Np * Nfields + fld * p_Np;
|
||||
MFEM_FOREACH_THREAD(j,x,D1D)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(k,y,D1D)
|
||||
{
|
||||
sums[j + k*D1D] = 0.0;
|
||||
for (int l = 0; l < D1D; ++l)
|
||||
{
|
||||
sums[j + k*D1D] += gf_in[elemOffset + j + k*D1D + l*D1D*D1D] *
|
||||
wtr[2*D1D+l];
|
||||
}
|
||||
sums[j+k*D1D] *= wtr[D1D+k]*wtr[j];
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
|
||||
MFEM_FOREACH_THREAD(j,x,1)
|
||||
{
|
||||
MFEM_FOREACH_THREAD(k,y,1)
|
||||
{
|
||||
double sumv = 0.0;
|
||||
for (int jj = 0; jj < D1D*D1D; ++jj)
|
||||
{
|
||||
sumv += sums[jj];
|
||||
}
|
||||
int_out[i + fld * npt] = sumv;
|
||||
}
|
||||
}
|
||||
MFEM_SYNC_THREAD;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FindPointsGSLIB::InterpolateLocal3(const Vector &field_in,
|
||||
Array<int> &gsl_elem_dev_l,
|
||||
Vector &gsl_ref_l,
|
||||
Vector &field_out,
|
||||
int npt, int ncomp,
|
||||
int nel, int dof1Dsol)
|
||||
{
|
||||
if (npt == 0) { return; }
|
||||
const int gf_offset = field_in.Size()/ncomp;
|
||||
auto pfin = field_in.Read();
|
||||
auto pgsle = gsl_elem_dev_l.ReadWrite();
|
||||
auto pgslr = gsl_ref_l.ReadWrite();
|
||||
auto pfout = field_out.Write();
|
||||
auto pgll = DEV.gll1d_sol.ReadWrite();
|
||||
auto plcf = DEV.lagcoeff_sol.ReadWrite();
|
||||
switch (dof1Dsol)
|
||||
{
|
||||
case 2: return InterpolateLocal3DKernel<2>(pfin, pgsle, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf);
|
||||
case 3: return InterpolateLocal3DKernel<3>(pfin, pgsle, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf);
|
||||
case 4: return InterpolateLocal3DKernel<4>(pfin, pgsle, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf);
|
||||
case 5: return InterpolateLocal3DKernel<5>(pfin, pgsle, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf);
|
||||
default: return InterpolateLocal3DKernel(pfin, pgsle, pgslr, pfout,
|
||||
npt, ncomp, nel, gf_offset,
|
||||
pgll, plcf, dof1Dsol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#undef CODE_INTERNAL
|
||||
#undef CODE_BORDER
|
||||
#undef CODE_NOT_FOUND
|
||||
#else
|
||||
void FindPointsGSLIB::InterpolateLocal3(const Vector &field_in,
|
||||
Array<int> &gsl_elem_dev_l,
|
||||
Vector &gsl_ref_l,
|
||||
Vector &field_out,
|
||||
int npt, int ncomp,
|
||||
int nel, int dof1Dsol) {};
|
||||
#endif
|
||||
} // namespace mfem
|
||||
|
||||
#endif //ifdef MFEM_USE_GSLIB
|
||||
+691
-27
@@ -18,6 +18,29 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
HyperbolicFormIntegrator::HyperbolicFormIntegrator(
|
||||
const NumericalFlux &numFlux,
|
||||
const int IntOrderOffset,
|
||||
real_t sign)
|
||||
: NonlinearFormIntegrator(),
|
||||
numFlux(numFlux),
|
||||
fluxFunction(numFlux.GetFluxFunction()),
|
||||
IntOrderOffset(IntOrderOffset),
|
||||
sign(sign),
|
||||
num_equations(fluxFunction.num_equations)
|
||||
{
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
state.SetSize(num_equations);
|
||||
flux.SetSize(num_equations, fluxFunction.dim);
|
||||
state1.SetSize(num_equations);
|
||||
state2.SetSize(num_equations);
|
||||
fluxN.SetSize(num_equations);
|
||||
JDotN.SetSize(num_equations);
|
||||
nor.SetSize(fluxFunction.dim);
|
||||
#endif
|
||||
ResetMaxCharSpeed();
|
||||
}
|
||||
|
||||
void HyperbolicFormIntegrator::AssembleElementVector(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
const Vector &elfun,
|
||||
@@ -33,7 +56,7 @@ void HyperbolicFormIntegrator::AssembleElementVector(const FiniteElement &el,
|
||||
// shape function value at an integration point
|
||||
Vector shape(dof);
|
||||
// derivative of shape function at an integration point
|
||||
DenseMatrix dshape(dof, el.GetDim());
|
||||
DenseMatrix dshape(dof, Tr.GetSpaceDim());
|
||||
// state value at an integration point
|
||||
Vector state(num_equations);
|
||||
// flux value at an integration point
|
||||
@@ -41,7 +64,7 @@ void HyperbolicFormIntegrator::AssembleElementVector(const FiniteElement &el,
|
||||
#else
|
||||
// resize shape and gradient shape storage
|
||||
shape.SetSize(dof);
|
||||
dshape.SetSize(dof, el.GetDim());
|
||||
dshape.SetSize(dof, Tr.GetSpaceDim());
|
||||
#endif
|
||||
|
||||
// setDegree-up output vector
|
||||
@@ -77,7 +100,77 @@ void HyperbolicFormIntegrator::AssembleElementVector(const FiniteElement &el,
|
||||
// update maximum characteristic speed
|
||||
max_char_speed = std::max(mcs, max_char_speed);
|
||||
// integrate (F(u,x), grad v)
|
||||
AddMult_a_ABt(ip.weight * Tr.Weight(), dshape, flux, elvect_mat);
|
||||
AddMult_a_ABt(ip.weight * Tr.Weight() * sign, dshape, flux, elvect_mat);
|
||||
}
|
||||
}
|
||||
|
||||
void HyperbolicFormIntegrator::AssembleElementGrad(
|
||||
const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun,
|
||||
DenseMatrix &grad)
|
||||
{
|
||||
// current element's the number of degrees of freedom
|
||||
// does not consider the number of equations
|
||||
const int dof = el.GetDof();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
|
||||
// shape function value at an integration point
|
||||
Vector shape(dof);
|
||||
// derivative of shape function at an integration point
|
||||
DenseMatrix dshape(dof, Tr.GetSpaceDim());
|
||||
// state value at an integration point
|
||||
Vector state(num_equations);
|
||||
// Jacobian value at an integration point
|
||||
DenseTensor J(num_equations, num_equations, fluxFunction.dim);
|
||||
#else
|
||||
// resize shape, gradient shape and Jacobian storage
|
||||
shape.SetSize(dof);
|
||||
dshape.SetSize(dof, Tr.GetSpaceDim());
|
||||
J.SetSize(num_equations, num_equations, fluxFunction.dim);
|
||||
#endif
|
||||
|
||||
// setup output gradient matrix
|
||||
grad.SetSize(dof * num_equations);
|
||||
grad = 0.0;
|
||||
|
||||
// make state variable and output dual vector matrix form.
|
||||
const DenseMatrix elfun_mat(elfun.GetData(), dof, num_equations);
|
||||
//DenseMatrix elvect_mat(elvect.GetData(), dof, num_equations);
|
||||
|
||||
// obtain integration rule. If integration is rule is given, then use it.
|
||||
// Otherwise, get (2*p + IntOrderOffset) order integration rule
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
const int order = el.GetOrder()*2 + IntOrderOffset;
|
||||
ir = &IntRules.Get(Tr.GetGeometryType(), order);
|
||||
}
|
||||
|
||||
// loop over integration points
|
||||
for (int q = 0; q < ir->GetNPoints(); q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(q);
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
el.CalcShape(ip, shape);
|
||||
el.CalcPhysDShape(Tr, dshape);
|
||||
// compute current state value with given shape function values
|
||||
elfun_mat.MultTranspose(shape, state);
|
||||
|
||||
// compute J(u,x)
|
||||
fluxFunction.ComputeFluxJacobian(state, Tr, J);
|
||||
|
||||
// integrate (J(u,x), grad v)
|
||||
const real_t w = ip.weight * Tr.Weight() * sign;
|
||||
for (int di = 0; di < num_equations; di++)
|
||||
for (int dj = 0; dj < num_equations; dj++)
|
||||
for (int i = 0; i < dof; i++)
|
||||
for (int j = 0; j < dof; j++)
|
||||
for (int d = 0; d < fluxFunction.dim; d++)
|
||||
{
|
||||
grad(di*dof+i, dj*dof+j) += w * dshape(i,d) * shape(j) * J(di,dj,d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +191,7 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
// shape function value at an integration point - second elem
|
||||
Vector shape2(dof2);
|
||||
// normal vector (usually not a unit vector)
|
||||
Vector nor(el1.GetDim());
|
||||
Vector nor(Tr.GetSpaceDim());
|
||||
// state value at an integration point - first elem
|
||||
Vector state1(num_equations);
|
||||
// state value at an integration point - second elem
|
||||
@@ -157,34 +250,144 @@ void HyperbolicFormIntegrator::AssembleFaceVector(
|
||||
}
|
||||
// Compute F(u+, x) and F(u-, x) with maximum characteristic speed
|
||||
// Compute hat(F) using evaluated quantities
|
||||
const real_t speed = rsolver.Eval(state1, state2, nor, Tr, fluxN);
|
||||
const real_t speed = numFlux.Eval(state1, state2, nor, Tr, fluxN);
|
||||
|
||||
// Update the global max char speed
|
||||
max_char_speed = std::max(speed, max_char_speed);
|
||||
|
||||
// pre-multiply integration weight to flux
|
||||
AddMult_a_VWt(-ip.weight, shape1, fluxN, elvect1_mat);
|
||||
AddMult_a_VWt(+ip.weight, shape2, fluxN, elvect2_mat);
|
||||
AddMult_a_VWt(-ip.weight*sign, shape1, fluxN, elvect1_mat);
|
||||
AddMult_a_VWt(+ip.weight*sign, shape2, fluxN, elvect2_mat);
|
||||
}
|
||||
}
|
||||
|
||||
HyperbolicFormIntegrator::HyperbolicFormIntegrator(
|
||||
const RiemannSolver &rsolver,
|
||||
const int IntOrderOffset)
|
||||
: NonlinearFormIntegrator(),
|
||||
rsolver(rsolver),
|
||||
fluxFunction(rsolver.GetFluxFunction()),
|
||||
IntOrderOffset(IntOrderOffset),
|
||||
num_equations(fluxFunction.num_equations)
|
||||
void HyperbolicFormIntegrator::AssembleFaceGrad(
|
||||
const FiniteElement &el1, const FiniteElement &el2,
|
||||
FaceElementTransformations &Tr, const Vector &elfun, DenseMatrix &elmat)
|
||||
{
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
state.SetSize(num_equations);
|
||||
flux.SetSize(num_equations, fluxFunction.dim);
|
||||
state1.SetSize(num_equations);
|
||||
state2.SetSize(num_equations);
|
||||
fluxN.SetSize(num_equations);
|
||||
nor.SetSize(fluxFunction.dim);
|
||||
// current elements' the number of degrees of freedom
|
||||
// does not consider the number of equations
|
||||
const int dof1 = el1.GetDof();
|
||||
const int dof2 = el2.GetDof();
|
||||
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
|
||||
// shape function value at an integration point - first elem
|
||||
Vector shape1(dof1);
|
||||
// shape function value at an integration point - second elem
|
||||
Vector shape2(dof2);
|
||||
// normal vector (usually not a unit vector)
|
||||
Vector nor(Tr.GetSpaceDim());
|
||||
// state value at an integration point - first elem
|
||||
Vector state1(num_equations);
|
||||
// state value at an integration point - second elem
|
||||
Vector state2(num_equations);
|
||||
// hat(J)(u,x)
|
||||
DenseMatrix JDotN(num_equations);
|
||||
#else
|
||||
shape1.SetSize(dof1);
|
||||
shape2.SetSize(dof2);
|
||||
#endif
|
||||
|
||||
elmat.SetSize((dof1 + dof2) * num_equations);
|
||||
elmat = 0.0;
|
||||
|
||||
const DenseMatrix elfun1_mat(elfun.GetData(), dof1, num_equations);
|
||||
const DenseMatrix elfun2_mat(elfun.GetData() + dof1 * num_equations, dof2,
|
||||
num_equations);
|
||||
|
||||
// Obtain integration rule. If integration is rule is given, then use it.
|
||||
// Otherwise, get (2*p + IntOrderOffset) order integration rule
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
const int order = 2*std::max(el1.GetOrder(), el2.GetOrder()) + IntOrderOffset;
|
||||
ir = &IntRules.Get(Tr.GetGeometryType(), order);
|
||||
}
|
||||
// loop over integration points
|
||||
for (int q = 0; q < ir->GetNPoints(); q++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(q);
|
||||
|
||||
Tr.SetAllIntPoints(&ip); // set face and element int. points
|
||||
|
||||
// Calculate basis functions on both elements at the face
|
||||
el1.CalcShape(Tr.GetElement1IntPoint(), shape1);
|
||||
el2.CalcShape(Tr.GetElement2IntPoint(), shape2);
|
||||
|
||||
// Interpolate elfun at the point
|
||||
elfun1_mat.MultTranspose(shape1, state1);
|
||||
elfun2_mat.MultTranspose(shape2, state2);
|
||||
|
||||
// Get the normal vector and the flux on the face
|
||||
if (nor.Size() == 1) // if 1D, use 1 or -1.
|
||||
{
|
||||
// This assume the 1D integration point is in (0,1). This may not work
|
||||
// if this changes.
|
||||
nor(0) = (Tr.GetElement1IntPoint().x - 0.5) * 2.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalcOrtho(Tr.Jacobian(), nor);
|
||||
}
|
||||
|
||||
// Trial side 1
|
||||
|
||||
// Compute hat(J) using evaluated quantities
|
||||
numFlux.Grad(1, state1, state2, nor, Tr, JDotN);
|
||||
|
||||
const int ioff = fluxFunction.num_equations * dof1;
|
||||
|
||||
for (int di = 0; di < fluxFunction.num_equations; di++)
|
||||
for (int dj = 0; dj < fluxFunction.num_equations; dj++)
|
||||
{
|
||||
// pre-multiply integration weight to Jacobian
|
||||
const real_t w = -ip.weight * sign * JDotN(di,dj);
|
||||
for (int j = 0; j < dof1; j++)
|
||||
{
|
||||
// Test side 1
|
||||
for (int i = 0; i < dof1; i++)
|
||||
{
|
||||
elmat(i+dof1*di, j+dof1*dj) += w * shape1(i) * shape1(j);
|
||||
}
|
||||
|
||||
// Test side 2
|
||||
for (int i = 0; i < dof2; i++)
|
||||
{
|
||||
elmat(ioff+i+dof2*di, j+dof1*dj) -= w * shape2(i) * shape1(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trial side 2
|
||||
|
||||
// Compute hat(J) using evaluated quantities
|
||||
numFlux.Grad(2, state1, state2, nor, Tr, JDotN);
|
||||
|
||||
const int joff = ioff;
|
||||
|
||||
for (int di = 0; di < fluxFunction.num_equations; di++)
|
||||
for (int dj = 0; dj < fluxFunction.num_equations; dj++)
|
||||
{
|
||||
// pre-multiply integration weight to Jacobian
|
||||
const real_t w = +ip.weight * sign * JDotN(di,dj);
|
||||
for (int j = 0; j < dof2; j++)
|
||||
{
|
||||
// Test side 1
|
||||
for (int i = 0; i < dof1; i++)
|
||||
{
|
||||
elmat(i+dof1*di, joff+j+dof2*dj) += w * shape1(i) * shape2(j);
|
||||
}
|
||||
|
||||
// Test side 2
|
||||
for (int i = 0; i < dof2; i++)
|
||||
{
|
||||
elmat(ioff+i+dof2*di, joff+j+dof2*dj) -= w * shape2(i) * shape2(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
real_t FluxFunction::ComputeFluxDotN(const Vector &U,
|
||||
@@ -194,12 +397,55 @@ real_t FluxFunction::ComputeFluxDotN(const Vector &U,
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix flux(num_equations, dim);
|
||||
#else
|
||||
flux.SetSize(num_equations, dim);
|
||||
#endif
|
||||
real_t val = ComputeFlux(U, Tr, flux);
|
||||
flux.Mult(normal, FUdotN);
|
||||
return val;
|
||||
}
|
||||
|
||||
real_t FluxFunction::ComputeAvgFluxDotN(const Vector &U1, const Vector &U2,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &fluxDotN) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix flux(num_equations, dim);
|
||||
#else
|
||||
flux.SetSize(num_equations, dim);
|
||||
#endif
|
||||
real_t val = ComputeAvgFlux(U1, U2, Tr, flux);
|
||||
flux.Mult(normal, fluxDotN);
|
||||
return val;
|
||||
}
|
||||
|
||||
void FluxFunction::ComputeFluxJacobianDotN(const Vector &U,
|
||||
const Vector &normal,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &JDotN) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseTensor J(num_equations, num_equations, dim);
|
||||
#else
|
||||
J.SetSize(num_equations, num_equations, dim);
|
||||
#endif
|
||||
ComputeFluxJacobian(U, Tr, J);
|
||||
JDotN.Set(normal(0), J(0));
|
||||
for (int d = 1; d < dim; d++)
|
||||
{
|
||||
JDotN.AddMatrix(normal(d), J(d), 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
RusanovFlux::RusanovFlux(const FluxFunction &fluxFunction)
|
||||
: NumericalFlux(fluxFunction)
|
||||
{
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
fluxN1.SetSize(fluxFunction.num_equations);
|
||||
fluxN2.SetSize(fluxFunction.num_equations);
|
||||
#endif
|
||||
}
|
||||
|
||||
real_t RusanovFlux::Eval(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
@@ -212,15 +458,321 @@ real_t RusanovFlux::Eval(const Vector &state1, const Vector &state2,
|
||||
const real_t speed2 = fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
|
||||
// NOTE: nor in general is not a unit normal
|
||||
const real_t maxE = std::max(speed1, speed2);
|
||||
// here, std::sqrt(nor*nor) is multiplied to match the scale with fluxN
|
||||
const real_t scaledMaxE = maxE*std::sqrt(nor*nor);
|
||||
for (int i=0; i<state1.Size(); i++)
|
||||
// here, nor.Norml2() is multiplied to match the scale with fluxN
|
||||
const real_t scaledMaxE = maxE * nor.Norml2();
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
flux[i] = 0.5*(scaledMaxE*(state1[i] - state2[i]) + (fluxN1[i] + fluxN2[i]));
|
||||
flux(i) = 0.5*(scaledMaxE*(state1(i) - state2(i)) + (fluxN1(i) + fluxN2(i)));
|
||||
}
|
||||
return maxE;
|
||||
}
|
||||
|
||||
void RusanovFlux::Grad(int side, const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector fluxN1(fluxFunction.num_equations), fluxN2(fluxFunction.num_equations);
|
||||
#endif
|
||||
|
||||
const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
|
||||
const real_t speed2 = fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
|
||||
|
||||
// NOTE: nor in general is not a unit normal
|
||||
const real_t maxE = std::max(speed1, speed2);
|
||||
// here, nor.Norml2() is multiplied to match the scale with fluxN
|
||||
const real_t scaledMaxE = maxE * nor.Norml2();
|
||||
|
||||
if (side == 1)
|
||||
{
|
||||
fluxFunction.ComputeFluxJacobianDotN(state1, nor, Tr, grad);
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
grad(i,i) += 0.5 * scaledMaxE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fluxFunction.ComputeFluxJacobianDotN(state2, nor, Tr, grad);
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
grad(i,i) -= 0.5 * scaledMaxE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
real_t RusanovFlux::Average(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector fluxN1(fluxFunction.num_equations), fluxN2(fluxFunction.num_equations);
|
||||
#endif
|
||||
const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
|
||||
const real_t speed2 = fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr,
|
||||
fluxN2);
|
||||
// NOTE: nor in general is not a unit normal
|
||||
const real_t maxE = std::max(speed1, speed2);
|
||||
// here, nor.Norml2() is multiplied to match the scale with fluxN
|
||||
const real_t scaledMaxE = maxE * nor.Norml2() * 0.5;
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
flux(i) = 0.5*(scaledMaxE*(state1(i) - state2(i)) + (fluxN1(i) + fluxN2(i)));
|
||||
}
|
||||
return maxE;
|
||||
}
|
||||
|
||||
void RusanovFlux::AverageGrad(int side, const Vector &state1,
|
||||
const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector fluxN1(fluxFunction.num_equations), fluxN2(fluxFunction.num_equations);
|
||||
#endif
|
||||
|
||||
#if defined(MFEM_USE_DOUBLE)
|
||||
constexpr real_t tol = 1e-12;
|
||||
#elif defined(MFEM_USE_SINGLE)
|
||||
constexpr real_t tol = 4e-6;
|
||||
#else
|
||||
#error "Only single and double precision are supported!"
|
||||
constexpr real_t tol = 1.;
|
||||
#endif
|
||||
|
||||
auto equal_check = [=](real_t a, real_t b) -> bool { return std::abs(a - b) <= tol * std::abs(a + b); };
|
||||
|
||||
if (side == 1)
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix JDotN(fluxFunction.num_equations);
|
||||
#else
|
||||
JDotN.SetSize(fluxFunction.num_equations);
|
||||
#endif
|
||||
const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
|
||||
const real_t speed2 = fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr,
|
||||
fluxN2);
|
||||
fluxFunction.ComputeFluxJacobianDotN(state1, nor, Tr, JDotN);
|
||||
|
||||
// NOTE: nor in general is not a unit normal
|
||||
const real_t maxE = std::max(speed1, speed2);
|
||||
// here, nor.Norml2() is multiplied to match the scale with fluxN
|
||||
const real_t scaledMaxE = maxE * nor.Norml2() * 0.5;
|
||||
|
||||
grad = 0.;
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
// Only diagonal terms of J are considered
|
||||
// lim_{u → u⁻} (F̄(u⁻,u)n - F(u⁻)n) / (u - u⁻) = ½λ
|
||||
if (equal_check(state1(i), state2(i))) { continue; }
|
||||
grad(i,i) = 0.5 * ((fluxN2(i) - fluxN1(i)) / (state2(i) - state1(i))
|
||||
- JDotN(i,i) + scaledMaxE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const real_t speed1 = fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr,
|
||||
fluxN1);
|
||||
const real_t speed2 = fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
|
||||
|
||||
// NOTE: nor in general is not a unit normal
|
||||
const real_t maxE = std::max(speed1, speed2);
|
||||
// here, nor.Norml2() is multiplied to match the scale with fluxN
|
||||
const real_t scaledMaxE = maxE * nor.Norml2() * 0.5;
|
||||
|
||||
grad = 0.;
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
// lim_{u → u⁻} (F(u)n - F̄(u⁻,u)n) / (u - u⁻) = ½λ
|
||||
if (equal_check(state1(i), state2(i))) { continue; }
|
||||
grad(i,i) = 0.5 * ((fluxN2(i) - fluxN1(i)) / (state2(i) - state1(i))
|
||||
- scaledMaxE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ComponentwiseUpwindFlux::ComponentwiseUpwindFlux(
|
||||
const FluxFunction &fluxFunction)
|
||||
: NumericalFlux(fluxFunction)
|
||||
{
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
fluxN1.SetSize(fluxFunction.num_equations);
|
||||
fluxN2.SetSize(fluxFunction.num_equations);
|
||||
#endif
|
||||
if (fluxFunction.dim > 1)
|
||||
MFEM_WARNING("Upwinded flux is implemented only component-wise.")
|
||||
}
|
||||
|
||||
real_t ComponentwiseUpwindFlux::Eval(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector fluxN1(fluxFunction.num_equations), fluxN2(fluxFunction.num_equations);
|
||||
#endif
|
||||
const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
|
||||
const real_t speed2 = fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
if (state1(i) <= state2(i))
|
||||
{
|
||||
flux(i) = std::min(fluxN1(i), fluxN2(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
flux(i) = std::max(fluxN1(i), fluxN2(i));
|
||||
}
|
||||
}
|
||||
|
||||
return std::max(speed1, speed2);
|
||||
}
|
||||
|
||||
void ComponentwiseUpwindFlux::Grad(int side, const Vector &state1,
|
||||
const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix JDotN(fluxFunction.num_equations);
|
||||
#else
|
||||
JDotN.SetSize(fluxFunction.num_equations);
|
||||
#endif
|
||||
|
||||
grad = 0.;
|
||||
|
||||
if (side == 1)
|
||||
{
|
||||
fluxFunction.ComputeFluxJacobianDotN(state1, nor, Tr, JDotN);
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
// Only diagonal terms of J are considered
|
||||
grad(i,i) = std::max(JDotN(i,i), 0_r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fluxFunction.ComputeFluxJacobianDotN(state2, nor, Tr, JDotN);
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
// Only diagonal terms of J are considered
|
||||
grad(i,i) = std::min(JDotN(i,i), 0_r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
real_t ComponentwiseUpwindFlux::Average(const Vector &state1,
|
||||
const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector fluxN1(fluxFunction.num_equations), fluxN2(fluxFunction.num_equations);
|
||||
#endif
|
||||
const real_t speed1 = fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
|
||||
const real_t speed2 = fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr,
|
||||
fluxN2);
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
if (state1(i) <= state2(i))
|
||||
{
|
||||
flux(i) = std::min(fluxN1(i), fluxN2(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
flux(i) = std::max(fluxN1(i), fluxN2(i));
|
||||
}
|
||||
}
|
||||
|
||||
return std::max(speed1, speed2);
|
||||
}
|
||||
|
||||
void ComponentwiseUpwindFlux::AverageGrad(int side, const Vector &state1,
|
||||
const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector fluxN1(fluxFunction.num_equations), fluxN2(fluxFunction.num_equations);
|
||||
#endif
|
||||
|
||||
#if defined(MFEM_USE_DOUBLE)
|
||||
constexpr real_t tol = 1e-12;
|
||||
#elif defined(MFEM_USE_SINGLE)
|
||||
constexpr real_t tol = 4e-6;
|
||||
#else
|
||||
#error "Only single and double precision are supported!"
|
||||
constexpr real_t tol = 1.;
|
||||
#endif
|
||||
|
||||
auto equal_check = [=](real_t a, real_t b) -> bool { return std::abs(a - b) <= tol * std::abs(a + b); };
|
||||
|
||||
if (side == 1)
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix JDotN(fluxFunction.num_equations);
|
||||
#else
|
||||
JDotN.SetSize(fluxFunction.num_equations);
|
||||
#endif
|
||||
fluxFunction.ComputeFluxDotN(state1, nor, Tr, fluxN1);
|
||||
fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr, fluxN2);
|
||||
fluxFunction.ComputeFluxJacobianDotN(state1, nor, Tr, JDotN);
|
||||
|
||||
grad = 0.;
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
// Only diagonal terms of J are considered
|
||||
// lim_{u → u⁻} (F̄(u⁻,u)n - F(u⁻)n) / (u - u⁻) = ½J(u⁻)n
|
||||
const real_t gr12 = (!equal_check(state1(i), state2(i)))?
|
||||
(fluxN2(i) - fluxN1(i)) / (state2(i) - state1(i))
|
||||
:(0.5 * JDotN(i,i));
|
||||
grad(i,i) = (gr12 >= 0.)?(JDotN(i,i)):(gr12);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
DenseMatrix JDotN;
|
||||
#endif
|
||||
fluxFunction.ComputeAvgFluxDotN(state1, state2, nor, Tr, fluxN1);
|
||||
fluxFunction.ComputeFluxDotN(state2, nor, Tr, fluxN2);
|
||||
|
||||
// Jacobian is not needed except the limit case when u⁺=u⁻
|
||||
bool J_needed = false;
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
if (equal_check(state1(i), state2(i)))
|
||||
{
|
||||
J_needed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (J_needed)
|
||||
{
|
||||
JDotN.SetSize(fluxFunction.num_equations);
|
||||
fluxFunction.ComputeFluxJacobianDotN(state1, nor, Tr, JDotN);
|
||||
}
|
||||
|
||||
grad = 0.;
|
||||
|
||||
for (int i = 0; i < fluxFunction.num_equations; i++)
|
||||
{
|
||||
// Only diagonal terms of J are considered
|
||||
// lim_{u → u⁻} (F(u)n - F̄(u⁻,u)n) / (u - u⁻) = ½J(u⁻)n
|
||||
const real_t gr12 = (!equal_check(state1(i), state2(i)))?
|
||||
(fluxN2(i) - fluxN1(i)) / (state2(i) - state1(i))
|
||||
:(0.5 * JDotN(i,i));
|
||||
grad(i,i) = std::min(gr12, 0_r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
real_t AdvectionFlux::ComputeFlux(const Vector &U,
|
||||
ElementTransformation &Tr,
|
||||
@@ -234,15 +786,127 @@ real_t AdvectionFlux::ComputeFlux(const Vector &U,
|
||||
return bval.Norml2();
|
||||
}
|
||||
|
||||
real_t AdvectionFlux::ComputeFluxDotN(const Vector &U,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &FDotN) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector bval(b.GetVDim());
|
||||
#endif
|
||||
b.Eval(bval, Tr, Tr.GetIntPoint());
|
||||
FDotN(0) = U(0) * (bval * normal);
|
||||
return bval.Norml2();
|
||||
}
|
||||
|
||||
real_t AdvectionFlux::ComputeAvgFlux(const Vector &U1, const Vector &U2,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &FU) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector bval(b.GetVDim());
|
||||
#endif
|
||||
b.Eval(bval, Tr, Tr.GetIntPoint());
|
||||
Vector Uavg(1);
|
||||
Uavg(0) = (U1(0) + U2(0)) * 0.5;
|
||||
MultVWt(Uavg, bval, FU);
|
||||
return bval.Norml2();
|
||||
}
|
||||
|
||||
real_t AdvectionFlux::ComputeAvgFluxDotN(const Vector &U1, const Vector &U2,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &FDotN) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector bval(b.GetVDim());
|
||||
#endif
|
||||
b.Eval(bval, Tr, Tr.GetIntPoint());
|
||||
FDotN(0) = (U1(0) + U2(0)) * 0.5 * (bval * normal);
|
||||
return bval.Norml2();
|
||||
}
|
||||
|
||||
void AdvectionFlux::ComputeFluxJacobian(const Vector &state,
|
||||
ElementTransformation &Tr,
|
||||
DenseTensor &J) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector bval(b.GetVDim());
|
||||
#endif
|
||||
b.Eval(bval, Tr, Tr.GetIntPoint());
|
||||
J = 0.;
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
J(0,0,d) = bval(d);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvectionFlux::ComputeFluxJacobianDotN(const Vector &state,
|
||||
const Vector &normal,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &JDotN) const
|
||||
{
|
||||
#ifdef MFEM_THREAD_SAFE
|
||||
Vector bval(b.GetVDim());
|
||||
#endif
|
||||
b.Eval(bval, Tr, Tr.GetIntPoint());
|
||||
JDotN(0,0) = bval * normal;
|
||||
}
|
||||
|
||||
real_t BurgersFlux::ComputeFlux(const Vector &U,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &FU) const
|
||||
{
|
||||
FU = U * U * 0.5;
|
||||
FU = U(0) * U(0) * 0.5;
|
||||
return std::fabs(U(0));
|
||||
}
|
||||
|
||||
real_t BurgersFlux::ComputeFluxDotN(const Vector &U,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &FDotN) const
|
||||
{
|
||||
FDotN(0) = U(0) * U(0) * 0.5 * normal.Sum();
|
||||
return std::fabs(U(0));
|
||||
}
|
||||
|
||||
real_t BurgersFlux::ComputeAvgFlux(const Vector &U1,
|
||||
const Vector &U2,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &FU) const
|
||||
{
|
||||
FU = (U1(0)*U1(0) + U1(0)*U2(0) + U2(0)*U2(0)) / 6.;
|
||||
return std::max(std::fabs(U1(0)), std::fabs(U2(0)));
|
||||
}
|
||||
|
||||
real_t BurgersFlux::ComputeAvgFluxDotN(const Vector &U1,
|
||||
const Vector &U2,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &FDotN) const
|
||||
{
|
||||
FDotN(0) = (U1(0)*U1(0) + U1(0)*U2(0) + U2(0)*U2(0)) / 6. * normal.Sum();
|
||||
return std::max(std::fabs(U1(0)), std::fabs(U2(0)));
|
||||
}
|
||||
|
||||
void BurgersFlux::ComputeFluxJacobian(const Vector &U,
|
||||
ElementTransformation &Tr,
|
||||
DenseTensor &J) const
|
||||
{
|
||||
J = 0.;
|
||||
for (int d = 0; d < dim; d++)
|
||||
{
|
||||
J(0,0,d) = U(0);
|
||||
}
|
||||
}
|
||||
|
||||
void BurgersFlux::ComputeFluxJacobianDotN(const Vector &U,
|
||||
const Vector &normal,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &JDotN) const
|
||||
{
|
||||
JDotN(0,0) = U(0) * normal.Sum();
|
||||
}
|
||||
|
||||
real_t ShallowWaterFlux::ComputeFlux(const Vector &U,
|
||||
ElementTransformation &Tr,
|
||||
|
||||
+570
-79
@@ -19,17 +19,17 @@ namespace mfem
|
||||
{
|
||||
|
||||
// This file contains general hyperbolic conservation element/face form
|
||||
// integrators. HyperbolicFormIntegrator and RiemannSolver are defined.
|
||||
// integrators. HyperbolicFormIntegrator and NumericalFlux are defined.
|
||||
//
|
||||
// HyperbolicFormIntegrator is a NonlinearFormIntegrator that implements
|
||||
// element weak divergence and interface flux
|
||||
//
|
||||
// ∫_T F(u):∇v, -∫_e F̂(u)⋅[[v]]
|
||||
// ∫_K F(u):∇v, -∫_f F̂(u)⋅n[v]
|
||||
//
|
||||
// Here, T is an element, e is an edge, and [[⋅]] is jump. This form integrator
|
||||
// is coupled with RiemannSolver that implements the numerical flux F̂. For
|
||||
// RiemannSolver, the Rusanov flux, also known as local Lax-Friedrichs flux, is
|
||||
// provided.
|
||||
// Here, K is an element, f is a face, n normal and [⋅] is jump. This form
|
||||
// integrator is coupled with NumericalFlux that implements the numerical flux
|
||||
// F̂. For NumericalFlux, the Rusanov flux, also known as local Lax-Friedrichs
|
||||
// flux, or component-wise upwinded flux are provided.
|
||||
//
|
||||
// To implement a specific hyperbolic conservation laws, users can create
|
||||
// derived classes from FluxFunction with overloaded ComputeFlux. One can
|
||||
@@ -61,58 +61,126 @@ public:
|
||||
const int dim;
|
||||
|
||||
FluxFunction(const int num_equations, const int dim)
|
||||
: num_equations(num_equations), dim(dim)
|
||||
{
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
flux.SetSize(num_equations, dim);
|
||||
#endif
|
||||
}
|
||||
: num_equations(num_equations), dim(dim) { }
|
||||
|
||||
virtual ~FluxFunction() {}
|
||||
|
||||
/**
|
||||
* @brief Compute flux F(u, x) for given state u and physical point x
|
||||
* @brief Compute flux F(u, x). Must be implemented in a derived class.
|
||||
*
|
||||
* @param[in] state value of state at the current integration point
|
||||
* @param[in] Tr element information
|
||||
* @param[out] flux F(u, x)
|
||||
* @return real_t maximum characteristic speed
|
||||
* Used in HyperbolicFormIntegrator::AssembleElementVector() for evaluation
|
||||
* of (F(u), ∇v) and in the default implementation of ComputeFluxDotN()
|
||||
* for evaluation of F(u)⋅n.
|
||||
* @param[in] state state at the current integration point (num_equations)
|
||||
* @param[in] Tr element transformation
|
||||
* @param[out] flux flux from the given element at the current
|
||||
* integration point (num_equations, dim)
|
||||
* @return real_t maximum characteristic speed |dF(u,x)/du|
|
||||
*
|
||||
* @note One can put assertion in here to detect non-physical solution
|
||||
*/
|
||||
virtual real_t ComputeFlux(const Vector &state, ElementTransformation &Tr,
|
||||
DenseMatrix &flux) const = 0;
|
||||
/**
|
||||
* @brief Compute normal flux. Optionally overloaded in the
|
||||
* derived class to avoid creating full dense matrix for flux.
|
||||
* @brief Compute normal flux F(u, x)⋅n. Optionally overloaded in a derived
|
||||
* class to avoid creating a full dense matrix for flux.
|
||||
*
|
||||
* @param[in] state state at the current integration point
|
||||
* @param[in] normal normal vector, @see CalcOrtho
|
||||
* @param[in] Tr face information
|
||||
* Used in NumericalFlux for evaluation of the normal flux on a face.
|
||||
* @param[in] state state at the current integration point (num_equations)
|
||||
* @param[in] normal normal vector, see mfem::CalcOrtho() (dim)
|
||||
* @param[in] Tr face transformation
|
||||
* @param[out] fluxDotN normal flux from the given element at the current
|
||||
* integration point
|
||||
* @return real_t maximum (normal) characteristic velocity
|
||||
* integration point (num_equations)
|
||||
* @return real_t maximum (normal) characteristic speed |dF(u,x)/du⋅n|
|
||||
*/
|
||||
virtual real_t ComputeFluxDotN(const Vector &state, const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &fluxDotN) const;
|
||||
|
||||
/**
|
||||
* @brief Compute flux Jacobian. Optionally overloaded in the derived class
|
||||
* when Jacobian is necessary (e.g. Newton iteration, flux limiter)
|
||||
* @brief Compute average flux over the given interval of states.
|
||||
* Optionally overloaded in a derived class.
|
||||
*
|
||||
* @param state state at the current integration point
|
||||
* @param Tr element information
|
||||
* @param J flux Jacobian, J(i,j,d) = dF_{id} / u_j
|
||||
* The average flux is defined as F̄(u1,u2) = ∫ F(u) du / (u2 - u1) for
|
||||
* u ∈ [u1,u2], where u1 is the first state (@a state1) and the u2 the
|
||||
* second state (@a state2), while F(u) is the flux as defined in
|
||||
* ComputeFlux().
|
||||
*
|
||||
* Used in the default implementation of ComputeAvgFluxDotN().
|
||||
* @param[in] state1 state of the beginning of the interval (num_equations)
|
||||
* @param[in] state2 state of the end of the interval (num_equations)
|
||||
* @param[in] Tr element transformation
|
||||
* @param[out] flux_ average flux from the given element at the current
|
||||
* integration point (num_equations, dim)
|
||||
* @return real_t maximum characteristic speed |dF(u,x)/du| over
|
||||
* the interval [u1,u2]
|
||||
*/
|
||||
virtual real_t ComputeAvgFlux(const Vector &state1, const Vector &state2,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &flux_) const
|
||||
{ MFEM_ABORT("Not Implemented."); }
|
||||
|
||||
/**
|
||||
* @brief Compute average normal flux over the given interval of states.
|
||||
* Optionally overloaded in a derived class.
|
||||
*
|
||||
* The average normal flux is defined as F̄(u1,u2)n = ∫ F(u)n du / (u2 - u1)
|
||||
* for u ∈ [u1,u2], where u1 is the first state (@a state1) and the u2 the
|
||||
* second state (@a state2), while n is the normal and F(u) is the flux as
|
||||
* defined in ComputeFlux().
|
||||
*
|
||||
* Used in NumericalFlux::Average() and NumericalFlux::AverageGrad() for
|
||||
* evaluation of the average normal flux on a face.
|
||||
* @param[in] state1 state of the beginning of the interval (num_equations)
|
||||
* @param[in] state2 state of the end of the interval (num_equations)
|
||||
* @param[in] normal normal vector, see mfem::CalcOrtho() (dim)
|
||||
* @param[in] Tr face transformation
|
||||
* @param[out] fluxDotN average normal flux from the given element at the
|
||||
* current integration point (num_equations)
|
||||
* @return real_t maximum (normal) characteristic speed |dF(u,x)/du⋅n|
|
||||
* over the interval [u1,u2]
|
||||
*/
|
||||
virtual real_t ComputeAvgFluxDotN(const Vector &state1, const Vector &state2,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &fluxDotN) const;
|
||||
|
||||
/**
|
||||
* @brief Compute flux Jacobian J(u, x). Optionally overloaded in a derived
|
||||
* class when Jacobian is necessary (e.g. Newton iteration, flux limiter)
|
||||
*
|
||||
* Used in HyperbolicFormIntegrator::AssembleElementGrad() for evaluation of
|
||||
* Jacobian of the flux in an element and in the default implementation of
|
||||
* ComputeFluxJacobianDotN().
|
||||
* @param[in] state state at the current integration point (num_equations)
|
||||
* @param[in] Tr element transformation
|
||||
* @param[out] J_ flux Jacobian, $ J(i,j,d) = dF_{id} / du_j $
|
||||
*/
|
||||
virtual void ComputeFluxJacobian(const Vector &state,
|
||||
ElementTransformation &Tr,
|
||||
DenseTensor &J) const
|
||||
{
|
||||
MFEM_ABORT("Not Implemented.");
|
||||
}
|
||||
DenseTensor &J_) const
|
||||
{ MFEM_ABORT("Not Implemented."); }
|
||||
|
||||
/**
|
||||
* @brief Compute normal flux Jacobian J(u, x)⋅n. Optionally overloaded in
|
||||
* a derived class to avoid creating a full dense tensor for Jacobian.
|
||||
*
|
||||
* Used in NumericalFlux for evaluation of Jacobian of the normal flux on
|
||||
* a face.
|
||||
* @param[in] state state at the current integration point (num_equations)
|
||||
* @param[in] normal normal vector, see mfem::CalcOrtho() (dim)
|
||||
* @param[in] Tr element transformation
|
||||
* @param[out] JDotN normal flux Jacobian, $ JDotN(i,j) = d(F_{id} n_d) / du_j $
|
||||
*/
|
||||
virtual void ComputeFluxJacobianDotN(const Vector &state,
|
||||
const Vector &normal,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &JDotN) const;
|
||||
|
||||
private:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable DenseMatrix flux;
|
||||
mutable DenseTensor J;
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -122,29 +190,99 @@ private:
|
||||
* conservation laws on a face with states, fluxes and characteristic speed
|
||||
*
|
||||
*/
|
||||
class RiemannSolver
|
||||
class NumericalFlux
|
||||
{
|
||||
public:
|
||||
RiemannSolver(const FluxFunction &fluxFunction)
|
||||
/**
|
||||
* @brief Constructor for a flux function
|
||||
* @param fluxFunction flux function F(u,x)
|
||||
*/
|
||||
NumericalFlux(const FluxFunction &fluxFunction)
|
||||
: fluxFunction(fluxFunction) { }
|
||||
|
||||
/**
|
||||
* @brief Evaluates numerical flux for given states and fluxes. Must be
|
||||
* overloaded in a derived class
|
||||
* @brief Evaluates normal numerical flux for the given states and normal.
|
||||
* Must be implemented in a derived class.
|
||||
*
|
||||
* Used in HyperbolicFormIntegrator::AssembleFaceVector() for evaluation of
|
||||
* <F̂(u⁻,u⁺,x) n, [v]> term at the face.
|
||||
* @param[in] state1 state value at a point from the first element
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value at a point from the second element
|
||||
* (num_equations)
|
||||
* @param[in] nor scaled normal vector, see mfem::CalcOrtho() (dim)
|
||||
* @param[in] Tr face information
|
||||
* @param[in] Tr face transformation
|
||||
* @param[out] flux numerical flux (num_equations)
|
||||
* @return real_t maximum characteristic speed |dF(u,x)/du⋅n|
|
||||
*/
|
||||
virtual real_t Eval(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const = 0;
|
||||
|
||||
virtual ~RiemannSolver() = default;
|
||||
/**
|
||||
* @brief Evaluates Jacobian of the normal numerical flux for the given
|
||||
* states and normal. Optionally overloaded in a derived class.
|
||||
*
|
||||
* Used in HyperbolicFormIntegrator::AssembleFaceGrad() for Jacobian
|
||||
* of the term <F̂(u⁻,u⁺,x) n, [v]> at the face.
|
||||
* @param[in] side indicates gradient w.r.t. the first (side = 1)
|
||||
* or second (side = 2) state
|
||||
* @param[in] state1 state value of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor scaled normal vector, see mfem::CalcOrtho() (dim)
|
||||
* @param[in] Tr face transformation
|
||||
* @param[out] grad Jacobian of normal numerical flux (num_equations, dim)
|
||||
*/
|
||||
virtual void Grad(int side, const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const
|
||||
{ MFEM_ABORT("Not implemented."); }
|
||||
|
||||
/**
|
||||
* @brief Evaluates average normal numerical flux over the interval between
|
||||
* the given end states in the second argument and for the given normal.
|
||||
* Optionally overloaded in a derived class.
|
||||
*
|
||||
* Presently, not used. Reserved for future use.
|
||||
* @param[in] state1 state value of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor scaled normal vector, see mfem::CalcOrtho() (dim)
|
||||
* @param[in] Tr face transformation
|
||||
* @param[out] flux numerical flux (num_equations)
|
||||
* @return real_t maximum characteristic speed |dF(u,x)/du⋅n|
|
||||
*/
|
||||
virtual real_t Average(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const
|
||||
{ MFEM_ABORT("Not implemented."); }
|
||||
|
||||
/**
|
||||
* @brief Evaluates Jacobian of the average normal numerical flux over the
|
||||
* interval between the given end states in the second argument and for the
|
||||
* given normal. Optionally overloaded in a derived class.
|
||||
*
|
||||
* Presently, not used. Reserved for future use.
|
||||
* @param[in] side indicates gradient w.r.t. the first (side = 1)
|
||||
* or second (side = 2) state
|
||||
* @param[in] state1 state value of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor scaled normal vector, see mfem::CalcOrtho() (dim)
|
||||
* @param[in] Tr face transformation
|
||||
* @param[out] grad Jacobian of the average normal numerical flux
|
||||
* (num_equations, dim)
|
||||
*/
|
||||
virtual void AverageGrad(int side, const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const
|
||||
{ MFEM_ABORT("Not implemented."); }
|
||||
|
||||
virtual ~NumericalFlux() = default;
|
||||
|
||||
/// @brief Get flux function F
|
||||
/// @return constant reference to the flux function.
|
||||
@@ -154,31 +292,41 @@ protected:
|
||||
const FluxFunction &fluxFunction;
|
||||
};
|
||||
|
||||
/// @deprecated Use NumericalFlux instead.
|
||||
MFEM_DEPRECATED typedef NumericalFlux RiemannSolver;
|
||||
|
||||
/**
|
||||
* @brief Abstract hyperbolic form integrator, (F(u, x), ∇v) and (F̂(u±, x, n))
|
||||
* @brief Abstract hyperbolic form integrator, assembling (F(u, x), ∇v) and
|
||||
* <F̂(u⁻,u⁺,x) n, [v]> terms for scalar finite elements.
|
||||
*
|
||||
* This form integrator is coupled with a NumericalFlux that implements the
|
||||
* numerical flux F̂ at the faces. The flux F is obtained from the FluxFunction
|
||||
* assigned to the aforementioned NumericalFlux.
|
||||
*/
|
||||
class HyperbolicFormIntegrator : public NonlinearFormIntegrator
|
||||
{
|
||||
private:
|
||||
// The maximum characteristic speed, updated during element/face vector assembly
|
||||
real_t max_char_speed;
|
||||
const RiemannSolver &rsolver; // Numerical flux that maps F(u±,x) to hat(F)
|
||||
const NumericalFlux &numFlux; // Numerical flux that maps F(u±,x) to F̂
|
||||
const FluxFunction &fluxFunction;
|
||||
const int IntOrderOffset; // integration order offset, 2*p + IntOrderOffset.
|
||||
const real_t sign;
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
// Local storage for element integration
|
||||
Vector shape; // shape function value at an integration point
|
||||
Vector state; // state value at an integration point
|
||||
DenseMatrix flux; // flux value at an integration point
|
||||
DenseTensor J; // Jacobian matrix at an integration point
|
||||
DenseMatrix dshape; // derivative of shape function at an integration point
|
||||
|
||||
Vector shape1; // shape function value at an integration point - first elem
|
||||
Vector shape2; // shape function value at an integration point - second elem
|
||||
Vector state1; // state value at an integration point - first elem
|
||||
Vector state2; // state value at an integration point - second elem
|
||||
Vector nor; // normal vector, @see CalcOrtho
|
||||
Vector fluxN; // hat(F)(u,x)
|
||||
Vector nor; // normal vector, see mfem::CalcOrtho()
|
||||
Vector fluxN; // F̂(u±,x) n
|
||||
DenseMatrix JDotN; // Ĵ(u±,x) n
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -186,12 +334,14 @@ public:
|
||||
/**
|
||||
* @brief Construct a new Hyperbolic Form Integrator object
|
||||
*
|
||||
* @param[in] rsolver numerical flux
|
||||
* @param[in] numFlux numerical flux
|
||||
* @param[in] IntOrderOffset integration order offset
|
||||
* @param[in] sign sign of the convection term
|
||||
*/
|
||||
HyperbolicFormIntegrator(
|
||||
const RiemannSolver &rsolver,
|
||||
const int IntOrderOffset=0);
|
||||
const NumericalFlux &numFlux,
|
||||
const int IntOrderOffset = 0,
|
||||
const real_t sign = 1.);
|
||||
|
||||
/**
|
||||
* @brief Reset the Max Char Speed 0
|
||||
@@ -210,7 +360,8 @@ public:
|
||||
const FluxFunction &GetFluxFunction() { return fluxFunction; }
|
||||
|
||||
/**
|
||||
* @brief implement (F(u), grad v) with abstract F computed by ComputeFlux
|
||||
* @brief Implements (F(u), ∇v) with abstract F computed by
|
||||
* FluxFunction::ComputeFlux()
|
||||
*
|
||||
* @param[in] el local finite element
|
||||
* @param[in] Tr element transformation
|
||||
@@ -222,62 +373,270 @@ public:
|
||||
const Vector &elfun, Vector &elvect) override;
|
||||
|
||||
/**
|
||||
* @brief implement <-hat(F)(u,x) n, [[v]]> with abstract hat(F) computed by
|
||||
* ComputeFluxDotN and numerical flux object
|
||||
* @brief Implements (J(u), ∇v) with abstract J computed by
|
||||
* FluxFunction::ComputeFluxJacobian()
|
||||
*
|
||||
* @param[in] el local finite element
|
||||
* @param[in] Tr element transformation
|
||||
* @param[in] elfun local coefficient of basis
|
||||
* @param[out] grad evaluated Jacobian
|
||||
*/
|
||||
void AssembleElementGrad(const FiniteElement &el,
|
||||
ElementTransformation &Tr,
|
||||
const Vector &elfun, DenseMatrix &grad) override;
|
||||
|
||||
/**
|
||||
* @brief Implements <-F̂(u⁻,u⁺,x) n, [v]> with abstract F̂ computed by
|
||||
* NumericalFlux::Eval() of the numerical flux object
|
||||
*
|
||||
* @param[in] el1 finite element of the first element
|
||||
* @param[in] el2 finite element of the second element
|
||||
* @param[in] Tr face element transformations
|
||||
* @param[in] elfun local coefficient of basis from both elements
|
||||
* @param[out] elvect evaluated dual vector <-hat(F)(u,x) n, [[v]]>
|
||||
* @param[out] elvect evaluated dual vector <-F̂(u⁻,u⁺,x) n, [v]>
|
||||
*/
|
||||
void AssembleFaceVector(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
FaceElementTransformations &Tr,
|
||||
const Vector &elfun, Vector &elvect) override;
|
||||
|
||||
/**
|
||||
* @brief Implements <-Ĵ(u⁻,u⁺,x) n, [v]> with abstract Ĵ computed by
|
||||
* NumericalFlux::Grad() of the numerical flux object
|
||||
*
|
||||
* @param[in] el1 finite element of the first element
|
||||
* @param[in] el2 finite element of the second element
|
||||
* @param[in] Tr face element transformations
|
||||
* @param[in] elfun local coefficient of basis from both elements
|
||||
* @param[out] elmat evaluated Jacobian matrix <-Ĵ(u⁻,u⁺,x) n, [v]>
|
||||
*/
|
||||
void AssembleFaceGrad(const FiniteElement &el1,
|
||||
const FiniteElement &el2,
|
||||
FaceElementTransformations &Tr,
|
||||
const Vector &elfun, DenseMatrix &elmat) override;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Rusanov flux, also known as local Lax-Friedrichs,
|
||||
* F̂ n = ½(F(u⁺,x)n + F(u⁻,x)n) - ½λ(u⁺ - u⁻)
|
||||
* where λ is the maximum characteristic velocity
|
||||
*
|
||||
* where λ is the maximum characteristic speed.
|
||||
* @note The implementation assumes monotonous |dF(u,x)/du⋅n| in u, so the
|
||||
* maximum characteristic speed λ for any interval [u⁻, u⁺] is given by
|
||||
* max(|dF(u⁺,x)/du⁺⋅n|, |dF(u⁻,x)/du⁻⋅n|).
|
||||
*/
|
||||
class RusanovFlux : public RiemannSolver
|
||||
class RusanovFlux : public NumericalFlux
|
||||
{
|
||||
public:
|
||||
RusanovFlux(const FluxFunction &fluxFunction)
|
||||
: RiemannSolver(fluxFunction)
|
||||
{
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
fluxN1.SetSize(fluxFunction.num_equations);
|
||||
fluxN2.SetSize(fluxFunction.num_equations);
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* @brief Constructor for a flux function
|
||||
* @param fluxFunction flux function F(u,x)
|
||||
*/
|
||||
RusanovFlux(const FluxFunction &fluxFunction);
|
||||
|
||||
/**
|
||||
* @brief hat(F)n = ½(F(u⁺,x)n + F(u⁻,x)n) - ½λ(u⁺ - u⁻)
|
||||
* @brief Normal numerical flux F̂(u⁻,u⁺,x) n
|
||||
* @note Systems of equations are treated component-wise
|
||||
*
|
||||
* @param[in] state1 state value at a point from the first element
|
||||
* @param[in] state1 state value (u⁻) at a point from the first element
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value at a point from the second element
|
||||
* @param[in] state2 state value (u⁺) at a point from the second element
|
||||
* (num_equations)
|
||||
* @param[in] nor normal vector (not a unit vector) (dim)
|
||||
* @param[in] Tr face element transformation
|
||||
* @param[out] flux ½(F(u⁺,x)n + F(u⁻,x)n) - ½λ(u⁺ - u⁻)
|
||||
* @param[out] flux F̂ n = ½(F(u⁺,x)n + F(u⁻,x)n) - ½λ(u⁺ - u⁻)
|
||||
* @return max(|dF(u⁺,x)/du⁺⋅n|, |dF(u⁻,x)/du⁻⋅n|)
|
||||
*/
|
||||
real_t Eval(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const override;
|
||||
|
||||
/**
|
||||
* @brief Jacobian of normal numerical flux F̂(u⁻,u⁺,x) n
|
||||
* @note The Jacobian of flux J n is required to be implemented in
|
||||
* FluxFunction::ComputeFluxJacobianDotN()
|
||||
*
|
||||
* @param[in] side gradient w.r.t the first (u⁻) or second argument (u⁺)
|
||||
* @param[in] state1 state value (u⁻) of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value (u⁺) of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor normal vector (not a unit vector) (dim)
|
||||
* @param[in] Tr face element transformation
|
||||
* @param[out] grad Jacobian of F(u⁻,u⁺,x) n
|
||||
* side = 1:
|
||||
* ½J(u⁻,x)n + ½λ
|
||||
* side = 2:
|
||||
* ½J(u⁺,x)n - ½λ
|
||||
*/
|
||||
void Grad(int side, const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const override;
|
||||
|
||||
/**
|
||||
* @brief Average normal numerical flux over the interval [u⁻, u⁺] in the
|
||||
* second argument of the flux F̂(u⁻,u,x) n
|
||||
* @note The average normal flux F̄ n is required to be implemented in
|
||||
* FluxFunction::ComputeAvgFluxDotN()
|
||||
* @note Systems of equations are treated component-wise
|
||||
*
|
||||
* @param[in] state1 state value (u⁻) of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value (u⁺) of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor normal vector (not a unit vector) (dim)
|
||||
* @param[in] Tr face element transformation
|
||||
* @param[out] flux ½(F̄(u⁻,u⁺,x)n + F(u⁻,x)n) - ¼λ(u⁺ - u⁻)
|
||||
* @return max(|dF(u⁺,x)/du⁺⋅n|, |dF(u⁻,x)/du⁻⋅n|)
|
||||
*/
|
||||
real_t Average(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const override;
|
||||
|
||||
/**
|
||||
* @brief Jacobian of average normal numerical flux over the interval
|
||||
* [u⁻, u⁺] in the second argument of the flux F̂(u⁻,u,x) n
|
||||
* @note The average normal flux F̄ n is required to be implemented in
|
||||
* FluxFunction::ComputeAvgFluxDotN() and the Jacobian of flux J n in
|
||||
* FluxFunction::ComputeFluxJacobianDotN()
|
||||
* @note Only the diagonal terms of the J n are considered, i.e., systems
|
||||
* are treated as a set of independent equations
|
||||
*
|
||||
* @param[in] side gradient w.r.t the first (u⁻) or second argument (u⁺)
|
||||
* @param[in] state1 state value (u⁻) of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value (u⁺) of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor normal vector (not a unit vector) (dim)
|
||||
* @param[in] Tr face element transformation
|
||||
* @param[out] grad Jacobian of F̄(u⁻,u⁺,x) n
|
||||
* side = 1:
|
||||
* ½(F̄(u⁻,u⁺,x)n - F(u⁻,x)n) / (u⁺ - u⁻) - ½J(u⁻,x)n + ¼λ
|
||||
* side = 2:
|
||||
* ½(F(u⁺,x)n - F̄(u⁻,u⁺,x)n) / (u⁺ - u⁻) - ¼λ
|
||||
*/
|
||||
void AverageGrad(int side, const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const override;
|
||||
|
||||
protected:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector fluxN1, fluxN2;
|
||||
mutable DenseMatrix JDotN;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Component-wise upwinded flux
|
||||
*
|
||||
* Upwinded flux for scalar equations, a special case of Godunov or
|
||||
* Engquist-Osher flux, is defined as follows:
|
||||
* F̂ n = F(u⁺)n for dF(u)/du < 0 on [u⁻,u⁺]
|
||||
* F̂ n = F(u⁻)n for dF(u)/du > 0 on [u⁻,u⁺]
|
||||
* @note This construction assumes monotonous F(u,x) in u
|
||||
* @note Systems of equations are treated component-wise
|
||||
*/
|
||||
class ComponentwiseUpwindFlux : public NumericalFlux
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for a flux function
|
||||
* @param fluxFunction flux function F(u,x)
|
||||
*/
|
||||
ComponentwiseUpwindFlux(const FluxFunction &fluxFunction);
|
||||
|
||||
/**
|
||||
* @brief Normal numerical flux F̂(u⁻,u⁺,x) n
|
||||
*
|
||||
* @param[in] state1 state value (u⁻) at a point from the first element
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value (u⁺) at a point from the second element
|
||||
* (num_equations)
|
||||
* @param[in] nor normal vector (not a unit vector) (dim)
|
||||
* @param[in] Tr face element transformation
|
||||
* @param[out] flux F̂ n = min(F(u⁻,x)n, F(u⁺,x)n) for u⁻ ≤ u⁺
|
||||
* or F̂ n = max(F(u⁻,x)n, F(u⁺,x)n) for u⁻ > u⁺
|
||||
* @return max(|dF(u⁺,x)/du⁺⋅n|, |dF(u⁻,x)/du⁻⋅n|)
|
||||
*/
|
||||
real_t Eval(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const override;
|
||||
|
||||
/**
|
||||
* @brief Jacobian of normal numerical flux F̂(u⁻,u⁺,x) n
|
||||
* @note The Jacobian of flux J n is required to be implemented in
|
||||
* FluxFunction::ComputeFluxJacobianDotN()
|
||||
*
|
||||
* @param[in] side gradient w.r.t the first (u⁻) or second argument (u⁺)
|
||||
* @param[in] state1 state value (u⁻) of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value (u⁺) of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor normal vector (not a unit vector) (dim)
|
||||
* @param[in] Tr face element transformation
|
||||
* @param[out] grad Jacobian of F(u⁻,u⁺,x) n
|
||||
* side = 1:
|
||||
* max(J(u⁻,x)n, 0)
|
||||
* side = 2:
|
||||
* min(J(u⁺,x)n, 0)
|
||||
*/
|
||||
void Grad(int side, const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const override;
|
||||
|
||||
/**
|
||||
* @brief Average normal numerical flux over the interval [u⁻, u⁺] in the
|
||||
* second argument of the flux F̂(u⁻,u,x) n
|
||||
* @note The average normal flux F̄ n is required to be implemented in
|
||||
* FluxFunction::ComputeAvgFluxDotN()
|
||||
*
|
||||
* @param[in] state1 state value (u⁻) of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value (u⁺) of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor normal vector (not a unit vector) (dim)
|
||||
* @param[in] Tr face element transformation
|
||||
* @param[out] flux F̂ n = min(F(u⁻)n, F̄(u⁺,x)n) for u⁻ ≤ u⁺
|
||||
* or F̂ n = max(F(u⁻)n, F̄(u⁺,x)n) for u⁻ > u⁺
|
||||
* @return max(|dF(u⁺,x)/du⁺⋅n|, |dF(u⁻,x)/du⁻⋅n|)
|
||||
*/
|
||||
real_t Average(const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
Vector &flux) const override;
|
||||
|
||||
/**
|
||||
* @brief Jacobian of average normal numerical flux over the interval
|
||||
* [u⁻, u⁺] in the second argument of the flux F̂(u⁻,u,x) n
|
||||
* @note The average normal flux F̄ n is required to be implemented in
|
||||
* FluxFunction::ComputeAvgFluxDotN() and the Jacobian of flux J n in
|
||||
* FluxFunction::ComputeFluxJacobianDotN()
|
||||
*
|
||||
* @param[in] side gradient w.r.t the first (u⁻) or second argument (u⁺)
|
||||
* @param[in] state1 state value (u⁻) of the beginning of the interval
|
||||
* (num_equations)
|
||||
* @param[in] state2 state value (u⁺) of the end of the interval
|
||||
* (num_equations)
|
||||
* @param[in] nor normal vector (not a unit vector) (dim)
|
||||
* @param[in] Tr face element transformation
|
||||
* @param[out] grad Jacobian of F̄(u⁻,u⁺,x) n
|
||||
* side = 1:
|
||||
* (F(u⁺) - F̄(u⁻,u⁺))n / (u⁺ - u⁻) when negative
|
||||
* J(u⁻,x) n otherwise
|
||||
* side = 2:
|
||||
* min((F(u⁺) - F̄(u⁻,u⁺))n / (u⁺ - u⁻), 0)
|
||||
*/
|
||||
void AverageGrad(int side, const Vector &state1, const Vector &state2,
|
||||
const Vector &nor, FaceElementTransformations &Tr,
|
||||
DenseMatrix &grad) const override;
|
||||
|
||||
protected:
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
mutable Vector fluxN1, fluxN2;
|
||||
mutable DenseMatrix JDotN;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Advection flux
|
||||
class AdvectionFlux : public FluxFunction
|
||||
{
|
||||
private:
|
||||
@@ -289,8 +648,7 @@ private:
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief Construct a new Advection Flux Function with given
|
||||
* spatial dimension
|
||||
* @brief Construct AdvectionFlux FluxFunction with given velocity
|
||||
*
|
||||
* @param b velocity coefficient, possibly depends on space
|
||||
*/
|
||||
@@ -306,20 +664,83 @@ public:
|
||||
* @brief Compute F(u)
|
||||
*
|
||||
* @param state state (u) at current integration point
|
||||
* @param Tr current element transformation with integration point
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param flux F(u) = ubᵀ
|
||||
* @return real_t maximum characteristic speed, |b|
|
||||
*/
|
||||
real_t ComputeFlux(const Vector &state, ElementTransformation &Tr,
|
||||
DenseMatrix &flux) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute F(u) n
|
||||
*
|
||||
* @param state state (u) at current integration point
|
||||
* @param normal normal vector, usually not a unit vector
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param fluxDotN F(u) n = u (bᵀn)
|
||||
* @return real_t maximum characteristic speed, |b|
|
||||
*/
|
||||
real_t ComputeFluxDotN(const Vector &state,
|
||||
const Vector &normal, FaceElementTransformations &Tr,
|
||||
Vector &fluxDotN) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute average flux F̄(u)
|
||||
*
|
||||
* @param state1 state value (u⁻) of the beginning of the interval
|
||||
* @param state2 state value (u⁺) of the end of the interval
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param flux F̄(u) = (u⁻+u⁺)/2*bᵀ
|
||||
* @return real_t maximum characteristic speed, |b|
|
||||
*/
|
||||
real_t ComputeAvgFlux(const Vector &state1, const Vector &state2,
|
||||
ElementTransformation &Tr, DenseMatrix &flux) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute average flux F̄(u) n
|
||||
*
|
||||
* @param state1 state value (u⁻) of the beginning of the interval
|
||||
* @param state2 state value (u⁺) of the end of the interval
|
||||
* @param normal normal vector, usually not a unit vector
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param fluxDotN F̄(u) n = (u⁻+u⁺)/2*(bᵀn)
|
||||
* @return real_t maximum characteristic speed, |b|
|
||||
*/
|
||||
real_t ComputeAvgFluxDotN(const Vector &state1, const Vector &state2,
|
||||
const Vector &normal, FaceElementTransformations &Tr,
|
||||
Vector &fluxDotN) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute J(u)
|
||||
*
|
||||
* @param state state (u) at current integration point
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param J J(u) = diag(b)
|
||||
*/
|
||||
void ComputeFluxJacobian(const Vector &state,
|
||||
ElementTransformation &Tr,
|
||||
DenseTensor &J) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute J(u) n
|
||||
*
|
||||
* @param state state (u) at current integration point
|
||||
* @param normal normal vector, usually not a unit vector
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param JDotN J(u) n = bᵀn
|
||||
*/
|
||||
void ComputeFluxJacobianDotN(const Vector &state,
|
||||
const Vector &normal,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &JDotN) const override;
|
||||
};
|
||||
|
||||
/// Burgers flux
|
||||
class BurgersFlux : public FluxFunction
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Burgers Flux Function with given
|
||||
* spatial dimension
|
||||
* @brief Construct BurgersFlux FluxFunction with given spatial dimension
|
||||
*
|
||||
* @param dim spatial dimension
|
||||
*/
|
||||
@@ -330,14 +751,83 @@ public:
|
||||
* @brief Compute F(u)
|
||||
*
|
||||
* @param state state (u) at current integration point
|
||||
* @param Tr current element transformation with integration point
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param flux F(u) = ½u²*1ᵀ where 1 is (dim) vector
|
||||
* @return real_t maximum characteristic speed, |u|
|
||||
*/
|
||||
real_t ComputeFlux(const Vector &state, ElementTransformation &Tr,
|
||||
DenseMatrix &flux) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute F(u) n
|
||||
*
|
||||
* @param state state (u) at current integration point
|
||||
* @param normal normal vector, usually not a unit vector
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param fluxDotN F(u) n = ½u²*(1ᵀn) where 1 is (dim) vector
|
||||
* @return real_t maximum characteristic speed, |u|
|
||||
*/
|
||||
real_t ComputeFluxDotN(const Vector &state,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &fluxDotN) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute average flux F̄(u)
|
||||
*
|
||||
* @param state1 state value (u⁻) of the beginning of the interval
|
||||
* @param state2 state value (u⁺) of the end of the interval
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param flux F̄(u) = (u⁻²+u⁻*u⁺+u⁺²)/6*1ᵀ where 1 is (dim) vector
|
||||
* @return real_t maximum characteristic speed, |u|
|
||||
*/
|
||||
real_t ComputeAvgFlux(const Vector &state1,
|
||||
const Vector &state2,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &flux) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute average flux F̄(u) n
|
||||
*
|
||||
* @param state1 state value (u⁻) of the beginning of the interval
|
||||
* @param state2 state value (u⁺) of the end of the interval
|
||||
* @param normal normal vector, usually not a unit vector
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param fluxDotN F̄(u) n = (u⁻²+u⁻*u⁺+u⁺²)/6*(1ᵀn) where 1 is (dim) vector
|
||||
* @return real_t maximum characteristic speed, |u|
|
||||
*/
|
||||
real_t ComputeAvgFluxDotN(const Vector &state1,
|
||||
const Vector &state2,
|
||||
const Vector &normal,
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &fluxDotN) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute J(u)
|
||||
*
|
||||
* @param state state (u) at current integration point
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param J J(u) = diag(u*1) where 1 is (dim) vector
|
||||
*/
|
||||
void ComputeFluxJacobian(const Vector &state,
|
||||
ElementTransformation &Tr,
|
||||
DenseTensor &J) const override;
|
||||
|
||||
/**
|
||||
* @brief Compute J(u) n
|
||||
*
|
||||
* @param state state (u) at current integration point
|
||||
* @param normal normal vector, usually not a unit vector
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param JDotN J(u) n = u*(1ᵀn) where 1 is (dim) vector
|
||||
*/
|
||||
void ComputeFluxJacobianDotN(const Vector &state,
|
||||
const Vector &normal,
|
||||
ElementTransformation &Tr,
|
||||
DenseMatrix &JDotN) const override;
|
||||
};
|
||||
|
||||
/// Shallow water flux
|
||||
class ShallowWaterFlux : public FluxFunction
|
||||
{
|
||||
private:
|
||||
@@ -345,8 +835,8 @@ private:
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Shallow Water Flux Function with
|
||||
* given spatial dimension
|
||||
* @brief Construct a new ShallowWaterFlux FluxFunction with given spatial
|
||||
* dimension and gravity constant
|
||||
*
|
||||
* @param dim spatial dimension
|
||||
* @param g gravity constant
|
||||
@@ -358,7 +848,7 @@ public:
|
||||
* @brief Compute F(h, hu)
|
||||
*
|
||||
* @param state state (h, hu) at current integration point
|
||||
* @param Tr current element transformation with integration point
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param flux F(h, hu) = [huᵀ; huuᵀ + ½gh²I]
|
||||
* @return real_t maximum characteristic speed, |u| + √(gh)
|
||||
*/
|
||||
@@ -370,7 +860,7 @@ public:
|
||||
*
|
||||
* @param state state (h, hu) at current integration point
|
||||
* @param normal normal vector, usually not a unit vector
|
||||
* @param Tr current element transformation with integration point
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param fluxN F(ρ, ρu, E)n = [ρu⋅n; ρu(u⋅n) + pn; (u⋅n)(E + p)]
|
||||
* @return real_t maximum characteristic speed, |u| + √(γp/ρ)
|
||||
*/
|
||||
@@ -379,6 +869,7 @@ public:
|
||||
Vector &fluxN) const override;
|
||||
};
|
||||
|
||||
/// Euler flux
|
||||
class EulerFlux : public FluxFunction
|
||||
{
|
||||
private:
|
||||
@@ -387,8 +878,8 @@ private:
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Euler Flux Function with given
|
||||
* spatial dimension
|
||||
* @brief Construct a new EulerFlux FluxFunction with given spatial
|
||||
* dimension and specific heat ratio
|
||||
*
|
||||
* @param dim spatial dimension
|
||||
* @param specific_heat_ratio specific heat ratio, γ
|
||||
@@ -401,7 +892,7 @@ public:
|
||||
* @brief Compute F(ρ, ρu, E)
|
||||
*
|
||||
* @param state state (ρ, ρu, E) at current integration point
|
||||
* @param Tr current element transformation with integration point
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param flux F(ρ, ρu, E) = [ρuᵀ; ρuuᵀ + pI; uᵀ(E + p)]
|
||||
* @return real_t maximum characteristic speed, |u| + √(γp/ρ)
|
||||
*/
|
||||
@@ -413,7 +904,7 @@ public:
|
||||
*
|
||||
* @param x x (ρ, ρu, E) at current integration point
|
||||
* @param normal normal vector, usually not a unit vector
|
||||
* @param Tr current element transformation with integration point
|
||||
* @param Tr current element transformation with the integration point
|
||||
* @param fluxN F(ρ, ρu, E)n = [ρu⋅n; ρu(u⋅n) + pn; (u⋅n)(E + p)]
|
||||
* @return real_t maximum characteristic speed, |u| + √(γp/ρ)
|
||||
*/
|
||||
|
||||
@@ -21,8 +21,8 @@ void ConvectionIntegrator::AssembleMF(const FiniteElementSpace &fes)
|
||||
// Assuming the same element type
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation &Trans = *fes.GetElementTransformation(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
ElementTransformation &Trans = *mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, Trans);
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
|
||||
@@ -138,8 +138,8 @@ void ConvectionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
Device::GetDeviceMemoryType() : pa_mt;
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation &Trans = *fes.GetElementTransformation(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
ElementTransformation &Trans = *mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, Trans);
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fel = fes.GetFE(0);
|
||||
const FiniteElement *fel = fes.GetTypicalFE();
|
||||
|
||||
const VectorTensorFiniteElement *el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(fel);
|
||||
@@ -27,7 +27,7 @@ void CurlCurlIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(*el, *el,
|
||||
*mesh->GetElementTransformation(0));
|
||||
*mesh->GetTypicalElementTransformation());
|
||||
|
||||
const int dims = el->GetDim();
|
||||
MFEM_VERIFY(dims == 2 || dims == 3, "");
|
||||
|
||||
@@ -456,18 +456,16 @@ void DGDiffusionIntegrator::SetupPA(const FiniteElementSpace &fes,
|
||||
|
||||
// Assumes tensor-product elements
|
||||
Mesh &mesh = *fes.GetMesh();
|
||||
const FiniteElement &el =
|
||||
*fes.GetTraceElement(0, mesh.GetFaceGeometry(0));
|
||||
FaceElementTransformations &T0 =
|
||||
*fes.GetMesh()->GetFaceElementTransformations(0);
|
||||
const Geometry::Type face_geom_type = mesh.GetTypicalFaceGeometry();
|
||||
const FiniteElement &el = *fes.GetTypicalTraceElement();
|
||||
const int ir_order = IntRule ? IntRule->GetOrder()
|
||||
: GetRule(el.GetOrder(), T0).GetOrder();
|
||||
const IntegrationRule &ir = irs.Get(T0.GetGeometryType(), ir_order);
|
||||
: GetRule(el.GetOrder(), face_geom_type).GetOrder();
|
||||
const IntegrationRule &ir = irs.Get(face_geom_type, ir_order);
|
||||
dim = mesh.Dimension();
|
||||
const int q1d = (ir.GetOrder() + 3)/2;
|
||||
MFEM_ASSERT(q1d == pow(real_t(ir.Size()), 1.0/(dim - 1)), "");
|
||||
|
||||
const auto vol_ir = irs.Get(mesh.GetElementGeometry(0), ir_order);
|
||||
const auto vol_ir = irs.Get(mesh.GetTypicalElementGeometry(), ir_order);
|
||||
const auto geom_flags = GeometricFactors::JACOBIANS |
|
||||
GeometricFactors::DETERMINANTS;
|
||||
const auto el_geom = mesh.GetGeometricFactors(vol_ir, geom_flags, mt);
|
||||
|
||||
@@ -143,13 +143,11 @@ void DGTraceIntegrator::SetupPA(const FiniteElementSpace &fes, FaceType type)
|
||||
if (nf==0) { return; }
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement &el =
|
||||
*fes.GetTraceElement(0, fes.GetMesh()->GetFaceGeometry(0));
|
||||
FaceElementTransformations &T0 =
|
||||
*fes.GetMesh()->GetFaceElementTransformations(0);
|
||||
const FiniteElement &el = *fes.GetTypicalTraceElement();
|
||||
const IntegrationRule *ir = IntRule?
|
||||
IntRule:
|
||||
&GetRule(el.GetGeomType(), el.GetOrder(), T0);
|
||||
&GetRule(el.GetGeomType(), el.GetOrder(),
|
||||
*mesh->GetTypicalElementTransformation());
|
||||
const int symmDims = 4;
|
||||
nq = ir->GetNPoints();
|
||||
dim = mesh->Dimension();
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace mfem
|
||||
|
||||
// PA Diffusion Integrator
|
||||
|
||||
DiffusionIntegrator::Kernels DiffusionIntegrator::kernels;
|
||||
DiffusionIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
|
||||
@@ -21,8 +21,7 @@ void DiffusionIntegrator::AssembleMF(const FiniteElementSpace &fes)
|
||||
// Assuming the same element type
|
||||
fespace = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
|
||||
@@ -93,8 +93,7 @@ void DiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
// Assuming the same element type
|
||||
fespace = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el);
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
|
||||
@@ -1039,7 +1039,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
|
||||
for (int zquad = 0; zquad<2; ++zquad)
|
||||
{
|
||||
// Reduced quadrature in z
|
||||
const int nwz = rid(zquad,2,patch)[jdz].size();
|
||||
const int nwz = static_cast<int>(rid(zquad,2,patch)[jdz].size());
|
||||
for (int irz=0; irz < nwz; ++irz)
|
||||
{
|
||||
const int qz = rid(zquad,2,patch)[jdz][irz] + minD[2][jdz];
|
||||
@@ -1062,7 +1062,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
|
||||
for (int yquad = 0; yquad<2; ++yquad)
|
||||
{
|
||||
// Reduced quadrature in y
|
||||
const int nwy = rid(yquad,1,patch)[jdy].size();
|
||||
const int nwy = static_cast<int>(rid(yquad,1,patch)[jdy].size());
|
||||
for (int iry=0; iry < nwy; ++iry)
|
||||
{
|
||||
const int qy = rid(yquad,1,patch)[jdy][iry] + minD[1][jdy];
|
||||
@@ -1082,7 +1082,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
|
||||
// Reduced quadrature in x
|
||||
for (int xquad=0; xquad<2; ++xquad)
|
||||
{
|
||||
const int nwx = rid(xquad,0,patch)[jdx].size();
|
||||
const int nwx = static_cast<int>(rid(xquad,0,patch)[jdx].size());
|
||||
for (int irx=0; irx < nwx; ++irx)
|
||||
{
|
||||
const int qx = rid(xquad,0,patch)[jdx][irx] + minD[0][jdx];
|
||||
@@ -1117,7 +1117,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
|
||||
}
|
||||
|
||||
// 00 terms
|
||||
const int nw = rid(0,0,patch)[jdx].size();
|
||||
const int nw = static_cast<int>(rid(0,0,patch)[jdx].size());
|
||||
for (int irx=0; irx < nw; ++irx)
|
||||
{
|
||||
const int qx = rid(0,0,patch)[jdx][irx] + minD[0][jdx];
|
||||
@@ -1140,7 +1140,7 @@ void DiffusionIntegrator::AssemblePatchMatrix_reducedQuadrature(
|
||||
}
|
||||
|
||||
// 11 terms
|
||||
const int nw11 = rid(1,0,patch)[jdx].size();
|
||||
const int nw11 = static_cast<int>(rid(1,0,patch)[jdx].size());
|
||||
|
||||
for (int irx=0; irx < nw11; ++irx)
|
||||
{
|
||||
|
||||
@@ -21,14 +21,14 @@ void DivDivIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement *fel = fes.GetFE(0);
|
||||
const FiniteElement *fel = fes.GetTypicalFE();
|
||||
|
||||
const VectorTensorFiniteElement *el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(fel);
|
||||
MFEM_VERIFY(el != NULL, "Only VectorTensorFiniteElement is supported!");
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &MassIntegrator::GetRule
|
||||
(*el, *el, *mesh->GetElementTransformation(0));
|
||||
(*el, *el, *mesh->GetTypicalElementTransformation());
|
||||
|
||||
const int dims = el->GetDim();
|
||||
MFEM_VERIFY(dims == 2 || dims == 3, "");
|
||||
|
||||
@@ -23,8 +23,8 @@ void ElasticityIntegrator::SetUpQuadratureSpaceAndCoefficients(
|
||||
if (IntRule == nullptr)
|
||||
{
|
||||
// This is where it's assumed that all elements are the same.
|
||||
const auto &T = *fes.GetElementTransformation(0);
|
||||
int quad_order = 2 * T.OrderGrad(fes.GetFE(0));
|
||||
const auto &T = *fes.GetMesh()->GetTypicalElementTransformation();
|
||||
int quad_order = 2 * T.OrderGrad(fes.GetTypicalFE());
|
||||
IntRule = &IntRules.Get(T.GetGeometryType(), quad_order);
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ void ElasticityIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
Mesh &mesh = *fespace->GetMesh();
|
||||
MFEM_VERIFY(fespace->GetVDim() == mesh.Dimension(), "");
|
||||
vdim = fespace->GetVDim();
|
||||
ndofs = fespace->GetFE(0)->GetDof();
|
||||
ndofs = fespace->GetTypicalFE()->GetDof();
|
||||
|
||||
SetUpQuadratureSpaceAndCoefficients(fes);
|
||||
|
||||
auto ordering = GetEVectorOrdering(*fespace);
|
||||
auto mode = ordering == ElementDofOrdering::NATIVE ? DofToQuad::FULL :
|
||||
DofToQuad::LEXICOGRAPHIC_FULL;
|
||||
maps = &fespace->GetFE(0)->GetDofToQuad(*IntRule, mode);
|
||||
maps = &fespace->GetTypicalFE()->GetDofToQuad(*IntRule, mode);
|
||||
geom = mesh.GetGeometricFactors(*IntRule, GeometricFactors::JACOBIANS);
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ void ElasticityComponentIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
DofToQuad::LEXICOGRAPHIC_FULL;
|
||||
geom = fes.GetMesh()->GetGeometricFactors(*IntRule,
|
||||
GeometricFactors::JACOBIANS);
|
||||
maps = &fespace->GetFE(0)->GetDofToQuad(*IntRule, mode);
|
||||
maps = &fespace->GetTypicalFE()->GetDofToQuad(*IntRule, mode);
|
||||
}
|
||||
|
||||
void ElasticityComponentIntegrator::AddMultPA(const Vector &x, Vector &y) const
|
||||
|
||||
@@ -202,9 +202,9 @@ void GradientIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
"PA Only supports Ordering::byNODES!");
|
||||
// Assuming the same element type
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement &trial_fe = *trial_fes.GetFE(0); // H1
|
||||
const FiniteElement &test_fe = *test_fes.GetFE(0); // H1^d or L2^d
|
||||
ElementTransformation *trans = mesh->GetElementTransformation(0);
|
||||
const FiniteElement &trial_fe = *trial_fes.GetTypicalFE(); // H1
|
||||
const FiniteElement &test_fe = *test_fes.GetTypicalFE(); // H1^d or L2^d
|
||||
ElementTransformation *trans = mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
|
||||
*trans);
|
||||
const int dims = trial_fe.GetDim();
|
||||
|
||||
@@ -1033,8 +1033,8 @@ void GradientInterpolator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
{
|
||||
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement *trial_fel = trial_fes.GetFE(0);
|
||||
const FiniteElement *test_fel = test_fes.GetFE(0);
|
||||
const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
|
||||
const FiniteElement *test_fel = test_fes.GetTypicalFE();
|
||||
|
||||
const NodalTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
|
||||
@@ -1800,8 +1800,8 @@ void IdentityInterpolator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
{
|
||||
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement *trial_fel = trial_fes.GetFE(0);
|
||||
const FiniteElement *test_fel = test_fes.GetFE(0);
|
||||
const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
|
||||
const FiniteElement *test_fel = test_fes.GetTypicalFE();
|
||||
|
||||
const NodalTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
MassIntegrator::Kernels MassIntegrator::kernels;
|
||||
MassIntegrator::Kernels::Kernels()
|
||||
{
|
||||
// 2D
|
||||
|
||||
@@ -21,9 +21,8 @@ void MassIntegrator::AssembleMF(const FiniteElementSpace &fes)
|
||||
// Assuming the same element type
|
||||
fespace = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation *T = mesh->GetElementTransformation(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
ElementTransformation *T = mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T);
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
|
||||
@@ -29,9 +29,8 @@ void MassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
// Assuming the same element type
|
||||
fespace = &fes;
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation *T0 = mesh->GetElementTransformation(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
ElementTransformation *T0 = mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, el, *T0);
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
|
||||
@@ -23,8 +23,8 @@ void MixedScalarCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement *fel = trial_fes.GetFE(0); // In H(curl)
|
||||
const FiniteElement *eltest = test_fes.GetFE(0); // In scalar space
|
||||
const FiniteElement *fel = trial_fes.GetTypicalFE(); // In H(curl)
|
||||
const FiniteElement *eltest = test_fes.GetTypicalFE(); // In scalar space
|
||||
|
||||
const VectorTensorFiniteElement *el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(fel);
|
||||
@@ -37,7 +37,7 @@ void MixedScalarCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(*eltest, *eltest,
|
||||
*mesh->GetElementTransformation(0));
|
||||
*mesh->GetTypicalElementTransformation());
|
||||
|
||||
const int dims = el->GetDim();
|
||||
MFEM_VERIFY(dims == 2, "");
|
||||
@@ -112,8 +112,8 @@ void MixedVectorCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
{
|
||||
// Assumes tensor-product elements, with vector test and trial spaces.
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement *trial_fel = trial_fes.GetFE(0);
|
||||
const FiniteElement *test_fel = test_fes.GetFE(0);
|
||||
const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
|
||||
const FiniteElement *test_fel = test_fes.GetTypicalFE();
|
||||
|
||||
const VectorTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
|
||||
@@ -125,7 +125,7 @@ void MixedVectorCurlIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
|
||||
*mesh->GetElementTransformation(0));
|
||||
*mesh->GetTypicalElementTransformation());
|
||||
const int dims = trial_el->GetDim();
|
||||
MFEM_VERIFY(dims == 3, "");
|
||||
|
||||
@@ -271,8 +271,8 @@ void MixedVectorWeakCurlIntegrator::AssemblePA(const FiniteElementSpace
|
||||
{
|
||||
// Assumes tensor-product elements, with vector test and trial spaces.
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement *trial_fel = trial_fes.GetFE(0);
|
||||
const FiniteElement *test_fel = test_fes.GetFE(0);
|
||||
const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
|
||||
const FiniteElement *test_fel = test_fes.GetTypicalFE();
|
||||
|
||||
const VectorTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
|
||||
@@ -284,7 +284,7 @@ void MixedVectorWeakCurlIntegrator::AssemblePA(const FiniteElementSpace
|
||||
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
|
||||
*mesh->GetElementTransformation(0));
|
||||
*mesh->GetTypicalElementTransformation());
|
||||
const int dims = trial_el->GetDim();
|
||||
MFEM_VERIFY(dims == 3, "");
|
||||
|
||||
|
||||
@@ -666,8 +666,8 @@ void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
|
||||
{
|
||||
// Assumes tensor-product elements, with a vector test space and H^1 trial space.
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement *trial_fel = trial_fes.GetFE(0);
|
||||
const FiniteElement *test_fel = test_fes.GetFE(0);
|
||||
const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
|
||||
const FiniteElement *test_fel = test_fes.GetTypicalFE();
|
||||
|
||||
const NodalTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const NodalTensorFiniteElement*>(trial_fel);
|
||||
@@ -679,7 +679,7 @@ void MixedVectorGradientIntegrator::AssemblePA(const FiniteElementSpace
|
||||
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
|
||||
*mesh->GetElementTransformation(0));
|
||||
*mesh->GetTypicalElementTransformation());
|
||||
const int dims = trial_el->GetDim();
|
||||
MFEM_VERIFY(dims == 2 || dims == 3, "");
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@ void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
Vector ea_data_tmp(ea_data.Size());
|
||||
bfi->AssembleEA(fes, ea_data_tmp, false);
|
||||
const int ne = fes.GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int dofs = fes.GetFE(0)->GetDof();
|
||||
const int dofs = fes.GetTypicalFE()->GetDof();
|
||||
auto A = Reshape(ea_data_tmp.Read(), dofs, dofs, ne);
|
||||
auto AT = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
|
||||
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
|
||||
@@ -43,8 +42,7 @@ void TransposeIntegrator::AssembleEA(const FiniteElementSpace &fes,
|
||||
{
|
||||
bfi->AssembleEA(fes, ea_data, false);
|
||||
const int ne = fes.GetNE();
|
||||
if (ne == 0) { return; }
|
||||
const int dofs = fes.GetFE(0)->GetDof();
|
||||
const int dofs = fes.GetTypicalFE()->GetDof();
|
||||
auto A = Reshape(ea_data.ReadWrite(), dofs, dofs, ne);
|
||||
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
|
||||
{
|
||||
@@ -74,8 +72,7 @@ void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
Vector ea_data_int_tmp(ea_data_int.Size());
|
||||
Vector ea_data_ext_tmp(ea_data_ext.Size());
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int_tmp, ea_data_ext_tmp, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
|
||||
const int faceDofs = fes.GetTypicalTraceElement()->GetDof();
|
||||
auto A_int = Reshape(ea_data_int_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto A_ext = Reshape(ea_data_ext_tmp.Read(), faceDofs, faceDofs, 2, nf);
|
||||
auto AT_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
@@ -101,8 +98,7 @@ void TransposeIntegrator::AssembleEAInteriorFaces(const FiniteElementSpace& fes,
|
||||
else
|
||||
{
|
||||
bfi->AssembleEAInteriorFaces(fes, ea_data_int, ea_data_ext, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
|
||||
const int faceDofs = fes.GetTypicalTraceElement()->GetDof();
|
||||
auto A_int = Reshape(ea_data_int.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
auto A_ext = Reshape(ea_data_ext.ReadWrite(), faceDofs, faceDofs, 2, nf);
|
||||
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
|
||||
@@ -145,8 +141,7 @@ void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
{
|
||||
Vector ea_data_bdr_tmp(ea_data_bdr.Size());
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr_tmp, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
|
||||
const int faceDofs = fes.GetTypicalTraceElement()->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr_tmp.Read(), faceDofs, faceDofs, nf);
|
||||
auto AT_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
|
||||
@@ -164,8 +159,7 @@ void TransposeIntegrator::AssembleEABoundaryFaces(const FiniteElementSpace& fes,
|
||||
else
|
||||
{
|
||||
bfi->AssembleEABoundaryFaces(fes, ea_data_bdr, false);
|
||||
const int faceDofs = fes.GetTraceElement(0,
|
||||
fes.GetMesh()->GetFaceGeometry(0))->GetDof();
|
||||
const int faceDofs = fes.GetTypicalTraceElement()->GetDof();
|
||||
auto A_bdr = Reshape(ea_data_bdr.ReadWrite(), faceDofs, faceDofs, nf);
|
||||
mfem::forall(nf, [=] MFEM_HOST_DEVICE (int f)
|
||||
{
|
||||
|
||||
@@ -20,8 +20,7 @@ void VectorDiffusionIntegrator::AssembleMF(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &DiffusionIntegrator::GetRule(el, el);
|
||||
if (DeviceCanUseCeed())
|
||||
|
||||
@@ -140,7 +140,7 @@ void VectorDiffusionIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &DiffusionIntegrator::GetRule(el, el);
|
||||
if (DeviceCanUseCeed())
|
||||
|
||||
@@ -124,9 +124,9 @@ void VectorDivergenceIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
MFEM_ASSERT(trial_fes.GetOrdering() == Ordering::byNODES,
|
||||
"PA Only supports Ordering::byNODES!");
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement &trial_fe = *trial_fes.GetFE(0);
|
||||
const FiniteElement &test_fe = *test_fes.GetFE(0);
|
||||
ElementTransformation *trans = mesh->GetElementTransformation(0);
|
||||
const FiniteElement &trial_fe = *trial_fes.GetTypicalFE();
|
||||
const FiniteElement &test_fe = *test_fes.GetTypicalFE();
|
||||
ElementTransformation *trans = mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(trial_fe, test_fe,
|
||||
*trans);
|
||||
const int dims = trial_fe.GetDim();
|
||||
|
||||
@@ -20,9 +20,8 @@ void VectorMassIntegrator::AssembleMF(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assuming the same element type
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation *T = mesh->GetElementTransformation(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
ElementTransformation *T = mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(el, el, *T);
|
||||
if (DeviceCanUseCeed())
|
||||
|
||||
@@ -21,9 +21,8 @@ void VectorMassIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
{
|
||||
// Assuming the same element type
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
if (mesh->GetNE() == 0) { return; }
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation *T = mesh->GetElementTransformation(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
ElementTransformation *T = mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(el, el, *T);
|
||||
if (DeviceCanUseCeed())
|
||||
|
||||
@@ -24,8 +24,8 @@ VectorFEDivergenceIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
// Assumes tensor-product elements, with a vector test space and
|
||||
// scalar trial space.
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
const FiniteElement *trial_fel = trial_fes.GetFE(0);
|
||||
const FiniteElement *test_fel = test_fes.GetFE(0);
|
||||
const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
|
||||
const FiniteElement *test_fel = test_fes.GetTypicalFE();
|
||||
|
||||
const VectorTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
|
||||
@@ -37,7 +37,7 @@ VectorFEDivergenceIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &MassIntegrator::GetRule(
|
||||
*trial_el, *trial_el,
|
||||
*mesh->GetElementTransformation(0));
|
||||
*mesh->GetTypicalElementTransformation());
|
||||
|
||||
const int dims = trial_el->GetDim();
|
||||
MFEM_VERIFY(dims == 2 || dims == 3, "");
|
||||
|
||||
@@ -31,19 +31,19 @@ void VectorFEMassIntegrator::AssemblePA(const FiniteElementSpace &trial_fes,
|
||||
// Assumes tensor-product elements
|
||||
Mesh *mesh = trial_fes.GetMesh();
|
||||
|
||||
const FiniteElement *trial_fel = trial_fes.GetFE(0);
|
||||
const FiniteElement *trial_fel = trial_fes.GetTypicalFE();
|
||||
const VectorTensorFiniteElement *trial_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(trial_fel);
|
||||
MFEM_VERIFY(trial_el != NULL, "Only VectorTensorFiniteElement is supported!");
|
||||
|
||||
const FiniteElement *test_fel = test_fes.GetFE(0);
|
||||
const FiniteElement *test_fel = test_fes.GetTypicalFE();
|
||||
const VectorTensorFiniteElement *test_el =
|
||||
dynamic_cast<const VectorTensorFiniteElement*>(test_fel);
|
||||
MFEM_VERIFY(test_el != NULL, "Only VectorTensorFiniteElement is supported!");
|
||||
|
||||
const IntegrationRule *ir
|
||||
= IntRule ? IntRule : &MassIntegrator::GetRule(*trial_el, *trial_el,
|
||||
*mesh->GetElementTransformation(0));
|
||||
*mesh->GetTypicalElementTransformation());
|
||||
const int dims = trial_el->GetDim();
|
||||
MFEM_VERIFY(dims == 2 || dims == 3, "");
|
||||
|
||||
|
||||
@@ -190,13 +190,13 @@ static void DLFEvalAssemble(const FiniteElementSpace &fes,
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const int dim = mesh->Dimension();
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
const MemoryType mt = Device::GetDeviceMemoryType();
|
||||
const DofToQuad &maps = el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int d = maps.ndof, q = maps.nqpt;
|
||||
constexpr int flags = GeometricFactors::DETERMINANTS;
|
||||
const GeometricFactors *geom = mesh->GetGeometricFactors(*ir, flags, mt);
|
||||
const int map_type = fes.GetFE(0)->GetMapType();
|
||||
const int map_type = fes.GetTypicalFE()->GetMapType();
|
||||
decltype(&DLFEvalAssemble2D<>) ker =
|
||||
dim == 2 ? DLFEvalAssemble2D<> : DLFEvalAssemble3D<>;
|
||||
|
||||
@@ -242,7 +242,7 @@ void DomainLFIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
||||
const Array<int> &markers,
|
||||
Vector &b)
|
||||
{
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const int qorder = oa * fe.GetOrder() + ob;
|
||||
const Geometry::Type gtype = fe.GetGeomType();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &IntRules.Get(gtype, qorder);
|
||||
@@ -256,7 +256,7 @@ void VectorDomainLFIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
||||
const Array<int> &markers,
|
||||
Vector &b)
|
||||
{
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const int qorder = 2 * fe.GetOrder();
|
||||
const Geometry::Type gtype = fe.GetGeomType();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &IntRules.Get(gtype, qorder);
|
||||
|
||||
@@ -267,7 +267,7 @@ static void DLFGradAssemble(const FiniteElementSpace &fes,
|
||||
{
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const int dim = mesh->Dimension();
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
const MemoryType mt = Device::GetDeviceMemoryType();
|
||||
const DofToQuad &maps = el.GetDofToQuad(*ir, DofToQuad::TENSOR);
|
||||
const int d = maps.ndof, q = maps.nqpt;
|
||||
@@ -320,7 +320,7 @@ void DomainLFGradIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
||||
Vector &b)
|
||||
{
|
||||
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const int qorder = 2 * fe.GetOrder();
|
||||
const Geometry::Type gtype = fe.GetGeomType();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &IntRules.Get(gtype, qorder);
|
||||
@@ -334,7 +334,7 @@ void VectorDomainLFGradIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
||||
const Array<int> &markers,
|
||||
Vector &b)
|
||||
{
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const int qorder = 2 * fe.GetOrder();
|
||||
const Geometry::Type gtype = fe.GetGeomType();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &IntRules.Get(gtype, qorder);
|
||||
|
||||
@@ -278,7 +278,7 @@ static void HdivDLFAssemble(const FiniteElementSpace &fes,
|
||||
{
|
||||
Mesh &mesh = *fes.GetMesh();
|
||||
const int dim = mesh.Dimension();
|
||||
const FiniteElement *el = fes.GetFE(0);
|
||||
const FiniteElement *el = fes.GetTypicalFE();
|
||||
const auto *vel = dynamic_cast<const VectorTensorFiniteElement *>(el);
|
||||
MFEM_VERIFY(vel != nullptr, "Must be VectorTensorFiniteElement");
|
||||
const MemoryType mt = Device::GetDeviceMemoryType();
|
||||
@@ -329,7 +329,7 @@ void VectorFEDomainLFIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
||||
const Array<int> &markers,
|
||||
Vector &b)
|
||||
{
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const int qorder = 2 * fe.GetOrder();
|
||||
const Geometry::Type gtype = fe.GetGeomType();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &IntRules.Get(gtype, qorder);
|
||||
|
||||
@@ -20,8 +20,8 @@ void VectorConvectionNLFIntegrator::AssembleMF(const FiniteElementSpace &fes)
|
||||
MFEM_ASSERT(fes.GetOrdering() == Ordering::byNODES,
|
||||
"PA Only supports Ordering::byNODES!");
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation &T = *mesh->GetElementTransformation(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
ElementTransformation &T = *mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, T);
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
|
||||
@@ -21,8 +21,8 @@ void VectorConvectionNLFIntegrator::AssemblePA(const FiniteElementSpace &fes)
|
||||
MFEM_ASSERT(fes.GetOrdering() == Ordering::byNODES,
|
||||
"PA Only supports Ordering::byNODES!");
|
||||
Mesh *mesh = fes.GetMesh();
|
||||
const FiniteElement &el = *fes.GetFE(0);
|
||||
ElementTransformation &T = *mesh->GetElementTransformation(0);
|
||||
const FiniteElement &el = *fes.GetTypicalFE();
|
||||
ElementTransformation &T = *mesh->GetTypicalElementTransformation();
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, T);
|
||||
if (DeviceCanUseCeed())
|
||||
{
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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.
|
||||
|
||||
#include "integrator.hpp"
|
||||
#include "fem.hpp"
|
||||
#include "intrules.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
const IntegrationRule* Integrator::GetIntegrationRule(
|
||||
const FiniteElement& trial_fe, const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const
|
||||
{
|
||||
const IntegrationRule* result;
|
||||
const NURBSFiniteElement *NURBSFE;
|
||||
if (patchRules &&
|
||||
(NURBSFE = dynamic_cast<const NURBSFiniteElement *>(&test_fe)))
|
||||
{
|
||||
const int patch = NURBSFE->GetPatch();
|
||||
const int* ijk = NURBSFE->GetIJK();
|
||||
Array<const KnotVector*>& kv = NURBSFE->KnotVectors();
|
||||
result = &patchRules->GetElementRule(NURBSFE->GetElement(), patch, ijk,
|
||||
kv);
|
||||
}
|
||||
else if (IntRule)
|
||||
{
|
||||
result = IntRule;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = GetDefaultIntegrationRule(trial_fe, test_fe, trans);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const IntegrationRule* Integrator::GetIntegrationRule(
|
||||
const FiniteElement& el,
|
||||
const ElementTransformation& trans) const
|
||||
{
|
||||
return GetIntegrationRule(el, el, trans);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// 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.
|
||||
|
||||
#ifndef MFEM_INTEGRATOR
|
||||
#define MFEM_INTEGRATOR
|
||||
|
||||
#include "../config/config.hpp"
|
||||
#include "fe.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
/** @brief This base class implements some shared functionality between
|
||||
linear and nonlinear form integrators. */
|
||||
class Integrator
|
||||
{
|
||||
public:
|
||||
/** @brief Create a new Integrator, optionally providing a prescribed
|
||||
quadrature rule to use in assembly. */
|
||||
Integrator(const IntegrationRule *ir = NULL) : IntRule(ir) {}
|
||||
|
||||
/** @brief Prescribe a fixed IntegrationRule to use, or set to null to let
|
||||
the integrator choose an appropriate rule.
|
||||
|
||||
@details This method allows setting a custom integration rule to use
|
||||
on each element during assembly, overriding the default
|
||||
choice if it is non-null. Passing a non-null value will
|
||||
set the Integrator's NURBS patch integration rule to null
|
||||
to avoid ambiguity in GetIntegrationRule.
|
||||
*/
|
||||
virtual void SetIntRule(const IntegrationRule *ir)
|
||||
{ IntRule = ir; if (ir) { patchRules = nullptr; } }
|
||||
|
||||
/** @brief Prescribe a fixed IntegrationRule to use. Sets the NURBS patch
|
||||
integration rule to null.
|
||||
|
||||
@see SetIntRule(const IntegrationRule*)
|
||||
*/
|
||||
void SetIntegrationRule(const IntegrationRule &ir) { SetIntRule(&ir); }
|
||||
|
||||
/** @brief Sets an integration rule for use on NURBS patches.
|
||||
|
||||
@details For patchwise integration, SetNURBSPatchIntRule
|
||||
must be called. Passing a non-null value will set the
|
||||
Integrator's standard element IntegrationRule to null
|
||||
to avoid ambiguity in GetIntegrationRule.
|
||||
*/
|
||||
void SetNURBSPatchIntRule(NURBSMeshRules *pr)
|
||||
{ patchRules = pr; if (pr) { IntRule = nullptr; } }
|
||||
|
||||
/** @brief Check if a NURBS patch integration rule has been set. */
|
||||
bool HasNURBSPatchIntRule() const { return patchRules != nullptr; }
|
||||
|
||||
/** @brief Directly return the IntRule pointer (possibly null) without
|
||||
checking for NURBS patch rules or falling back on a default. */
|
||||
const IntegrationRule *GetIntRule() const { return IntRule; }
|
||||
|
||||
/** @brief Equivalent to GetIntRule, but retained for backward
|
||||
compatibility with applications. */
|
||||
const IntegrationRule *GetIntegrationRule() const { return GetIntRule(); }
|
||||
|
||||
protected:
|
||||
const IntegrationRule *IntRule;
|
||||
NURBSMeshRules *patchRules = nullptr;
|
||||
|
||||
/** @brief Returns an integration rule based on the the arguments and
|
||||
internal state of the Integrator object.
|
||||
|
||||
@details This method returns an integration rule in a way that depends
|
||||
on the integrator's attributes. Attributes can specify an
|
||||
existing IntegrationRule, and/or a NURBSMeshRules object.
|
||||
This method will pick the NURBSMeshRules' restriction to the
|
||||
element if given and applicable, and IntRule otherwise,
|
||||
prioritizing the NURBS rule if available. If neither is
|
||||
valid, the integrator will fall back on the virtual method
|
||||
GetDefaultIntegrationRule to choose a default integration
|
||||
rule, where subclasses can override this in a problem-specific
|
||||
way.
|
||||
*/
|
||||
const IntegrationRule* GetIntegrationRule(
|
||||
const FiniteElement& trial_fe, const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const;
|
||||
|
||||
/** @brief Returns an integration rule based on the arguments and
|
||||
internal state. (Version for identical trial_fe and test_fe)
|
||||
|
||||
@see GetIntegrationRule(const FiniteElement*, const FiniteElement*,
|
||||
const ElementTransformation*)
|
||||
*/
|
||||
const IntegrationRule* GetIntegrationRule(
|
||||
const FiniteElement& el,
|
||||
const ElementTransformation& trans) const;
|
||||
|
||||
/** @brief Subclasses should override to choose a default integration rule.
|
||||
|
||||
@details This method is intended to be overriden by subclasses to
|
||||
choose an appropriate integration rule based on the finite
|
||||
element spaces and/or element transformation. The trial_fe
|
||||
and test_fe should be equal for linear forms. The default
|
||||
base-class implementation returns null, which assumes that
|
||||
an appropriate rule is provided by another means, or that null
|
||||
integration rules are handled appropriately by the caller.
|
||||
*/
|
||||
virtual const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe, const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const
|
||||
{ return NULL; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
+20
-15
@@ -1864,11 +1864,8 @@ IntegrationRule *IntegrationRules::CubeIntegrationRule(int Order)
|
||||
|
||||
IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
|
||||
const int patch, const int *ijk,
|
||||
Array<const KnotVector*> const& kv,
|
||||
bool & deleteRule) const
|
||||
Array<const KnotVector*> const& kv) const
|
||||
{
|
||||
deleteRule = false;
|
||||
|
||||
// First check whether a rule has been assigned to element index elem.
|
||||
auto search = elementToRule.find(elem);
|
||||
if (search != elementToRule.end())
|
||||
@@ -1876,6 +1873,11 @@ IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
|
||||
return *elementRule[search->second];
|
||||
}
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
// If no prescribed rule is given for the current element, a temporary one is
|
||||
// formed by restricting a tensor-product of 1D rules to the element. The
|
||||
// ownership model for this temporary rule is not thread-safe.
|
||||
|
||||
MFEM_VERIFY(patchRules1D.NumRows(),
|
||||
"Undefined rule in NURBSMeshRules::GetElementRule");
|
||||
|
||||
@@ -1908,14 +1910,13 @@ IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
|
||||
}
|
||||
}
|
||||
|
||||
npd[d] = el[d].size() / 2;
|
||||
npd[d] = static_cast<int>(el[d].size() / 2);
|
||||
np *= npd[d];
|
||||
}
|
||||
|
||||
IntegrationRule *irp = new IntegrationRule(np);
|
||||
deleteRule = true;
|
||||
temporaryElementRule.SetSize(np);
|
||||
|
||||
// Set (*irp)[i + j*npd[0] + k*npd[0]*npd[1]] =
|
||||
// Set temporaryElementRule[i + j*npd[0] + k*npd[0]*npd[1]] =
|
||||
// (el[0][2*i], el[1][2*j], el[2][2*k])
|
||||
|
||||
MFEM_VERIFY(npd[0] > 0 && npd[1] > 0, "Assuming 2D or 3D");
|
||||
@@ -1927,22 +1928,26 @@ IntegrationRule& NURBSMeshRules::GetElementRule(const int elem,
|
||||
for (int k = 0; k < std::max(npd[2], 1); ++k)
|
||||
{
|
||||
const int id = i + j*npd[0] + k*npd[0]*npd[1];
|
||||
(*irp)[id].x = el[0][2*i];
|
||||
(*irp)[id].y = el[1][2*j];
|
||||
temporaryElementRule[id].x = el[0][2*i];
|
||||
temporaryElementRule[id].y = el[1][2*j];
|
||||
|
||||
(*irp)[id].weight = el[0][(2*i)+1];
|
||||
(*irp)[id].weight *= el[1][(2*j)+1];
|
||||
temporaryElementRule[id].weight = el[0][(2*i)+1];
|
||||
temporaryElementRule[id].weight *= el[1][(2*j)+1];
|
||||
|
||||
if (npd[2] > 0)
|
||||
{
|
||||
(*irp)[id].z = el[2][2*k];
|
||||
(*irp)[id].weight *= el[2][(2*k)+1];
|
||||
temporaryElementRule[id].z = el[2][2*k];
|
||||
temporaryElementRule[id].weight *= el[2][(2*k)+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *irp;
|
||||
return temporaryElementRule;
|
||||
#else
|
||||
MFEM_ABORT("Temporary integration rules on NURBS elements "
|
||||
"are not thread-safe.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void NURBSMeshRules::GetIntegrationPointFrom1D(const int patch, int i, int j,
|
||||
|
||||
+8
-2
@@ -286,8 +286,7 @@ public:
|
||||
/// Returns a rule for the element.
|
||||
IntegrationRule &GetElementRule(const int elem, const int patch,
|
||||
const int *ijk,
|
||||
Array<const KnotVector*> const& kv,
|
||||
bool & deleteRule) const;
|
||||
Array<const KnotVector*> const& kv) const;
|
||||
|
||||
/// Add a rule to be used for individual elements. Returns the rule index.
|
||||
std::size_t AddElementRule(IntegrationRule *ir_element)
|
||||
@@ -361,6 +360,13 @@ private:
|
||||
std::vector<Array3D<int>> pointToElem;
|
||||
std::vector<std::vector<Array<int>>> patchRules1D_KnotSpan;
|
||||
|
||||
#ifndef MFEM_THREAD_SAFE
|
||||
// This is a temporary quadrature rule for integrating over the
|
||||
// current element in an assembly loop. It may be modified when
|
||||
// moving to a new element, and is therefore not thread-safe.
|
||||
mutable IntegrationRule temporaryElementRule;
|
||||
#endif
|
||||
|
||||
const int npatches;
|
||||
const int dim;
|
||||
};
|
||||
|
||||
+2
-2
@@ -109,8 +109,8 @@ public:
|
||||
}
|
||||
|
||||
// intialize the bounding box
|
||||
const FiniteElement* el=space->GetFE(0);
|
||||
trans = space->GetElementTransformation(0);
|
||||
const FiniteElement* el = space->GetTypicalFE();
|
||||
trans = mesh->GetTypicalElementTransformation();
|
||||
ir=&(el->GetNodes());
|
||||
space->GetElementVDofs(0,vdofs);
|
||||
elco.SetSize(dim,ir->GetNPoints());
|
||||
|
||||
+12
-6
@@ -78,9 +78,9 @@ namespace mfem
|
||||
const char *kernel_name = MFEM_KERNEL_NAME(KernelName); \
|
||||
using KernelSignature = KernelType; \
|
||||
template <MFEM_PARAM_LIST P3> \
|
||||
static KernelSignature Kernel(); \
|
||||
static KernelSignature Fallback(MFEM_PARAM_LIST P1); \
|
||||
static KernelName &Get() \
|
||||
static MFEM_EXPORT KernelSignature Kernel(); \
|
||||
static MFEM_EXPORT KernelSignature Fallback(MFEM_PARAM_LIST P1); \
|
||||
static MFEM_EXPORT KernelName &Get() \
|
||||
{ static KernelName table; return table;} \
|
||||
}
|
||||
|
||||
@@ -126,9 +126,9 @@ class KernelDispatchTable<Kernels,
|
||||
internal::KernelTypeList<Params...>,
|
||||
internal::KernelTypeList<OptParams...>>
|
||||
{
|
||||
std::unordered_map<std::tuple<Params...>,
|
||||
Signature,
|
||||
KernelDispatchKeyHash<Params...>> table;
|
||||
using TableType = std::unordered_map<std::tuple<Params...>,
|
||||
Signature, KernelDispatchKeyHash<Params...>>;
|
||||
TableType table;
|
||||
|
||||
public:
|
||||
/// @brief Run the kernel with the given dispatch parameters and arguments.
|
||||
@@ -176,6 +176,12 @@ public:
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/// Return the dispatch map table
|
||||
static const TableType &GetDispatchTable()
|
||||
{
|
||||
return Kernels::Get().table;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class KernelReporter
|
||||
std::set<std::string> reported_fallbacks;
|
||||
KernelReporter()
|
||||
{
|
||||
const char *env = getenv("MFEM_REPORT_KERNELS");
|
||||
const char *env = GetEnv("MFEM_REPORT_KERNELS");
|
||||
if (env)
|
||||
{
|
||||
if (std::string(env) != "NO") { enabled = true; }
|
||||
|
||||
+9
-8
@@ -11,10 +11,10 @@
|
||||
|
||||
#include "fem.hpp"
|
||||
#include <cmath>
|
||||
#include "intrules.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
void LinearFormIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
||||
const Array<int> &markers,
|
||||
Vector &b)
|
||||
@@ -45,7 +45,8 @@ void DomainLFIntegrator::AssembleRHSElementVect(const FiniteElement &el,
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
|
||||
if (ir == NULL)
|
||||
{
|
||||
// ir = &IntRules.Get(el.GetGeomType(),
|
||||
@@ -86,7 +87,7 @@ void DomainLFGradIntegrator::AssembleRHSElementVect(
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2 * el.GetOrder();
|
||||
@@ -278,7 +279,7 @@ void VectorDomainLFIntegrator::AssembleRHSElementVect(
|
||||
elvect.SetSize(dof * vdim);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2*el.GetOrder();
|
||||
@@ -337,7 +338,7 @@ void VectorDomainLFGradIntegrator::AssembleRHSElementVect(
|
||||
elvect.SetSize(dof*(vdim/sdim));
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2 * el.GetOrder();
|
||||
@@ -463,7 +464,7 @@ void VectorFEDomainLFIntegrator::AssembleRHSElementVect(
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
if (ir == NULL)
|
||||
{
|
||||
// int intorder = 2*el.GetOrder() - 1; // ok for O(h^{k+1}) conv. in L2
|
||||
@@ -512,7 +513,7 @@ void VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect(
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2*el.GetOrder();
|
||||
@@ -558,7 +559,7 @@ void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(
|
||||
elvect.SetSize(dof);
|
||||
elvect = 0.0;
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
||||
if (ir == NULL)
|
||||
{
|
||||
int intorder = 2 * el.GetOrder();
|
||||
|
||||
+4
-7
@@ -16,17 +16,17 @@
|
||||
#include "coefficient.hpp"
|
||||
#include "bilininteg.hpp"
|
||||
#include <random>
|
||||
#include "integrator.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
|
||||
/// Abstract base class LinearFormIntegrator
|
||||
class LinearFormIntegrator
|
||||
class LinearFormIntegrator : public Integrator
|
||||
{
|
||||
protected:
|
||||
const IntegrationRule *IntRule;
|
||||
|
||||
LinearFormIntegrator(const IntegrationRule *ir = NULL) { IntRule = ir; }
|
||||
LinearFormIntegrator(const IntegrationRule *ir = NULL) : Integrator(ir) {}
|
||||
|
||||
public:
|
||||
|
||||
@@ -51,9 +51,6 @@ public:
|
||||
FaceElementTransformations &Tr,
|
||||
Vector &elvect);
|
||||
|
||||
virtual void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
|
||||
const IntegrationRule* GetIntRule() { return IntRule; }
|
||||
|
||||
virtual ~LinearFormIntegrator() { }
|
||||
};
|
||||
|
||||
@@ -676,7 +673,7 @@ public:
|
||||
int myid;
|
||||
MPI_Comm_rank(comm, &myid);
|
||||
|
||||
int seed = (seed_ > 0) ? seed_ + myid : time(0) + myid;
|
||||
int seed = (seed_ > 0) ? seed_ + myid : (int)time(0) + myid;
|
||||
SetSeed(seed);
|
||||
}
|
||||
#else
|
||||
|
||||
+2
-2
@@ -29,7 +29,7 @@ void LORBase::AddIntegrators(BilinearForm &a_from,
|
||||
{
|
||||
BilinearFormIntegrator *integrator = (*integrators)[i];
|
||||
(a_to.*add_integrator)(integrator);
|
||||
ir_map[integrator] = integrator->GetIntegrationRule();
|
||||
ir_map[integrator] = integrator->GetIntRule();
|
||||
if (ir) { integrator->SetIntegrationRule(*ir); }
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@ void LORBase::AddIntegratorsAndMarkers(BilinearForm &a_from,
|
||||
{
|
||||
(a_to.*add_integrator)(integrator);
|
||||
}
|
||||
ir_map[integrator] = integrator->GetIntegrationRule();
|
||||
ir_map[integrator] = integrator->GetIntRule();
|
||||
if (ir) { integrator->SetIntegrationRule(*ir); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ int BatchedLORAssembly::FillI(SparseMatrix &A) const
|
||||
|
||||
const int nvdof = fes_ho.GetVSize();
|
||||
|
||||
const int ndof_per_el = fes_ho.GetFE(0)->GetDof();
|
||||
const int ndof_per_el = fes_ho.GetTypicalFE()->GetDof();
|
||||
const int nel_ho = fes_ho.GetNE();
|
||||
const int nnz_per_row = sparse_mapping.Size()/ndof_per_el;
|
||||
|
||||
@@ -230,7 +230,7 @@ int BatchedLORAssembly::FillI(SparseMatrix &A) const
|
||||
void BatchedLORAssembly::FillJAndData(SparseMatrix &A) const
|
||||
{
|
||||
const int nvdof = fes_ho.GetVSize();
|
||||
const int ndof_per_el = fes_ho.GetFE(0)->GetDof();
|
||||
const int ndof_per_el = fes_ho.GetTypicalFE()->GetDof();
|
||||
const int nel_ho = fes_ho.GetNE();
|
||||
const int nnz_per_row = sparse_mapping.Size()/ndof_per_el;
|
||||
|
||||
@@ -500,7 +500,7 @@ BatchedLORAssembly::BatchedLORAssembly(FiniteElementSpace &fes_ho_)
|
||||
IntegrationRule GetCollocatedIntRule(FiniteElementSpace &fes)
|
||||
{
|
||||
IntegrationRules irs(0, Quadrature1D::GaussLobatto);
|
||||
const Geometry::Type geom = fes.GetMesh()->GetElementGeometry(0);
|
||||
const Geometry::Type geom = fes.GetMesh()->GetTypicalElementGeometry();
|
||||
const int nd1d = fes.GetMaxElementOrder() + 1;
|
||||
return irs.Get(geom, 2*nd1d - 3);
|
||||
}
|
||||
|
||||
+14
-12
@@ -383,6 +383,12 @@ void NeoHookeanModel::AssembleH(const DenseMatrix &J, const DenseMatrix &DS,
|
||||
}
|
||||
}
|
||||
|
||||
const IntegrationRule* HyperelasticNLFIntegrator::GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe, const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const
|
||||
{
|
||||
return &(IntRules.Get(test_fe.GetGeomType(), 2*test_fe.GetOrder() + 3));
|
||||
}
|
||||
|
||||
real_t HyperelasticNLFIntegrator::GetElementEnergy(const FiniteElement &el,
|
||||
ElementTransformation &Ttr,
|
||||
@@ -397,11 +403,7 @@ real_t HyperelasticNLFIntegrator::GetElementEnergy(const FiniteElement &el,
|
||||
Jpt.SetSize(dim);
|
||||
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
if (!ir)
|
||||
{
|
||||
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
||||
}
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Ttr);
|
||||
|
||||
energy = 0.0;
|
||||
model->SetTransformation(Ttr);
|
||||
@@ -436,7 +438,7 @@ void HyperelasticNLFIntegrator::AssembleElementVector(
|
||||
elvect.SetSize(dof*dim);
|
||||
PMatO.UseExternalData(elvect.GetData(), dof, dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Ttr);
|
||||
if (!ir)
|
||||
{
|
||||
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
||||
@@ -475,7 +477,7 @@ void HyperelasticNLFIntegrator::AssembleElementGrad(const FiniteElement &el,
|
||||
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
||||
elmat.SetSize(dof*dim);
|
||||
|
||||
const IntegrationRule *ir = IntRule;
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, Ttr);
|
||||
if (!ir)
|
||||
{
|
||||
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
||||
@@ -733,7 +735,7 @@ void IncompressibleNeoHookeanIntegrator::AssembleElementGrad(
|
||||
|
||||
const IntegrationRule&
|
||||
VectorConvectionNLFIntegrator::GetRule(const FiniteElement &fe,
|
||||
ElementTransformation &T)
|
||||
const ElementTransformation &T)
|
||||
{
|
||||
const int order = 2 * fe.GetOrder() + T.OrderGrad(&fe);
|
||||
return IntRules.Get(fe.GetGeomType(), order);
|
||||
@@ -757,7 +759,7 @@ void VectorConvectionNLFIntegrator::AssembleElementVector(
|
||||
ELV.UseExternalData(elvect.GetData(), nd, dim);
|
||||
|
||||
Vector vec1(dim), vec2(dim);
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, T);
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, T);
|
||||
ELV = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
{
|
||||
@@ -797,7 +799,7 @@ void VectorConvectionNLFIntegrator::AssembleElementGrad(
|
||||
real_t w;
|
||||
Vector vec1(dim), vec2(dim), vec3(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, trans);
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, trans);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -868,7 +870,7 @@ void ConvectiveVectorConvectionNLFIntegrator::AssembleElementGrad(
|
||||
|
||||
Vector vec1(dim), vec2(dim), vec3(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, trans);
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, trans);
|
||||
|
||||
elmat = 0.0;
|
||||
for (int i = 0; i < ir->GetNPoints(); i++)
|
||||
@@ -919,7 +921,7 @@ void SkewSymmetricVectorConvectionNLFIntegrator::AssembleElementGrad(
|
||||
|
||||
Vector vec1(dim), vec2(dim), vec3(nd), vec4(dim), vec5(nd);
|
||||
|
||||
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, trans);
|
||||
const IntegrationRule *ir = GetIntegrationRule(el, trans);
|
||||
|
||||
elmat = 0.0;
|
||||
elmat_comp_T = 0.0;
|
||||
|
||||
+19
-19
@@ -17,6 +17,7 @@
|
||||
#include "coefficient.hpp"
|
||||
#include "fespace.hpp"
|
||||
#include "ceed/interface/operator.hpp"
|
||||
#include "integrator.hpp"
|
||||
|
||||
namespace mfem
|
||||
{
|
||||
@@ -24,7 +25,7 @@ namespace mfem
|
||||
/** @brief This class is used to express the local action of a general nonlinear
|
||||
finite element operator. In addition it may provide the capability to
|
||||
assemble the local gradient operator and to compute the local energy. */
|
||||
class NonlinearFormIntegrator
|
||||
class NonlinearFormIntegrator : public Integrator
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
@@ -36,43 +37,27 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
const IntegrationRule *IntRule;
|
||||
|
||||
Mode integrationMode = Mode::ELEMENTWISE;
|
||||
|
||||
// Prescribed integration rules (not reduced approximate rules).
|
||||
NURBSMeshRules *patchRules = nullptr;
|
||||
|
||||
// CEED extension
|
||||
ceed::Operator* ceedOp;
|
||||
|
||||
MemoryType pa_mt = MemoryType::DEFAULT;
|
||||
|
||||
NonlinearFormIntegrator(const IntegrationRule *ir = NULL)
|
||||
: IntRule(ir), ceedOp(NULL) { }
|
||||
: Integrator(ir), ceedOp(NULL) { }
|
||||
|
||||
public:
|
||||
/** @brief Prescribe a fixed IntegrationRule to use (when @a ir != NULL) or
|
||||
let the integrator choose (when @a ir == NULL). */
|
||||
virtual void SetIntRule(const IntegrationRule *ir) { IntRule = ir; }
|
||||
|
||||
void SetIntegrationMode(Mode m) { integrationMode = m; }
|
||||
|
||||
/// For patchwise integration, SetNURBSPatchIntRule must be called.
|
||||
void SetNURBSPatchIntRule(NURBSMeshRules *pr) { patchRules = pr; }
|
||||
bool HasNURBSPatchIntRule() const { return patchRules != nullptr; }
|
||||
|
||||
bool Patchwise() const { return integrationMode != Mode::ELEMENTWISE; }
|
||||
|
||||
/// Prescribe a fixed IntegrationRule to use.
|
||||
void SetIntegrationRule(const IntegrationRule &ir) { SetIntRule(&ir); }
|
||||
|
||||
/// Set the memory type used for GeometricFactors and other large allocations
|
||||
/// in PA extensions.
|
||||
void SetPAMemoryType(MemoryType mt) { pa_mt = mt; }
|
||||
|
||||
/// Get the integration rule of the integrator (possibly NULL).
|
||||
const IntegrationRule *GetIntegrationRule() const { return IntRule; }
|
||||
|
||||
/// Perform the local action of the NonlinearFormIntegrator
|
||||
virtual void AssembleElementVector(const FiniteElement &el,
|
||||
@@ -353,6 +338,11 @@ public:
|
||||
void AssembleElementGrad(const FiniteElement &el,
|
||||
ElementTransformation &Ttr,
|
||||
const Vector &elfun, DenseMatrix &elmat) override;
|
||||
protected:
|
||||
const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe,
|
||||
const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const override;
|
||||
};
|
||||
|
||||
/** Hyperelastic incompressible Neo-Hookean integrator with the PK1 stress
|
||||
@@ -405,7 +395,7 @@ public:
|
||||
VectorConvectionNLFIntegrator() = default;
|
||||
|
||||
static const IntegrationRule &GetRule(const FiniteElement &fe,
|
||||
ElementTransformation &T);
|
||||
const ElementTransformation &T);
|
||||
|
||||
void AssembleElementVector(const FiniteElement &el,
|
||||
ElementTransformation &trans,
|
||||
@@ -426,6 +416,16 @@ public:
|
||||
void AddMultPA(const Vector &x, Vector &y) const override;
|
||||
|
||||
void AddMultMF(const Vector &x, Vector &y) const override;
|
||||
|
||||
|
||||
protected:
|
||||
const IntegrationRule* GetDefaultIntegrationRule(
|
||||
const FiniteElement& trial_fe,
|
||||
const FiniteElement& test_fe,
|
||||
const ElementTransformation& trans) const override
|
||||
{
|
||||
return &GetRule(test_fe, trans);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ L2NormalDerivativeFaceRestriction::L2NormalDerivativeFaceRestriction(
|
||||
|
||||
Mesh &mesh = *fes.GetMesh();
|
||||
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const int d = fe.GetDofToQuad(fe.GetNodes(), DofToQuad::TENSOR).ndof;
|
||||
|
||||
if (dim == 2)
|
||||
@@ -323,7 +323,7 @@ void L2NormalDerivativeFaceRestriction::Mult2D(const Vector &x, Vector &y) const
|
||||
const bool t = fes.GetOrdering() == Ordering::byVDIM;
|
||||
const int num_elem = ne;
|
||||
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const DofToQuad &maps = fe.GetDofToQuad(fe.GetNodes(), DofToQuad::TENSOR);
|
||||
|
||||
const int q = maps.nqpt;
|
||||
@@ -435,7 +435,7 @@ void L2NormalDerivativeFaceRestriction::Mult3D(const Vector &x, Vector &y) const
|
||||
const bool t = fes.GetOrdering() == Ordering::byVDIM;
|
||||
const int num_elem = ne;
|
||||
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const DofToQuad &maps = fe.GetDofToQuad(fe.GetNodes(), DofToQuad::TENSOR);
|
||||
|
||||
const int q = maps.nqpt;
|
||||
@@ -560,7 +560,7 @@ void L2NormalDerivativeFaceRestriction::AddMultTranspose2D(
|
||||
const int vd = fes.GetVDim();
|
||||
const bool t = fes.GetOrdering() == Ordering::byVDIM;
|
||||
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const DofToQuad &maps = fe.GetDofToQuad(fe.GetNodes(), DofToQuad::TENSOR);
|
||||
|
||||
const int q = maps.nqpt;
|
||||
@@ -682,7 +682,7 @@ void L2NormalDerivativeFaceRestriction::AddMultTranspose3D(
|
||||
|
||||
MFEM_VERIFY(vd == 1, "vdim > 1 not supported.");
|
||||
|
||||
const FiniteElement &fe = *fes.GetFE(0);
|
||||
const FiniteElement &fe = *fes.GetTypicalFE();
|
||||
const DofToQuad &maps = fe.GetDofToQuad(fe.GetNodes(), DofToQuad::TENSOR);
|
||||
|
||||
const int q = maps.nqpt;
|
||||
|
||||
+56
-8
@@ -1068,6 +1068,54 @@ void ParFiniteElementSpace::GetEssentialTrueDofs(const Array<int>
|
||||
MarkerToList(true_ess_dofs, ess_tdof_list);
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetExteriorVDofs(Array<int> &ext_dofs,
|
||||
int component) const
|
||||
{
|
||||
FiniteElementSpace::GetExteriorVDofs(ext_dofs, component);
|
||||
|
||||
// Make sure that processors without boundary elements mark
|
||||
// their boundary dofs (if they have any).
|
||||
Synchronize(ext_dofs);
|
||||
}
|
||||
|
||||
void ParFiniteElementSpace::GetExteriorTrueDofs(Array<int> &ext_tdof_list,
|
||||
int component) const
|
||||
{
|
||||
Array<int> ext_dofs, true_ext_dofs;
|
||||
|
||||
GetExteriorVDofs(ext_dofs, component);
|
||||
GetRestrictionMatrix()->BooleanMult(ext_dofs, true_ext_dofs);
|
||||
|
||||
#ifdef MFEM_DEBUG
|
||||
// Verify that in boolean arithmetic: P^T ext_dofs = R ext_dofs.
|
||||
Array<int> true_ext_dofs2(true_ext_dofs.Size());
|
||||
auto Pt = std::unique_ptr<HypreParMatrix>(Dof_TrueDof_Matrix()->Transpose());
|
||||
|
||||
const int *ext_dofs_data = ext_dofs.HostRead();
|
||||
Pt->BooleanMult(1, ext_dofs_data, 0, true_ext_dofs2);
|
||||
int counter = 0;
|
||||
const int *ted = true_ext_dofs.HostRead();
|
||||
std::string error_msg = "failed dof: ";
|
||||
for (int i = 0; i < true_ext_dofs.Size(); i++)
|
||||
{
|
||||
if (bool(ted[i]) != bool(true_ext_dofs2[i]))
|
||||
{
|
||||
error_msg += std::to_string(i) += "(R ";
|
||||
error_msg += std::to_string(bool(ted[i])) += " P^T ";
|
||||
error_msg += std::to_string(bool(true_ext_dofs2[i])) += ") ";
|
||||
++counter;
|
||||
}
|
||||
}
|
||||
MFEM_ASSERT(R->Height() == P->Width(), "!");
|
||||
MFEM_ASSERT(R->Width() == P->Height(), "!");
|
||||
MFEM_ASSERT(R->Width() == ext_dofs.Size(), "!");
|
||||
MFEM_VERIFY(counter == 0, "internal MFEM error: counter = " << counter
|
||||
<< ", rank = " << MyRank << ", " << error_msg);
|
||||
#endif
|
||||
|
||||
MarkerToList(true_ext_dofs, ext_tdof_list);
|
||||
}
|
||||
|
||||
int ParFiniteElementSpace::GetLocalTDofNumber(int ldof) const
|
||||
{
|
||||
if (Nonconforming())
|
||||
@@ -1880,7 +1928,7 @@ void ParFiniteElementSpace::UnpackDof(int dof,
|
||||
{
|
||||
if (uni_fdof >= 0) // uniform faces
|
||||
{
|
||||
int nf = fec->DofForGeometry(pncmesh->GetFaceGeometry(0));
|
||||
int nf = fec->DofForGeometry(pmesh->GetTypicalFaceGeometry());
|
||||
index = dof / nf, edof = dof % nf;
|
||||
}
|
||||
else // mixed faces or var-order space
|
||||
@@ -1984,7 +2032,7 @@ struct PMatrixRow
|
||||
|
||||
void write(std::ostream &os, real_t sign) const
|
||||
{
|
||||
bin_io::write<int>(os, elems.size());
|
||||
bin_io::write<int>(os, static_cast<int>(elems.size()));
|
||||
for (unsigned i = 0; i < elems.size(); i++)
|
||||
{
|
||||
const PMatrixElement &e = elems[i];
|
||||
@@ -2074,7 +2122,7 @@ void NeighborRowMessage::Encode(int rank)
|
||||
}
|
||||
|
||||
Array<GroupId> all_group_ids;
|
||||
all_group_ids.Reserve(rows.size());
|
||||
all_group_ids.Reserve(static_cast<int>(rows.size()));
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
all_group_ids.Append(group_ids[i]);
|
||||
@@ -2833,7 +2881,7 @@ HypreParMatrix* ParFiniteElementSpace
|
||||
}
|
||||
|
||||
// create offd column mapping
|
||||
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(col_map.size());
|
||||
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(static_cast<int>(col_map.size()));
|
||||
int offd_col = 0;
|
||||
for (auto it = col_map.begin(); it != col_map.end(); ++it)
|
||||
{
|
||||
@@ -2893,7 +2941,7 @@ HypreParMatrix* ParFiniteElementSpace
|
||||
row_starts.GetData(), col_starts.GetData(),
|
||||
I_diag, J_diag, A_diag,
|
||||
I_offd, J_offd, A_offd,
|
||||
col_map.size(), cmap);
|
||||
static_cast<HYPRE_Int>(col_map.size()), cmap);
|
||||
}
|
||||
|
||||
template <typename int_type>
|
||||
@@ -3119,7 +3167,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
msg.dofs[i] = old_offset + dofs[i];
|
||||
}
|
||||
|
||||
MPI_Isend(&msg.dofs[0], msg.dofs.size(), HYPRE_MPI_BIG_INT,
|
||||
MPI_Isend(&msg.dofs[0], static_cast<int>(msg.dofs.size()), HYPRE_MPI_BIG_INT,
|
||||
coarse_rank, 291, MyComm, &msg.request);
|
||||
}
|
||||
else if (coarse_rank == MyRank && fine_rank != MyRank)
|
||||
@@ -3240,7 +3288,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
{
|
||||
if (row[j] == 0.0) { continue; } // NOTE: lR thresholded
|
||||
int &lcol = col_map[remote_dofs[j]];
|
||||
if (!lcol) { lcol = col_map.size(); }
|
||||
if (!lcol) { lcol = static_cast<int>(col_map.size()); }
|
||||
offd->_Set_(m, lcol-1, row[j]);
|
||||
}
|
||||
mark[m] = 1;
|
||||
@@ -3252,7 +3300,7 @@ ParFiniteElementSpace::ParallelDerefinementMatrix(int old_ndofs,
|
||||
|
||||
messages.clear();
|
||||
offd->Finalize(0);
|
||||
offd->SetWidth(col_map.size());
|
||||
offd->SetWidth(static_cast<int>(col_map.size()));
|
||||
|
||||
// create offd column mapping for use by hypre
|
||||
HYPRE_BigInt *cmap = Memory<HYPRE_BigInt>(offd->Width());
|
||||
|
||||
@@ -367,6 +367,15 @@ public:
|
||||
Array<int> &ess_tdof_list,
|
||||
int component = -1) const override;
|
||||
|
||||
/// Determine the external degrees of freedom
|
||||
void GetExteriorVDofs(Array<int> &ext_dofs,
|
||||
int component = -1) const override;
|
||||
|
||||
/** Get a list of external true dofs, ext_tdof_list, corresponding to the
|
||||
face on the exterior of the mesh. */
|
||||
void GetExteriorTrueDofs(Array<int> &ext_tdof_list,
|
||||
int component = -1) const override;
|
||||
|
||||
/** If the given ldof is owned by the current processor, return its local
|
||||
tdof number, otherwise return -1 */
|
||||
int GetLocalTDofNumber(int ldof) const;
|
||||
|
||||
+61
-67
@@ -914,19 +914,22 @@ real_t ParGridFunction::ComputeDGFaceJumpError(Coefficient *exsol,
|
||||
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
|
||||
}
|
||||
}
|
||||
real_t face_error = 0.0;
|
||||
transf = face_elem_transf;
|
||||
for (int j = 0; j < ir->GetNPoints(); j++)
|
||||
{
|
||||
const IntegrationPoint &ip = ir->IntPoint(j);
|
||||
transf->SetIntPoint(&ip);
|
||||
real_t nu = jump_scaling.Eval(h, p);
|
||||
error += shared_face_factor*(ip.weight * nu * ell_coeff_val(j) *
|
||||
transf->Weight() *
|
||||
err_val(j) * err_val(j));
|
||||
face_error += shared_face_factor*(ip.weight * nu * ell_coeff_val(j) *
|
||||
transf->Weight() *
|
||||
err_val(j) * err_val(j));
|
||||
}
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
error += fabs(face_error);
|
||||
}
|
||||
|
||||
error = (error < 0.0) ? -sqrt(-error) : sqrt(error);
|
||||
error = sqrt(error);
|
||||
return GlobalLpNorm(2.0, error, pfes->GetComm());
|
||||
}
|
||||
|
||||
@@ -982,70 +985,65 @@ void ParGridFunction::SaveAsSerial(const char *fname, int precision,
|
||||
MPI_Barrier(pmesh->GetComm());
|
||||
}
|
||||
|
||||
GridFunction ParGridFunction::GetSerialGridFunction(int save_rank,
|
||||
Mesh &serial_mesh) const
|
||||
GridFunction ParGridFunction::GetSerialGridFunction(
|
||||
int save_rank, FiniteElementSpace &serial_fes) const
|
||||
{
|
||||
ParFiniteElementSpace *pfespace = ParFESpace();
|
||||
ParMesh *pmesh = pfespace->GetParMesh();
|
||||
|
||||
int vdim = pfespace->GetVDim();
|
||||
auto *fec_serial = FiniteElementCollection::New(pfespace->FEColl()->Name());
|
||||
auto *fespace_serial = new FiniteElementSpace(&serial_mesh,
|
||||
fec_serial,
|
||||
vdim,
|
||||
pfespace->GetOrdering());
|
||||
GridFunction serial_gf(&serial_fes);
|
||||
|
||||
GridFunction gf_serial(fespace_serial);
|
||||
gf_serial.MakeOwner(fec_serial);
|
||||
Array<real_t> vals;
|
||||
Array<int> dofs;
|
||||
MPI_Status status;
|
||||
int n_send_recv;
|
||||
|
||||
int my_rank = pmesh->GetMyRank(),
|
||||
nranks = pmesh->GetNRanks();
|
||||
MPI_Comm my_comm = pmesh->GetComm();
|
||||
const int vdim = pfespace->GetVDim();
|
||||
|
||||
int elem_count = 0; // To keep track of element count in serial mesh
|
||||
const int my_rank = pmesh->GetMyRank();
|
||||
const int nranks = pmesh->GetNRanks();
|
||||
MPI_Comm comm = pmesh->GetComm();
|
||||
|
||||
if (my_rank == save_rank)
|
||||
{
|
||||
int elem_count = 0; // To keep track of element count in serial mesh
|
||||
|
||||
Vector nodeval;
|
||||
for (int e = 0; e < pmesh->GetNE(); e++)
|
||||
{
|
||||
GetElementDofValues(e, nodeval);
|
||||
fespace_serial->GetElementVDofs(elem_count++, dofs);
|
||||
gf_serial.SetSubVector(dofs, nodeval);
|
||||
serial_fes.GetElementVDofs(elem_count++, dofs);
|
||||
serial_gf.SetSubVector(dofs, nodeval);
|
||||
}
|
||||
|
||||
for (int p = 0; p < nranks; p++)
|
||||
{
|
||||
if (p == save_rank) { continue; }
|
||||
MPI_Recv(&n_send_recv, 1, MPI_INT, p, 448, my_comm, &status);
|
||||
int n_send_recv;
|
||||
MPI_Recv(&n_send_recv, 1, MPI_INT, p, 448, comm, &status);
|
||||
vals.SetSize(n_send_recv);
|
||||
if (n_send_recv)
|
||||
{
|
||||
MPI_Recv(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, p, 449, my_comm,
|
||||
MPI_Recv(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, p, 449, comm,
|
||||
&status);
|
||||
}
|
||||
for (int i = 0; i < n_send_recv; )
|
||||
{
|
||||
fespace_serial->GetElementVDofs(elem_count++, dofs);
|
||||
gf_serial.SetSubVector(dofs, &vals[i]);
|
||||
serial_fes.GetElementVDofs(elem_count++, dofs);
|
||||
serial_gf.SetSubVector(dofs, &vals[i]);
|
||||
i += dofs.Size();
|
||||
}
|
||||
}
|
||||
} // my_rank == save_rank
|
||||
else
|
||||
{
|
||||
n_send_recv = 0;
|
||||
int n_send_recv = 0;
|
||||
Vector nodeval;
|
||||
for (int e = 0; e < pmesh->GetNE(); e++)
|
||||
{
|
||||
const FiniteElement *fe = pfespace->GetFE(e);
|
||||
n_send_recv += vdim*fe->GetDof();
|
||||
}
|
||||
MPI_Send(&n_send_recv, 1, MPI_INT, save_rank, 448, my_comm);
|
||||
MPI_Send(&n_send_recv, 1, MPI_INT, save_rank, 448, comm);
|
||||
vals.Reserve(n_send_recv);
|
||||
vals.SetSize(0);
|
||||
for (int e = 0; e < pmesh->GetNE(); e++)
|
||||
@@ -1059,12 +1057,24 @@ GridFunction ParGridFunction::GetSerialGridFunction(int save_rank,
|
||||
if (n_send_recv)
|
||||
{
|
||||
MPI_Send(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, save_rank, 449,
|
||||
my_comm);
|
||||
comm);
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Barrier(my_comm);
|
||||
return gf_serial;
|
||||
return serial_gf;
|
||||
}
|
||||
|
||||
GridFunction ParGridFunction::GetSerialGridFunction(int save_rank,
|
||||
Mesh &serial_mesh) const
|
||||
{
|
||||
auto *serial_fec = pfes->FEColl()->Clone(pfes->FEColl()->GetOrder());
|
||||
auto *serial_fes = new FiniteElementSpace(&serial_mesh,
|
||||
serial_fec,
|
||||
pfes->GetVDim(),
|
||||
pfes->GetOrdering());
|
||||
GridFunction serial_gf = GetSerialGridFunction(save_rank, *serial_fes);
|
||||
serial_gf.MakeOwner(serial_fec); // Also assumes ownership of serial_fes
|
||||
return serial_gf;
|
||||
}
|
||||
|
||||
#ifdef MFEM_USE_ADIOS2
|
||||
@@ -1226,34 +1236,22 @@ real_t GlobalLpNorm(const real_t p, real_t loc_norm, MPI_Comm comm)
|
||||
{
|
||||
real_t glob_norm;
|
||||
|
||||
// negative quadrature weights may cause the local norm to be negative
|
||||
loc_norm = fabs(loc_norm);
|
||||
|
||||
if (p < infinity())
|
||||
{
|
||||
// negative quadrature weights may cause the error to be negative
|
||||
if (loc_norm < 0.0)
|
||||
{
|
||||
loc_norm = -pow(-loc_norm, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
loc_norm = pow(loc_norm, p);
|
||||
}
|
||||
loc_norm = pow(loc_norm, p);
|
||||
|
||||
MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type, MPI_SUM,
|
||||
comm);
|
||||
MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type,
|
||||
MPI_SUM, comm);
|
||||
|
||||
if (glob_norm < 0.0)
|
||||
{
|
||||
glob_norm = -pow(-glob_norm, 1.0/p);
|
||||
}
|
||||
else
|
||||
{
|
||||
glob_norm = pow(glob_norm, 1.0/p);
|
||||
}
|
||||
glob_norm = pow(fabs(glob_norm), 1.0/p);
|
||||
}
|
||||
else
|
||||
{
|
||||
MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type, MPI_MAX,
|
||||
comm);
|
||||
MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type,
|
||||
MPI_MAX, comm);
|
||||
}
|
||||
|
||||
return glob_norm;
|
||||
@@ -1337,23 +1335,19 @@ real_t L2ZZErrorEstimator(BilinearFormIntegrator &flux_integrator,
|
||||
ParLinearForm *b = new ParLinearForm(&smooth_flux_fes);
|
||||
VectorGridFunctionCoefficient f(&flux);
|
||||
|
||||
if (xfes->GetNE())
|
||||
{
|
||||
MFEM_VERIFY(smooth_flux_fes.GetFE(0) != NULL,
|
||||
"Could not obtain FE of smooth flux space.");
|
||||
const FiniteElement *smooth_flux_fe = smooth_flux_fes.GetTypicalFE();
|
||||
|
||||
if (smooth_flux_fes.GetFE(0)->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
VectorMassIntegrator *vmass = new VectorMassIntegrator;
|
||||
vmass->SetVDim(smooth_flux_fes.GetVDim());
|
||||
a->AddDomainIntegrator(vmass);
|
||||
b->AddDomainIntegrator(new VectorDomainLFIntegrator(f));
|
||||
}
|
||||
else
|
||||
{
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator);
|
||||
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
|
||||
}
|
||||
if (smooth_flux_fe->GetRangeType() == FiniteElement::SCALAR)
|
||||
{
|
||||
VectorMassIntegrator *vmass = new VectorMassIntegrator;
|
||||
vmass->SetVDim(smooth_flux_fes.GetVDim());
|
||||
a->AddDomainIntegrator(vmass);
|
||||
b->AddDomainIntegrator(new VectorDomainLFIntegrator(f));
|
||||
}
|
||||
else
|
||||
{
|
||||
a->AddDomainIntegrator(new VectorFEMassIntegrator);
|
||||
b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
|
||||
}
|
||||
|
||||
b->Assemble();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user